Guest User

Untitled

a guest
Dec 7th, 2010
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        Yays! (Yet Another Youtube Script)
  3. // @description Control autoplaying and playback quality on YouTube.
  4. // @version     1.4.3
  5. // @author      eugenox_gmail_com
  6. // @license     (CC) BY-SA-3.0 http://creativecommons.org/licenses/by-sa/3.0/
  7. // @namespace   youtube
  8. // @include     http://*.youtube.*/*
  9. // @include     http://youtube.*/*
  10. // ==/UserScript==
  11.  
  12. function YAYS(unsafeWindow) {
  13.  
  14. /*
  15.  * Meta data
  16.  */
  17. var Meta = {
  18.     title:       'Yays! (Yet Another Youtube Script)',
  19.     version:     '1.4.3',
  20.     releasedate: 'Jul 24, 2010',
  21.     site:        'http://eugenox.appspot.com/script/yays',
  22.     namespace:   'yays'
  23. };
  24.  
  25. /*
  26.  * Script namespace.
  27.  */
  28. unsafeWindow[Meta.namespace] = {};
  29.  
  30. /*
  31.  * Utility functions.
  32.  */
  33. function each(callback, iterable, scope) {
  34.     if (iterable.length) {
  35.         for (var i = 0; i < iterable.length; i++)
  36.             callback.call(scope, i, iterable[i]);
  37.     }
  38.     else {
  39.         for (var key in iterable)
  40.             if (iterable.hasOwnProperty(key))
  41.                 callback.call(scope, key, iterable[key]);
  42.     }
  43. }
  44.  
  45. function map() {
  46.     var args = Array.prototype.constructor.apply([], arguments);
  47.     var callback = args.shift() || createCallback(Array.prototype.constructor, []);
  48.  
  49.     var buffer = [];
  50.  
  51.     if (args.length > 1) {
  52.         var len = Math.max.apply(Math, map(function(arg) { return arg.length; }, args));
  53.         var getter = function(arg) { return arg[i]; };
  54.  
  55.         for (var i = 0; i < len; i++)
  56.             buffer.push(callback.apply(null, map(getter, args)));
  57.     }
  58.     else {
  59.         for (var i = 0, arg = args[0], len = arg.length; i < len; i++)
  60.             buffer.push(callback(arg[i]));
  61.     }
  62.  
  63.     return buffer;
  64. }
  65.  
  66. function combine(keys, values) {
  67.     var object = {};
  68.     map(function(key, value) { object[key] = value; }, keys, values);
  69.  
  70.     return object;
  71. }
  72.  
  73. function copyProperties(src, target) {
  74.     for (var key in src) target[key] = src[key];
  75.     return target;
  76. }
  77.  
  78. function createCallback(func, scope) {
  79.     return function() { return func.apply(scope, arguments); };
  80. }
  81.  
  82. var emptyFunction = function() { return; };
  83.  
  84. function extendFunction(func, extension) {
  85.     return function() {
  86.         try { func.apply(this, arguments); } catch (ex) { }
  87.         extension.apply(this, arguments);
  88.     };
  89. }
  90.  
  91. /*
  92.  * i18n
  93.  */
  94. function _(text) {
  95.     return _.dictionary[text] || text;
  96. }
  97.  
  98. _.dictionary = (function() {
  99.     var vocabulary = [
  100.         'Auto play', 'ON', 'OFF', 'Toggle video autoplay',
  101.         'Quality', 'AUTO', 'LOW', 'MEDIUM', 'HIGH', 'VERY HIGH', 'Set default video quality',
  102.         'Settings', 'Player settings'
  103.     ];
  104.  
  105.     switch ((document.documentElement.lang || 'en').substr(0, 2)) {
  106.         // hungarian - magyar
  107.         case 'hu':
  108.             return combine(vocabulary, [
  109.                 'Automatikus lej\xE1tsz\xE1s', 'BE', 'KI', 'Automatikus lej\xE1tsz\xE1s ki-, bekapcsol\xE1sa',
  110.                 'Min\u0151s\xE9g', 'AUTO', 'ALACSONY', 'K\xD6ZEPES', 'MAGAS', 'NAGYON MAGAS', 'Vide\xF3k alap\xE9rtelmezett felbont\xE1sa',
  111.                 'Be\xE1ll\xEDt\xE1sok', 'Lej\xE1tsz\xF3 be\xE1ll\xEDt\xE1sai'
  112.             ]);
  113.  
  114.         // dutch - nederlands (Mike-RaWare @userscripts.org)
  115.         case 'nl':
  116.             return combine(vocabulary, [
  117.                 'Auto spelen', 'AAN', 'UIT', 'Stel automatisch afspelen in',
  118.                 'Kwaliteit', 'AUTOMATISCH', 'LAAG', 'GEMIDDELD', 'HOOG', 'ZEER HOOG', 'Stel standaard videokwaliteit in',
  119.                 undefined, undefined
  120.             ]);
  121.  
  122.         // spanish - español (yonane @userscripts.org)
  123.         case 'es':
  124.             return combine(vocabulary, [
  125.                 'Reproducci\xF3n Autom\xE1tica', undefined, undefined, 'Modificar Reproducci\xF3n Autom\xE1tica',
  126.                 'Calidad', 'AUTO', 'BAJA', 'MEDIA', 'ALTA', undefined, 'Usar calidad por defecto',
  127.                 undefined, undefined
  128.             ]);
  129.        
  130.         // german - deutsch (xemino @userscripts.org)
  131.         case 'de':
  132.             return combine(vocabulary, [
  133.                 'Automatische Wiedergabe', 'AN', 'AUS', 'Automatische Wiedergabe umschalten',
  134.                 'Qualit\xE4t', 'AUTO', 'NIEDRIG', 'MITTEL', 'HOCH', undefined, 'Standard Video Qualit\xE4t setzen',
  135.                 undefined, undefined
  136.             ]);
  137.        
  138.         // brazilian portuguese - português brasileiro (Pitukinha @userscripts.org)
  139.         case 'pt':
  140.             return combine(vocabulary, [
  141.                 'Reprodu\xE7\xE3o Autom\xE1tica', 'LIGADO', 'DESLIGADO', 'Modificar Reprodu\xE7\xE3o Autom\xE1tica',
  142.                 'Qualidade', 'AUTOM\xC1TICO', 'MÁ', 'M\xC9DIO', 'BOA', 'MUITO BOA', 'Defini\xE7\xE3o padr\xE3o de v\xEDdeo',
  143.                 'Configura\xE7\xF5es', 'Configura\xE7\xE3o do usu\xE1rio'
  144.             ]);
  145.     }
  146.  
  147.     return {};
  148. })();
  149.  
  150. /*
  151.  * DOM Helper singleton.
  152.  */
  153. var DH = {
  154.     build: function(def) {
  155.         switch (Object.prototype.toString.call(def)) {
  156.             case '[object Object]':
  157.                 def = copyProperties(def, {tag: 'div', style: {}, attributes: {}, children: []});
  158.  
  159.                 var node = this.createElement(def.tag);
  160.  
  161.                 this.style(node, def.style);
  162.                 this.attributes(node, def.attributes);
  163.                 this.append(node, def.children);
  164.  
  165.                 return node;
  166.  
  167.             case '[object String]':
  168.                 return this.createTextNode(def);
  169.  
  170.             default:
  171.                 return def;
  172.         }
  173.     },
  174.  
  175.     getById: createCallback(unsafeWindow.document.getElementById, unsafeWindow.document),
  176.     createElement: createCallback(unsafeWindow.document.createElement, unsafeWindow.document),
  177.     createTextNode: createCallback(unsafeWindow.document.createTextNode, unsafeWindow.document),
  178.  
  179.     style: function(node, style) {
  180.         copyProperties(style, node.style);
  181.     },
  182.  
  183.     append: function(node, children) {
  184.         each(function(i, child) { node.appendChild(this.build(child)); }, [].concat(children), this);
  185.     },
  186.  
  187.     prepend: function(node, children) {
  188.         if (node.hasChildNodes()) {
  189.             var firstChild = node.firstChild;
  190.             each(function(i, child) { node.insertBefore(this.build(child), firstChild); }, [].concat(children), this);
  191.         }
  192.         else {
  193.             this.append(node, children);
  194.         }
  195.     },
  196.  
  197.     content: function(node, children) {
  198.         if (node.hasChildNodes()) {
  199.             var child;
  200.             while (child = node.firstChild) node.removeChild(child);
  201.         }
  202.  
  203.         this.append(node, children);
  204.     },
  205.  
  206.     attributes: function(node, attributes) {
  207.         each(node.setAttribute, attributes, node);
  208.     },
  209.  
  210.     on: function(node, type, listener) {
  211.         node.addEventListener(type, listener, false);
  212.     }
  213. };
  214.  
  215. /*
  216.  * Configuration handler singleton.
  217.  */
  218. var Config = (function(namespace) {
  219.     // Greasemonkey compatible
  220.     if (typeof GM_listValues == 'function') {
  221.         // Accessing GM_getValue from unsafeWindow is not allowed.
  222.         var GM_values = combine(GM_listValues(), map(GM_getValue, GM_listValues()));
  223.  
  224.         return {
  225.             get: function(key) {
  226.                 return GM_values[key] || null;
  227.             },
  228.  
  229.             set: function(key, value) {
  230.                 GM_setValue(key, value);
  231.                 GM_values[key] = value;
  232.             }
  233.         };
  234.     }
  235.    
  236.     var prefix = namespace ? namespace + '.' : '';
  237.    
  238.     // HTML5
  239.     if (typeof unsafeWindow.localStorage == 'object') {
  240.         return {
  241.             get: function(key) { return unsafeWindow.localStorage.getItem(prefix + key); },
  242.             set: function(key, value) { return unsafeWindow.localStorage.setItem(prefix + key, value); }
  243.         };
  244.     }
  245.  
  246.     // Cookie
  247.     return {
  248.         get: function(key) {
  249.             return (document.cookie.match(new RegExp('(?:^|; *)' + prefix + key + '=(\\w+)(?:$|;)')) || [, null])[1];
  250.         },
  251.  
  252.         set: function(key, value) {
  253.             key = prefix + key;
  254.            
  255.             if (new RegExp('(?:^|; *)' + key + '=\\w+(?:$|;)').test(document.cookie)) {
  256.                 document.cookie = key + '=' + value;
  257.             }
  258.             else {
  259.                 document.cookie = key + '=' + value + '; path=/; expires=' + new Date(new Date().valueOf() + 365 * 24 * 3600 * 1000).toUTCString();
  260.             }
  261.         }
  262.     };
  263. })(Meta.namespace);
  264.  
  265. /*
  266.  * JSONRequest class.
  267.  */
  268. var JSONRequest = (function(namespace) {
  269.     function buildURL(base, parameters) {
  270.         var queryParams = [];
  271.         each(function(key, value) { queryParams.push(key + '=' + encodeURIComponent(value)); }, parameters);
  272.  
  273.         return base + '?' + queryParams.join('&');
  274.     }
  275.  
  276.     var RequestClass;
  277.  
  278.     // Greasemonkey XHR
  279.     if (typeof GM_xmlhttpRequest == 'function') {
  280.         RequestClass = function(url, parameters, callback) {
  281.             this._callback = callback;
  282.  
  283.             GM_xmlhttpRequest({
  284.                 method: 'GET',
  285.                 url: buildURL(url, parameters),
  286.                 onload: createCallback(this._onLoad, this)
  287.             });
  288.         };
  289.  
  290.         RequestClass.prototype = {
  291.             _onLoad: function(response) {
  292.                 this._callback(eval('(' + response.responseText + ')'));
  293.             }
  294.         };
  295.     }
  296.     // Script tag
  297.     else {
  298.         unsafeWindow[namespace].JSONRequest = [];
  299.  
  300.         RequestClass = function(url, parameters, callback) {
  301.             this._callback = callback;
  302.             this._id = unsafeWindow[namespace].JSONRequest.push(createCallback(this._onLoad, this)) - 1;
  303.  
  304.             parameters.callback = namespace + '.JSONRequest[' + this._id + ']';
  305.  
  306.             this._scriptTag = document.body.appendChild(DH.build({
  307.                 tag: 'script',
  308.                 attributes: {
  309.                     type: 'text/javascript',
  310.                     src: buildURL(url, parameters)
  311.                 }
  312.             }));
  313.         };
  314.  
  315.         RequestClass.prototype = {
  316.             _onLoad: function(response) {
  317.                 this._callback(response);
  318.  
  319.                 document.body.removeChild(this._scriptTag);
  320.                 delete unsafeWindow[namespace].JSONRequest[this._id];
  321.             }
  322.         };
  323.     }
  324.  
  325.     return RequestClass;
  326. })(Meta.namespace);
  327.  
  328. /*
  329.  * Check for update.
  330.  */
  331. (function () {
  332.  
  333.     if (new Date().valueOf() - new Number(Config.get('update_checked_at')).valueOf() < 24 * 3600 * 1000) return;
  334.  
  335.     var popup = null;
  336.  
  337.     new JSONRequest(Meta.site + '/changelog', {version: Meta.version}, function (changelog) {
  338.         Config.set('update_checked_at', new String(new Date().valueOf()).valueOf());
  339.  
  340.         if (changelog && changelog.length) popup = renderPopup(changelog);
  341.     });
  342.  
  343.     function renderPopup(changelog) {
  344.         return document.body.appendChild(DH.build({
  345.             style: {
  346.                 position: 'fixed', top: '20px', right: '20px', zIndex: 1000, padding: '5px', background: '#f5f5f5', border: '1px solid #c3c3c3',
  347.                 color: '#202020', fontSize: '11px', fontFamily: 'Arial,Nimbus Sans L,sans-serif', lineHeight: '11px'
  348.             },
  349.             children: [{
  350.                 style: {margin: '2px 0', textAlign: 'center', fontWeight: 'bold'},
  351.                 children: Meta.title
  352.             }, {
  353.                 style: {marginBottom: '6px', textAlign: 'center'},
  354.                 children: 'UserScript update notification.'
  355.             }, {
  356.                 children: ['You are using version ', {tag: 'b', children: Meta.version}, {tag: 'i', children: [' (', Meta.releasedate, ')']}, '. Consider updating to the newest version.']
  357.             }, {
  358.                 style: {margin: '5px'},
  359.                 children: map(function(entry) {
  360.                     return {
  361.                         children: [
  362.                             {tag: 'b', style: {fontSize: '11px'}, children: entry.version},
  363.                             {tag: 'i', style: {marginLeft: '5px'}, children: entry.date},
  364.                             {style: {padding: '0 0 2px 10px', whiteSpace: 'pre'}, children: [].concat(entry.note).join('\n')}
  365.                         ]
  366.                     };
  367.                 }, [].concat(changelog))
  368.             }, {
  369.                 style: {textAlign: 'center', padding: '10px'},
  370.                 children: map(function(text, handler) {
  371.                     var node = DH.build({
  372.                         tag: 'span',
  373.                         style: {border: '1px solid #cccccc', padding: '3px 10px', margin: '0 5px', cursor: 'pointer', backgroundColor: '#e5e5e5'},
  374.                         children: text
  375.                     });
  376.  
  377.                     DH.on(node, 'click', handler);
  378.  
  379.                     return node;
  380.                 }, ['Update', 'Later'], [openSite, removePopup])
  381.             }]
  382.         }));
  383.     }
  384.    
  385.     function removePopup() {
  386.         document.body.removeChild(popup);
  387.     }
  388.    
  389.     function openSite() {
  390.         removePopup();
  391.         unsafeWindow.open(Meta.site);
  392.     }
  393.  
  394. })();
  395.  
  396. /*
  397.  * Button class.
  398.  */
  399. function Button(labelText, tooltipText) {
  400.     var node = DH.build(this._dom.node);
  401.     var label = DH.build(this._dom.label);
  402.     var indicator = DH.build(this._dom.indicator);
  403.  
  404.     DH.attributes(node, { title: tooltipText });
  405.     DH.append(label, labelText);
  406.     DH.append(node, [label, indicator]);
  407.  
  408.     DH.on(node, 'click', createCallback(this._onClick, this));
  409.  
  410.     this._node = node;
  411.  
  412.     this.indicator = indicator.firstChild;
  413. }
  414.  
  415. Button.prototype = {
  416.     _onClick: function(event) {
  417.         this.handler();
  418.         this.refresh();
  419.     },
  420.  
  421.     render: function() {
  422.         this.refresh();
  423.         return this._node;
  424.     },
  425.  
  426.     _dom: {
  427.         node: {
  428.             tag: 'button',
  429.             style: {margin: '0 0 0 5px'},
  430.             attributes: {type: 'button', 'class': 'yt-uix-button yt-uix-tooltip'}
  431.         },
  432.  
  433.         label: {
  434.             tag: 'span',
  435.             attributes: {'class': 'yt-uix-button-content'}
  436.         },
  437.  
  438.         indicator: {
  439.             tag: 'span',
  440.             style: {fontWeight: 'bold', marginLeft: '5px'},
  441.             attributes: {'class': 'yt-uix-button-content'},
  442.             children: ''
  443.         }
  444.     },
  445.    
  446.     handler: emptyFunction,
  447.     refresh: emptyFunction
  448. };
  449.  
  450. /*
  451.  * PLAYERFUNCTION class.
  452.  */
  453. function PlayerFunction(configKey, overrides) {
  454.     copyProperties(overrides, this);
  455.  
  456.     this._configKey = configKey;
  457.  
  458.     PlayerFunction.functions.push(this);
  459. }
  460.  
  461. PlayerFunction.prototype = {
  462.     _player: null,
  463.  
  464.     get: function() {
  465.         return new Number(Config.get(this._configKey)).valueOf();
  466.     },
  467.  
  468.     set: function(value) {
  469.         Config.set(this._configKey, value);
  470.     },
  471.  
  472.     init: emptyFunction,
  473.     apply: emptyFunction
  474. };
  475.  
  476. PlayerFunction.functions = [];
  477.  
  478. PlayerFunction.init = function(player) {
  479.     this.prototype._player = player;
  480.     each(function(i, func) { func.init(); }, this.functions);
  481. };
  482.  
  483. /*
  484.  * AUTOPLAY
  485.  */
  486. var AutoPlay = new PlayerFunction('auto_play', {
  487.     _applied: false,
  488.  
  489.     init: function() {
  490.         this._applied = this.get() == 0;
  491.     },
  492.  
  493.     step: function() {
  494.         this.set((this.get() + 1) % 2);
  495.     },
  496.  
  497.     apply: function() {
  498.         if (! this._applied && this._player.getPlayerState() == 1) {
  499.             this._player.seekTo(0, true);
  500.             this._player.pauseVideo();
  501.  
  502.             this._applied = true;
  503.         }
  504.     },
  505.  
  506.     createButton: function() {
  507.         var button = new Button(_('Auto play'), _('Toggle video autoplay'));
  508.  
  509.         button.handler = createCallback(this.step, this);
  510.  
  511.         button.refresh = function() {
  512.             this.indicator.data = _(['ON', 'OFF'][AutoPlay.get()]);
  513.         };
  514.  
  515.         return button;
  516.     }
  517. });
  518.  
  519. /*
  520.  * VIDEO QUALITY
  521.  */
  522. var VideoQuality = new PlayerFunction('video_quality', {
  523.     step: function() {
  524.         this.set((this.get() + 1) % 5);
  525.     },
  526.  
  527.     qualities: {hd1080: 4, hd720: 3, large: 2, medium: 1, small: 0},
  528.  
  529.     apply: function() {
  530.         var qualities = this._player.getAvailableQualityLevels();
  531.         var quality = null;
  532.  
  533.         switch (this.get()) {
  534.             case 1: // LOW
  535.                 quality = qualities.pop(); break;
  536.             case 2: // MEDIUM
  537.                 while (this.qualities[quality = qualities.shift()] > this.qualities.large); break;
  538.             case 3: // HIGH
  539.                 while (this.qualities[quality = qualities.shift()] > this.qualities.hd720); break;
  540.             case 4: // VERY HIGH
  541.                 quality = qualities.shift(); break;
  542.             default:
  543.                 return;
  544.         }
  545.  
  546.         this._player.setPlaybackQuality(quality);
  547.     },
  548.  
  549.     createButton: function() {
  550.         var button = new Button(_('Quality'), _('Set default video quality'));
  551.  
  552.         button.handler = createCallback(this.step, this);
  553.  
  554.         button.refresh = function() {
  555.             this.indicator.data = _(['AUTO', 'LOW', 'MEDIUM', 'HIGH', 'VERY HIGH'][VideoQuality.get()]);
  556.         };
  557.  
  558.         return button;
  559.     }
  560. });
  561.  
  562. /*
  563.  * PLAYER STATE CHANGE callback
  564.  */
  565. unsafeWindow[Meta.namespace].onPlayerStateChange = function() {
  566.     AutoPlay.apply();
  567.  
  568. };
  569.  
  570. /*
  571.  * PLAYER READY callback
  572.  */
  573. function onPlayerReady() {
  574.     var player = DH.getById('movie_player');
  575.     if (player/* && typeof player.getPlayerState == 'function'*/) {
  576.  
  577.         PlayerFunction.init(player);
  578.  
  579.         VideoQuality.apply();
  580.         AutoPlay.apply();
  581.         player.addEventListener('onStateChange', Meta.namespace + '.onPlayerStateChange()');
  582.         return true;
  583.     }
  584.  
  585.     return false;
  586. }
  587.  
  588. /*
  589.  * PER-SITE
  590.  */
  591. // WATCH page
  592. if (DH.getById('watch-actions-right') !== null) {
  593.  
  594.     var controlButton = DH.build({
  595.         tag: 'button',
  596.         style: {margin: '0 0 0 5px'},
  597.         attributes: {type: 'button', 'class': 'yt-uix-button yt-uix-tooltip', title: _('Player settings')},
  598.         children: {
  599.                 tag: 'img',
  600.                 attributes: {src: 'data:image/png;base64,\
  601. iVBORw0KGgoAAAANSUhEUgAAABAAAAARCAQAAAB+puRPAAAAAXNSR0IArs4c6QAAAYxJREFUKM+N\
  602. 0T9I1HEABfDPzzuMLvFPQ38QOYj+YCClo7T0l/7SEji1VkSu/bGhsRouyS6IlnDpcIksggYnA6Os\
  603. 5EoIrMBQKIIo9O707vzdt0FBx97y4L03vMeLrMHgoXA1Ft86N7KqJdcGPOteT65balWqg1x/LgwW\
  604. qYQFZc2BbDEbBgYgIne+9cF20z6hA+/Qqd2Yid4b2SQLiUlJJXusU8EBiyqmvFSpI8Hw+JmF1OGS\
  605. ed+8MqtBpKpkri+TIXqUr7aFlg5zfno6Ue5plh463pnQ5LlKoToTPQzHTPutwWufdz7+QmZH21Ra\
  606. UaOtrkjGSpaQsElhZVoQi1UUzIl687/a0i0nlTQam4h6gtrQvs6KWNbfwuJMBHcu775dk1LvO9Ji\
  607. RfOe9OVukiBzsda/V2yDRi02SiHS6u3B9j+Tb5JU412ajPuq3gmxuyJHbbbFaG2l1IV7PeFUmevl\
  608. fHgfTpfZX+4K7ffXvHQ2gmtLo+FFOLIEXdGyk1imj2Dbh+H0yEz10uwUP/wn/gGkFpjRuL8SbgAA\
  609. AABJRU5ErkJggg=='}
  610.         }
  611.     });
  612.  
  613.     DH.on(controlButton, 'click', function() {
  614.         DH.attributes(DH.getById('watch-actions-area-container'), {
  615.             'class': '',
  616.             style: 'height: auto'
  617.         });
  618.  
  619.         DH.content(DH.getById('watch-actions-area'), [{
  620.             attributes: {'class': 'close'},
  621.             children: {
  622.                 tag: 'img',
  623.                 attributes: {'class': 'master-sprite close-button', src: 'http://s.ytimg.com/yt/img/pixel-vfl73.gif', onclick: 'yt.www.watch.watch5.hide()'}
  624.             }
  625.         }, {
  626.             style: {textAlign: 'center', margin: '5px 0'},
  627.             children: [
  628.                 VideoQuality.createButton().render(),
  629.                 AutoPlay.createButton().render()
  630.             ]
  631.         }]);
  632.     });
  633.  
  634.     DH.append(DH.getById('watch-actions-right'), controlButton);
  635.  
  636.     unsafeWindow.onYouTubePlayerReady = extendFunction(unsafeWindow.onYouTubePlayerReady, onPlayerReady);
  637.     onPlayerReady();
  638.  
  639. }
  640. // CHANNEL page
  641. else if (DH.getById('playnav-video-details') !== null) {
  642.  
  643.     var tabLabel = DH.build({
  644.         tag: 'a',
  645.         attributes: {href: 'javascript:', title: _('Player settings')},
  646.         children: _('Settings')
  647.     });
  648.  
  649.     // "Settings" tab clicked
  650.     DH.on(tabLabel, 'mousedown', function() {
  651.         each(function(index, element) {
  652.             var panelName = (new RegExp('^playnav-panel-tab-(\\w+)').exec(element.getAttribute('id')) || [, null])[1];
  653.             if (panelName) {
  654.                 element.setAttribute('class', '');
  655.                 DH.getById('playnav-panel-' + panelName).style.display = 'none';
  656.             }
  657.         }, DH.getById('playnav-bottom-links-clip').getElementsByTagName('td'));
  658.  
  659.         DH.getById('playnav-panel-tab-settings').setAttribute('class', 'panel-tab-selected');
  660.         DH.getById('playnav-panel-settings').style.display = 'block';
  661.     });
  662.  
  663.     // Create and append tab
  664.     DH.append(DH.getById('playnav-bottom-links-clip').getElementsByTagName('tr')[0], {
  665.         tag: 'td',
  666.         attributes: {id: 'playnav-panel-tab-settings'},
  667.         children: {
  668.             tag: 'table',
  669.             attributes: {'class': 'panel-tabs'},
  670.             children: [{
  671.                 tag: 'tr',
  672.                 children: {
  673.                     tag: 'td',
  674.                     attributes: {'class': 'panel-tab-title-cell'},
  675.                     children: [{
  676.                         attributes: {'class': 'playnav-panel-tab-icon'},
  677.                         style: {marginTop: '2px', height: '10px', backgroundImage: 'url(data:image/png;base64,\
  678. iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAEdJREFUGNON\
  679. kFEOADAEQ9udyf1P0DvZl0RsRL+kHqJAkSSX5NU/GfgNRc0OyjIzctoYEACwAtGo/sFS+9PbZ54o\
  680. co7jgi7wC1N5OUtzk3BUAAAAAElFTkSuQmCC)'}
  681.                     }, {
  682.                         attributes: {'class': 'playnav-bottom-link'},
  683.                         children: tabLabel
  684.                     }]
  685.                 }
  686.             }, {
  687.                 tag: 'tr',
  688.                 children: {
  689.                     tag: 'td',
  690.                     attributes: {'class': 'panel-tab-indicator-cell inner-box-opacity'},
  691.                     children: {
  692.                         attributes: {'class': 'panel-tab-indicator-arrow'}
  693.                     }
  694.                 }
  695.             }]
  696.         }
  697.     });
  698.  
  699.     // Other tab clicked
  700.     unsafeWindow.playnav.selectPanel = extendFunction(unsafeWindow.playnav.selectPanel, function () {
  701.         DH.getById('playnav-panel-tab-settings').setAttribute('class', '');
  702.         DH.getById('playnav-panel-settings').style.display = 'none';
  703.     });
  704.  
  705.     // Create and append panel
  706.     DH.append(DH.getById('playnav-video-panel-inner'), {
  707.         attributes: {id: 'playnav-panel-settings', 'class': 'hid'},
  708.         children: {
  709.             children: [{
  710.                 tag: 'b',
  711.                 children: _('Player settings')
  712.             }, {
  713.                 style: {textAlign: 'center', marginTop: '5px'},
  714.                 children: [
  715.                     VideoQuality.createButton().render(),
  716.                     AutoPlay.createButton().render()
  717.                 ]
  718.             }]
  719.         }
  720.     });
  721.  
  722.     unsafeWindow.onChannelPlayerReady = extendFunction(unsafeWindow.onChannelPlayerReady, onPlayerReady);
  723.     onPlayerReady();
  724.  
  725. }
  726.  
  727. } // YAYS
  728.  
  729. /*
  730.  * DETECT browser, and run YAYS() accordingly.
  731.  */
  732.  
  733. // Firefox
  734. /*if (new RegExp('Firefox/\\d', 'i').test(navigator.userAgent)) {
  735.     YAYS(unsafeWindow);
  736. }
  737. // Chrome, Opera, Safari
  738. else*/ {
  739.     var scriptNode = document.createElement('script');
  740.     scriptNode.setAttribute('type', 'text/javascript');
  741.     scriptNode.text = '(' + YAYS.toString() + ')(window);';
  742.     document.body.appendChild(scriptNode);
  743. }
Add Comment
Please, Sign In to add comment