BigBisous

YouTube Link Title

Dec 13th, 2016
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name           YouTube Link Title
  3. // @description    Adds video titles, shows previews and embeds on click. Also supported: Vimeo, LiveLeak, Dailymotion, WorldStarHipHop, Vine, Coub
  4. // @author         kuehlschrank
  5. // @homepage       http://userscripts.org/scripts/show/83584
  6. // @version        2014.3.12
  7. // @icon           https://s3.amazonaws.com/uso_ss/icon/83584/large.png
  8. // @updateURL      https://userscripts.org/scripts/source/83584.meta.js
  9. // @downloadURL    https://userscripts.org/scripts/source/83584.user.js
  10. // @include        http*
  11. // @exclude        http*//*.google.*/*
  12. // @exclude        *//*.googleapis.com/*
  13. // @exclude        *//*.youtube.com/*
  14. // @exclude        *//vimeo.com/*
  15. // @exclude        *//*.vimeo.com/*
  16. // @exclude        *//*.liveleak.com/*
  17. // @exclude        *//*.worldstarhiphop.com/*
  18. // @exclude        *//vine.co/*
  19. // @exclude        *//*.dailymotion.com/*
  20. // @exclude        *//coub.com/*
  21. // @exclude        *//*.reddit.com/toolbar/*
  22. // ==/UserScript==
  23. 'use strict';
  24. function onLoad() {
  25.   cfg.load();
  26.   var q = 'a[href*="//t.co/"]';
  27.   for (var sid in sites) {
  28.     q += sites[sid].patterns.reduce(function (prev, cur) {
  29.       return prev + ',a[href*="' + cur + '"]';
  30.     }, '');
  31.   }
  32.   links.query = q;
  33.   links.process(d.body);
  34.   var M = window.MutationObserver || window.WebKitMutationObserver;
  35.   if (M) {
  36.     new M(onMutations).observe(d.body, {
  37.       childList: true,
  38.       subtree: true,
  39.       attributes: true,
  40.       attributeFilter: [
  41.         'href'
  42.       ]
  43.     });
  44.   } else {
  45.     d.body.addEventListener('DOMNodeInserted', onNodeInserted, false);
  46.   }
  47.   GM_registerMenuCommand('Set up YouTube Link Title', setup.show);
  48. }
  49. function onNodeInserted(e) {
  50.   var t = e.target;
  51.   if (t.nodeType == 1) window.setTimeout(links.process, 100, t);
  52. }
  53. function onMutations(muts) {
  54.   for (var i = muts.length, m; i-- && (m = muts[i]); ) {
  55.     if (m.type == 'attributes') {
  56.       window.setTimeout(links.process, 100, m.target);
  57.     } else {
  58.       for (var j = m.addedNodes.length, node; j-- && (node = m.addedNodes[j]); ) {
  59.         if (node.nodeType == 1) window.setTimeout(links.process, 100, node);
  60.       }
  61.     }
  62.   }
  63. }
  64. function ce(n, props) {
  65.   var n = d.createElement(n);
  66.   if (props) {
  67.     forEach(props, function (p) {
  68.       if (p == 'click' || p == 'mousedown' || p == 'mousedown') {
  69.         n.addEventListener(p, props[p], false);
  70.       } else {
  71.         n[p] = props[p];
  72.       }
  73.     });
  74.   }
  75.   return n;
  76. }
  77. function forEach(o, f) {
  78.   var props = Object.keys(o);
  79.   for (var i = props.length, p; i-- && (p = props[i]); ) {
  80.     if (o.hasOwnProperty(p)) f(p);
  81.   }
  82. }
  83. function rm(id) {
  84.   var node = $(id);
  85.   if (node) node.parentNode.removeChild(node);
  86. }
  87. var d = document,
  88. $ = function (id) {
  89.   return d.getElementById(id);
  90. };
  91. var setup = {
  92.   id: 'YTLT-setup',
  93.   html: function () {
  94.     var h = '<div>YouTube Link Title</div><ul>';
  95.     this.forEach(function (n) {
  96.       var s = cfg.settings[n];
  97.       if (typeof s.default == 'boolean') {
  98.         h += '<li><input type="checkbox" name="' + n + '"> ' + s.title + '</li>'
  99.       } else if (s.options) {
  100.         h += '<li>' + s.title + ': <select name="' + n + '">';
  101.         forEach(s.options, function (on) {
  102.           h += '<option value="' + on + '">' + s.options[on] + '</option>';
  103.         });
  104.         h += '</select></li>';
  105.       }
  106.     });
  107.     return h += '</ul><div><button name="save">Save settings</button></div></div>';
  108.   },
  109.   q: function (n) {
  110.     return d.querySelector('#' + this.id + ' *[name="' + n + '"]');
  111.   },
  112.   get: function (n) {
  113.     var s = cfg.settings[n];
  114.     if (typeof s.default == 'boolean') return this.q(n).checked;
  115.     if (s.options) {
  116.       var sel = this.q(n);
  117.       return sel.options[sel.selectedIndex].value;
  118.     }
  119.   },
  120.   set: function (n, val) {
  121.     var s = cfg.settings[n];
  122.     if (typeof s.default == 'boolean') {
  123.       this.q(n).checked = val;
  124.     } else if (s.options) {
  125.       var sel = this.q(n);
  126.       for (var i = sel.options.length; i--; ) {
  127.         if (sel.options[i].value == val) sel.selectedIndex = i;
  128.       }
  129.     }
  130.   },
  131.   forEach: function (f) {
  132.     forEach(cfg.settings, function (n) {
  133.       if (cfg.settings[n].title) f(n);
  134.     });
  135.   },
  136.   show: function () {
  137.     rm(setup.id);
  138.     GM_addStyle('\t        #'
  139.     + setup.id + ' { position:fixed;z-index:10001;top:40px;right:40px;padding:20px 30px;background-color:white;width:auto;border:1px solid black }\t        #'
  140.     + setup.id + ' * { color:black;text-align:left;line-height:normal;font-size:12px }\t        #'
  141.     + setup.id + ' div { text-align:center;font-weight:bold;font-size:14px }\t        #'
  142.     + setup.id + ' ul { margin:15px 0 15px 0;padding:0;list-style:none }\t        #'
  143.     + setup.id + ' li { margin:0;padding:3px 0 3px 0;vertical-align:middle }'
  144.     );
  145.     d.body.appendChild(ce('div', {
  146.       id: setup.id,
  147.       innerHTML: setup.html()
  148.     }));
  149.     setup.q('save').addEventListener('click', function () {
  150.       setup.forEach(function (n) {
  151.         cfg[n] = setup.get(n);
  152.       });
  153.       cfg.x = cfg.y = false;
  154.       cfg.save();
  155.       this.disabled = true;
  156.       this.innerHTML = 'Reloading...';
  157.       window.location.reload();
  158.     }, false);
  159.     setup.forEach(function (n) {
  160.       setup.set(n, cfg[n]);
  161.       setup.q(n).addEventListener('change', setup.update, false);
  162.     });
  163.     setup.update();
  164.   },
  165.   update: function () {
  166.     setup.forEach(function (n) {
  167.       var s = cfg.settings[n];
  168.       if (!s.depends) return;
  169.       setup.q(n).parentNode.style.display = (Object.keys(s.depends).every(function (dn) {
  170.         return s.depends[dn].test(setup.get(dn));
  171.       })) ? '' : 'none';
  172.     });
  173.   }
  174. }
  175. var links = {
  176.   process: function (node) {
  177.     var i = 0,
  178.     list = node.tagName.toUpperCase() == 'A' ? [
  179.       node
  180.     ] : node.querySelectorAll(links.query),
  181.     isFB = location.hostname == 'www.facebook.com';
  182.     if (list.length < 1) return;
  183.     function processChunk() {
  184.       var a,
  185.       li,
  186.       vi,
  187.       num = 0,
  188.       ae = d.activeElement;
  189.       while (a = list[i++]) {
  190.         if (!(li = links.parseInfo(a)) || ae && ae != d.body && ae.contains(a) || isFB && a.parentNode.outerHTML.indexOf('shareLink') > - 1) continue;
  191.         if ((vi = cache.get(li.sid, li.vid)) || cfg.urls_only && !li.url) {
  192.           links.decorate(a, li, vi);
  193.         } else {
  194.           (function (a, li) {
  195.             net.info(li, function (vi) {
  196.               links.decorate(a, li, vi);
  197.             });
  198.           }) (a, li);
  199.         }
  200.         if (++num == 15) return window.setTimeout(processChunk, 100);
  201.       }
  202.       list = null;
  203.     }
  204.     node = null;
  205.     processChunk();
  206.   },
  207.   parseInfo: function (a) {
  208.     var url = a.getAttribute('data-expanded-url') || a.getAttribute('data-full-url') || a.href;
  209.     try {
  210.       url = decodeURIComponent(url.replace(/^https?:\/\/www\.facebook\.com\/.+(http.+)/, '$1'));
  211.     } catch (ex) {
  212.     };
  213.     var test = function (pattern) {
  214.       return this.indexOf(pattern.toLowerCase()) != - 1;
  215.     };
  216.     for (var sid in sites) {
  217.       var s = sites[sid],
  218.       info;
  219.       if (!sites[sid].patterns.some(test, url.toLowerCase())) continue;
  220.       if (info = sites[sid].parse(url)) return {
  221.         sid: sid,
  222.         vid: info.vid,
  223.         t: info.t,
  224.         url: sites[sid].patterns.some(test, a.textContent.toLowerCase()),
  225.         oUrl: url
  226.       };
  227.     }
  228.     return null;
  229.   },
  230.   decorate: function (a, li, vi) {
  231.     if (a.className.indexOf('YTLT-') > - 1) {
  232.       a.removeEventListener('click', this.onClick, false);
  233.       a.removeEventListener('mouseover', this.onMouseOver, false);
  234.     } else {
  235.       if (!this.styleAdded) {
  236.         var css = '\t\t\t\t\t#YTLT-preview { position:fixed;z-index:8888;width:320px;padding:0;border:1px solid black;background-color:black; }\t\t\t\t\t#YTLT-preview img { max-height:240px;width:inherit;vertical-align:bottom; }\t\t\t\t\t#YTLT-preview div { padding:4px 2px;width:316px;text-align:center;font-family:sans-serif;font-size:13px;color:white;font-weight:bold; }\t\t\t\t\ta.YTLT-na { text-decoration: line-through!important; }\t\t\t\t\ta.YTLT-text { font-weight:bold!important;font-style:italic!important; }\t\t\t\t\ta.YTLT-icon { padding-left:18px!important; }\t\t\t\t\ta.YTLT-icon.YTLT-na:hover, a.YTLT-icon.YTLT-ne:hover { background:transparent url(data:image/gif;base64,R0lGODlhEAAQAKIGAO/v7+vr676+vmVlZZqamv///////wAAACH5BAEAAAYALAAAAAAQABAAAAM/aLrc/tAIQisRj4DCOSAZN4xDATpEV4zmMlVdWZ6GxqWr2Cq4mau0nk0VCHZelsuiBwypbpkNkcZAWjCRrCIBADs=) center left no-repeat!important; }'
  237.         ;
  238.         for (var sid in sites) {
  239.           css += 'a.YTLT-icon-' + sid + ' { background:transparent url(' + sites[sid].icon + ') center left no-repeat!important; }';
  240.         }
  241.         GM_addStyle(css);
  242.         this.styleAdded = true;
  243.       }
  244.       var c = ' YTLT-link';
  245.       if (li.url || window.location.hostname == 'twitter.com') {
  246.         c += ' YTLT-text YTLT-icon YTLT-icon-' + li.sid;
  247.         if (vi) a.innerHTML = vi.title;
  248.       } else {
  249.         if (vi && !cfg.previews && vi.title) a.title = vi.title;
  250.         if (a.hasChildNodes() && a.innerHTML.indexOf('<img') == - 1 && a.textContent.trim()) {
  251.           c += ' YTLT-icon YTLT-icon-' + li.sid;
  252.         }
  253.       }
  254.       if (vi.status == 3 || vi.status == 4) {
  255.         c += ' YTLT-na';
  256.       } else if (vi.status == 5) {
  257.         c += ' YTLT-ne';
  258.       }
  259.       a.className += c;
  260.       if (cfg.rewrite && sites[li.sid].url) {
  261.         a.href = sites[li.sid].url(li.vid, li.t, li.oUrl);
  262.       }
  263.     }
  264.     if (cfg.embed_mode != 'off') {
  265.       a.target = '_blank';
  266.       if (!vi.status) a.addEventListener('click', this.onClick, false);
  267.     }
  268.     if (cfg.previews && (vi && vi.preview || sites[li.sid].preview) && !a.querySelector('iframe')) {
  269.       a.addEventListener('mouseover', this.onMouseOver, false);
  270.       new Image().src = embedding.preview(vi, li);
  271.     }
  272.   },
  273.   onClick: function (e) {
  274.     if (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey || e.button != 0) return;
  275.     e.preventDefault();
  276.     e.stopImmediatePropagation();
  277.     rm('YTLT-preview');
  278.     embedding.play(this);
  279.   },
  280.   onMouseOver: function (e) {
  281.     rm('YTLT-preview');
  282.     var li = links.parseInfo(this);
  283.     var vi = cache.get(li.sid, li.vid);
  284.     var qm = d.compatMode == 'BackCompat';
  285.     var w = qm ? d.body.clientWidth : d.documentElement.clientWidth,
  286.     h = qm ? d.body.clientHeight : d.documentElement.clientHeight;
  287.     var img = ce('img', {
  288.       src: embedding.preview(vi, li)
  289.     });
  290.     var div = ce('div', {
  291.       id: 'YTLT-preview'
  292.     });
  293.     div.appendChild(img);
  294.     if (vi.title && this.textContent.indexOf(vi.title) == - 1) div.appendChild(ce('div', {
  295.       innerHTML: vi.title
  296.     }));
  297.     d.body.appendChild(div);
  298.     var r = (this.firstElementChild || this).getBoundingClientRect();
  299.     var dw = Math.max(div.offsetWidth, 320),
  300.     dh = Math.max(div.offsetHeight, 240);
  301.     if (h - r.height > 2 * dh) {
  302.       if (r.top + r.bottom > h) {
  303.         div.style.bottom = h - r.top + 15 + 'px';
  304.       } else {
  305.         div.style.top = r.bottom + 15 + 'px';
  306.       }
  307.       div.style.left = Math.min(w - dw - 10, Math.max(10, e.pageX - dw / 2)) + 'px';
  308.     } else {
  309.       if (r.right + r.left > w) {
  310.         div.style.right = w - r.right + r.width + 15 + 'px';
  311.       } else {
  312.         div.style.left = r.left + r.width + 15 + 'px';
  313.       }
  314.       if (r.top + r.bottom > h) {
  315.         div.style.bottom = Math.max(20, h - r.top - r.height / 2 - dh / 2) + 'px';
  316.       } else {
  317.         div.style.top = Math.max(10, r.top + r.height / 2 - dh / 2) + 'px';
  318.       }
  319.     }
  320.     this.addEventListener('mouseout', links.onMouseOut, false);
  321.   },
  322.   onMouseOut: function (e) {
  323.     this.removeEventListener('mouseout', links.onMouseOut, false);
  324.     rm('YTLT-preview');
  325.   }
  326. };
  327. var net = {
  328.   info: function (li, f) {
  329.     var id = li.sid + li.vid;
  330.     if (typeof net.pending[id] != 'object') {
  331.       net.pending[id] = [
  332.         f
  333.       ];
  334.       sites[li.sid].request(li.vid, function (vi) {
  335.         if (vi) {
  336.           cache.set(li.sid, li.vid, vi);
  337.           for (var i = net.pending[id].length; i--; ) {
  338.             window.setTimeout(net.pending[id][i], 0, vi);
  339.           }
  340.         }
  341.         delete net.pending[id];
  342.       });
  343.     } else {
  344.       net.pending[id].push(f);
  345.     }
  346.   },
  347.   pending: {
  348.   },
  349.   json: function (url, f) {
  350.     GM_xmlhttpRequest({
  351.       method: 'GET',
  352.       url: url,
  353.       onload: function (req) {
  354.         var obj;
  355.         try {
  356.           obj = JSON.parse(req.responseText);
  357.         } catch (ex) {
  358.           GM_log('JSON data from ' + url + ' could not be parsed: ' + ex + '\nHTTP: ' + req.status + '\nResponse: ' + req.responseText);
  359.         }
  360.         window.setTimeout(f, 0, req.status, obj, req.responseText);
  361.       },
  362.       onerror: function () {
  363.         GM_log('Request to ' + url + ' failed.');
  364.       }
  365.     });
  366.   },
  367.   text: function (url, re, f) {
  368.     GM_xmlhttpRequest({
  369.       method: 'GET',
  370.       url: url,
  371.       onload: function (req) {
  372.         var m = [
  373.         ],
  374.         txt = req.responseText;
  375.         for (var i = 0, len = re.length; i < len; i++) {
  376.           m.push(re[i].exec(txt));
  377.         }
  378.         window.setTimeout(f, 0, req.status, m);
  379.       },
  380.       onerror: function () {
  381.         GM_log('Request to ' + url + ' failed.');
  382.       }
  383.     });
  384.   }
  385. };
  386. var embedding = {
  387.   play: function (a) {
  388.     var li = links.parseInfo(a);
  389.     if (cfg.embed_mode == 'inline') {
  390.       var embed = embedding.embed(li, cfg.big);
  391.       a.parentNode.replaceChild(embed, a);
  392.       window.setTimeout(window.scrollTo, 0, 0, window.scrollY + embed.getBoundingClientRect().top - window.innerHeight / 2 + embed.offsetHeight / 2);
  393.     } else if (cfg.embed_mode == 'window') {
  394.       var embed = embedding.embed(li, cfg.big);
  395.       var w = parseInt(embed.style.width),
  396.       h = parseInt(embed.style.height);
  397.       embed.style.width = '100%';
  398.       embed.style.height = '100%';
  399.       var div = ce('div');
  400.       div.appendChild(embed);
  401.       var features = 'left=' + (window.screen.width / 2 - w / 2) + ',top=' + (window.screen.height / 2 - h / 2) + ',width=' + w + ',height=' + h + ',status=no,scrollbars=no,location=no,menubar=no,toolbar=no,personalbar=no,dependent=no';
  402.       window.open('data:text/html,<html><title>Video Player</title><body style="padding:0;margin:0;overflow:hidden;background:black">' + encodeURIComponent(div.innerHTML) + '</body></html>', 'YouTube Link Title', features);
  403.       div.removeChild(embed);
  404.     } else if (cfg.embed_mode == 'player') {
  405.       popup.close();
  406.       popup.show(li);
  407.     }
  408.   },
  409.   embed: function (li, big) {
  410.     var site = sites[li.sid];
  411.     var embed = ce('iframe', {
  412.       src: site.embed(li.vid, li.t),
  413.       className: 'YTLT-embed'
  414.     });
  415.     embed.setAttribute('webkitAllowFullScreen', '');
  416.     embed.setAttribute('allowfullscreen', '');
  417.     embed.setAttribute('YTLT-sid', li.sid);
  418.     embedding.resize(embed, big);
  419.     embed.style.display = 'block';
  420.     return embed;
  421.   },
  422.   resize: function (embed, big) {
  423.     var site = sites[embed.getAttribute('YTLT-sid')];
  424.     var w = site.sizes[big ? 1 : 0][0];
  425.     var h = site.sizes[big ? 1 : 0][1];
  426.     embed.style.width = w + 'px';
  427.     embed.style.height = h + 'px';
  428.   },
  429.   preview: function (vi, li) {
  430.     if (vi && vi.preview) {
  431.       return vi.preview;
  432.     } else if (sites[li.sid].preview) {
  433.       return sites[li.sid].preview(li.vid);
  434.     }
  435.   }
  436. };
  437. var popup = {
  438.   show: function (li) {
  439.     if (!this.styleAdded) {
  440.       GM_addStyle('\t\t\t\t#YTLT-bg { position:fixed;z-index:9999;top:0;right:0;bottom:0;left:0;background-color:black;opacity:0.9; }\t\t\t\t#YTLT-player { display:block;position:fixed;z-index:10000;line-height:normal;background-color:black;border:2px solid black;font-size:13px;line-height:16px;padding:0;margin:0;left:auto;top:auto;right:auto;bottom:auto; }\t\t\t\t#YTLT-player-titlebar { display:block;line-height:17px;padding:0;background:#1b1b1b;border-bottom:2px solid black;text-align:'
  441.       + (cfg.reverse_buttons ? 'left' : 'right') + '; }\t\t\t\t#YTLT-player-darken { padding:0px 11px 3px 11px; }\t\t\t\t#YTLT-player-resize { padding:1px 11px 2px 11px; }\t\t\t\t#YTLT-player-close { padding:0px 28px 3px 28px; }\t\t\t\t#YTLT-player .YTLT-embed { border:0;line-height:normal; }\t\t\t\t#YTLT-player .YTLT-player-titlebar-button { vertical-align:top;display:inline-block;margin:0;font-weight:bold;font-size:14px;text-decoration:none;border:0;border-'
  442.       + (cfg.reverse_buttons ? 'right' : 'left') + ':2px solid black;color:#757575;text-decoration:none;cursor:pointer;font-family:"segoe ui",verdana,sans-serif; }\t\t\t\t#YTLT-player .YTLT-player-titlebar-button:hover { color:#959595!important; }\t\t\t\t.YTLT-embed { display:block;background-color:black;border:2px solid black;margin:0;padding:0;transition-property:width,height;transition-duration:500ms;transition-timing-function:ease; }\t\t\t\t#YTLT-player.YTLT-player-moving { opacity:0.8;cursor:move;border:2px solid white; }\t\t\t\t#YTLT-player.YTLT-player-moving .YTLT-embed { visibility:hidden; }\t\t\t\t.YTLT-noselect { -moz-user-select:none;-webkit-user-select:none;-o-user-select:none; }'
  443.       );
  444.       this.styleAdded = true;
  445.     }
  446.     this.li = li;
  447.     var titlebar = ce('div', {
  448.       id: 'YTLT-player-titlebar',
  449.       mousedown: this.onTitlebarMouseDown
  450.     });
  451.     var buttons = [
  452.       ce('a', {
  453.         id: 'YTLT-player-darken',
  454.         className: 'YTLT-player-titlebar-button YTLT-noselect',
  455.         innerHTML: '&#9788;',
  456.         click: this.onDarkenClick
  457.       }),
  458.       ce('a', {
  459.         id: 'YTLT-player-resize',
  460.         className: 'YTLT-player-titlebar-button YTLT-noselect',
  461.         click: this.onResizeClick
  462.       }),
  463.       ce('a', {
  464.         id: 'YTLT-player-close',
  465.         className: 'YTLT-player-titlebar-button YTLT-noselect',
  466.         innerHTML: 'X',
  467.         click: this.onCloseClick
  468.       })
  469.     ];
  470.     if (cfg.reverse_buttons) buttons.reverse();
  471.     for (var i = 0; i < buttons.length; i++) {
  472.       titlebar.appendChild(buttons[i]);
  473.     }
  474.     var player = ce('div', {
  475.       id: 'YTLT-player'
  476.     });
  477.     player.appendChild(titlebar);
  478.     player.appendChild(embedding.embed(li, cfg.big));
  479.     d.body.appendChild(player);
  480.     this.update();
  481.     var w = player.offsetWidth,
  482.     h = player.offsetHeight;
  483.     var x = parseFloat(cfg.x),
  484.     y = parseFloat(cfg.y);
  485.     var qm = d.compatMode == 'BackCompat';
  486.     var cw = qm ? d.body.clientWidth : d.documentElement.clientWidth;
  487.     var ch = qm ? d.body.clientHeight : d.documentElement.clientHeight;
  488.     var mx = cw - x - w / 2;
  489.     var isPosValid = mx > 0 && mx < cw && y > - 5 && y < ch - h / 2;
  490.     player.style.right = (isPosValid ? x : 80) + 'px';
  491.     player.style.top = (isPosValid ? y : ch / 2 - h / 2) + 'px';
  492.     if (cfg.darken) d.body.appendChild(ce('div', {
  493.       id: 'YTLT-bg'
  494.     }));
  495.     d.addEventListener('keydown', this.onKeyDown, false);
  496.   },
  497.   close: function () {
  498.     rm('YTLT-player');
  499.     rm('YTLT-bg');
  500.     d.removeEventListener('keydown', popup.onKeyDown, true);
  501.   },
  502.   update: function (e) {
  503.     $('YTLT-player-resize').innerHTML = cfg.big ? '&#65293;' : '&#65291;';
  504.   },
  505.   onCloseClick: function (e) {
  506.     e.preventDefault();
  507.     popup.close();
  508.   },
  509.   onResizeClick: function (e) {
  510.     e.preventDefault();
  511.     cfg.big = !cfg.big;
  512.     cfg.save();
  513.     var embed = d.body.querySelector('#YTLT-player .YTLT-embed');
  514.     embedding.resize(embed, cfg.big);
  515.     popup.update();
  516.   },
  517.   onDarkenClick: function (e) {
  518.     if ($('YTLT-bg')) {
  519.       rm('YTLT-bg');
  520.       cfg.darken = false;
  521.       cfg.save();
  522.     } else {
  523.       d.body.appendChild(ce('div', {
  524.         id: 'YTLT-bg'
  525.       }));
  526.       cfg.darken = true;
  527.       cfg.save();
  528.     }
  529.   },
  530.   onKeyDown: function (e) {
  531.     if (e.keyCode == 27) popup.close();
  532.   },
  533.   onTitlebarMouseDown: function (e) {
  534.     var t = e.target;
  535.     if (t.id != 'YTLT-player-titlebar') return;
  536.     t.parentNode.className = 'YTLT-player-moving';
  537.     var r = t.getBoundingClientRect();
  538.     t.dx = e.clientX - r.left;
  539.     t.dy = e.clientY - r.top;
  540.     d.body.className += ' YTLT-noselect';
  541.     window.addEventListener('mousemove', popup.onTitlebarMouseMove, false);
  542.     window.addEventListener('mouseup', popup.onTitlebarMouseUp, false);
  543.   },
  544.   onTitlebarMouseMove: function (e) {
  545.     var titlebar = $('YTLT-player-titlebar');
  546.     titlebar.parentNode.style.right = (d.compatMode == 'BackCompat' ? d.body.clientWidth : d.documentElement.clientWidth) - e.clientX - titlebar.offsetWidth + titlebar.dx - 2 + 'px';
  547.     titlebar.parentNode.style.top = e.clientY - titlebar.dy - 2 + 'px';
  548.   },
  549.   onTitlebarMouseUp: function (e) {
  550.     var titlebar = $('YTLT-player-titlebar');
  551.     titlebar.parentNode.className = '';
  552.     titlebar.dx = null;
  553.     titlebar.dy = null;
  554.     window.removeEventListener('mousemove', popup.onTitlebarMouseMove, false);
  555.     window.removeEventListener('mouseup', popup.onTitlebarMouseUp, false);
  556.     d.body.className = d.body.className.replace('YTLT-noselect', '');
  557.     cfg.x = parseInt(titlebar.parentNode.style.right);
  558.     cfg.y = titlebar.parentNode.style.top;
  559.     cfg.save();
  560.   }
  561. };
  562. var sites = {
  563.   'yt': {
  564.     patterns: [
  565.       'youtube.com',
  566.       'youtu.be',
  567.       'youtube.googleapis.com'
  568.     ],
  569.     parse: function (url) {
  570.       return /^https?:\/\/((www\.|m\.)?you.+v[=\/]|#p\/[a-z]\/.+\/|youtu\.be\/)([a-z0-9_-]+)(.*[#&\?]t=([0-9hms]+))?/i.exec(url) ? {
  571.         vid: RegExp.$3,
  572.         t: RegExp.$5
  573.       }
  574.        : null;
  575.     },
  576.     sizes: [
  577.       [640,
  578.       390],
  579.       [
  580.         853,
  581.         510
  582.       ]
  583.     ],
  584.     embed: function (vid, t) {
  585.       var m = /((\d+)h)?((\d+)m)?(\d+)?/.exec(t);
  586.       t = parseInt(m[2] || 0) * 3600 + parseInt(m[4] || 0) * 60 + parseInt(m[5] || 0);
  587.       return 'https://www.youtube.com/embed/' + vid + '?autoplay=1&rel=1' + (t ? '&start=' + t : '');
  588.     },
  589.     url: function (vid, t, oUrl) {
  590.       return 'https://www.youtube.com/watch?v=' + vid + (/\b(list=[a-z0-9_-]+)/i.exec(oUrl) ? '&' + RegExp.$1 : '') + (t ? '#t=' + t : '');
  591.     },
  592.     preview: function (vid) {
  593.       return 'https://img.youtube.com/vi/' + vid + '/0.jpg';
  594.     },
  595.     icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAAMZQTFRFkQ0IyBILyBILkQ0IyBILkQ0IkQ0IyBILyBILkQ0IpA8JmQ4JlQ4Ing4JuxEKtRAKwBEKxBELyBILkQ0IAAAA+fn5wRcQtR0Yvh8YqRsWrx0XoxsV56Wj8vLy9+/vyTMttxgS252b6Ojo0WNfnRcTy8jIlg4JzL+/XAgFjjAtdAoHiFNRmA4IbxQQgQwI05qYmw4JrI2M8fHx1dXV5+fn3d3dkQ0IpA8JtRAKyBILng4Jqg8JrxAKuxEKmQ4JwBEKxBELlQ4ItxbjVAAAABV0Uk5TCaUJBvmihNKi2PzMh+rq/MyHzMwAD5S0KQAAAItJREFUGNOFz8cWgjAARNGxKx2CvWDvFRILCuj//5QJcYMuvKt3Zjdwv+BnyOec4u2j4lRd2M8MG1bCNXpeIlkwIq5VH0yilAHzyjV9vz8aijLxEDqU0vEhTdyFNmNssUoTyoXrBsFptxWlQA+56WyzPooIdagxN1/uY0mF9srQgBIhZ6lGSLmAv2/fr2gov1/MElQAAAAASUVORK5CYII=',
  596.     request: function (vid, f) {
  597.       net.json('https://gdata.youtube.com/feeds/api/videos/' + vid + '?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode', function (code, obj, txt) {
  598.         if (code == 404 && txt.indexOf('Video not found') != - 1) {
  599.           window.setTimeout(f, 0, {
  600.             title: 'Video not found',
  601.             status: 4
  602.           });
  603.         } else if (code == 403 && txt.indexOf('Private video') != - 1) {
  604.           window.setTimeout(f, 0, {
  605.             title: 'Private video',
  606.             status: 3
  607.           });
  608.         } else if (code == 200 && obj) {
  609.           var entry = obj.entry;
  610.           var title = entry.title.$t;
  611.           var status;
  612.           if (entry.app$control && entry.app$control.yt$state && entry.app$control.yt$state.reasonCode && entry.app$control.yt$state.reasonCode != 'limitedSyndication') {
  613.             status = 3;
  614.           } else if (typeof entry.yt$noembed == 'object') {
  615.             status = 5;
  616.           }
  617.           window.setTimeout(f, 0, {
  618.             title: title,
  619.             status: status
  620.           });
  621.         } else {
  622.           window.setTimeout(f, 0);
  623.         }
  624.       });
  625.     }
  626.   },
  627.   'vm': {
  628.     patterns: [
  629.       'vimeo.com'
  630.     ],
  631.     parse: function (url) {
  632.       return /^https?:\/\/vimeo\.com\/(m\/)?([0-9]+)/i.exec(url) ? {
  633.         vid: RegExp.$2
  634.       }
  635.        : null;
  636.     },
  637.     sizes: [
  638.       [640,
  639.       360],
  640.       [
  641.         853,
  642.         480
  643.       ]
  644.     ],
  645.     embed: function (vid, t) {
  646.       return 'https://player.vimeo.com/video/' + vid + '?title=1&portrait=1&byline=1&color=aa0000&autoplay=1';
  647.     },
  648.     url: function (vid, t) {
  649.       return 'https://vimeo.com/' + vid;
  650.     },
  651.     icon: 'data:image/gif;base64,R0lGODlhEAAQAMQfAAuUuQynzzu83u/09Ryy2Su320rC4IbW6mKOngqHq5GvuoO3xhVbc0m92zV7keDo60R8j8Hc5KHEzwuawGSluaTg8Ah1lfD5/BmPsJPI13fR6LLd6f///wuavg2t1gAAACH5BAEAAB8ALAAAAAAQABAAAAVu4NeNZFmKgqeurCqMbbzCbrEWh0ao9MFdNgNnWOF1CJUhR+PZDIYRY2MRGWYIFsVQYgRYHNBAc4gwqiaPoUfIkQDMKsnwkB5YZp0VRTmEsGgeGHwIb3grAVoDCAktgB4WEAyMjY4AYpQiJpojHyEAOw==',
  652.     request: function (vid, f) {
  653.       net.json('https://vimeo.com/api/oembed.json?url=http://vimeo.com/' + vid, function (code, obj) {
  654.         if (code == 404) {
  655.           window.setTimeout(f, 0, {
  656.             title: 'Video not found',
  657.             status: 4
  658.           });
  659.         } else if (code == 403) {
  660.           window.setTimeout(f, 0, {
  661.             title: 'Unknown video',
  662.             status: 5
  663.           });
  664.         } else if (code == 200 && obj) {
  665.           window.setTimeout(f, 0, {
  666.             title: obj.title ? obj.title : 'Unknown video',
  667.             preview: obj.thumbnail_url
  668.           });
  669.         } else {
  670.           window.setTimeout(f, 0);
  671.         }
  672.       });
  673.     }
  674.   },
  675.   'vn': {
  676.     patterns: [
  677.       'vine.co'
  678.     ],
  679.     parse: function (url) {
  680.       return /^https?:\/\/(www\.)?vine\.co\/v\/([a-z0-9]+)/i.exec(url) ? {
  681.         vid: RegExp.$2
  682.       }
  683.        : null;
  684.     },
  685.     sizes: [
  686.       [500,
  687.       500],
  688.       [
  689.         660,
  690.         660
  691.       ]
  692.     ],
  693.     embed: function (vid, t) {
  694.       return 'https://vine.co/v/' + vid + '/card?mute=0';
  695.     },
  696.     url: function (vid, t) {
  697.       return 'https://vine.co/v/' + vid;
  698.     },
  699.     icon: 'data:image/gif;base64,R0lGODlhEAAQALMAAAqnfLXk1/b7+jS1ks3t5JvZyFbBpOf28onSvhirhHLLswCjdgCkdwCjd////wCkeCH5BAAAAAAALAAAAAAQABAAAARp8Mk5TQgoNbqrcGCgMQZiUISDHcK5IE4xDezQBI6yvOpcPzjdwtCbBAEpF+1gkygchIEis0kkdwwr1DUpFCUDnOAgHI6bTtABQcGJGA1tYeTJSWBMLAU//ZQ5AF4fMQCAe36FhhQGXBQRADs=',
  700.     request: function (vid, f) {
  701.       net.text('https://vine.co/v/' + vid, [
  702.         /"og:title" content="(.+?)">/,
  703.         /"og:image" content="(.+?)"/
  704.       ], function (code, m) {
  705.         var title = m[0],
  706.         preview = m[1];
  707.         if (code == 404) {
  708.           window.setTimeout(f, 0, {
  709.             title: 'Video not found',
  710.             status: 4
  711.           });
  712.         } else {
  713.           window.setTimeout(f, 0, {
  714.             title: title ? title[1] : 'Unknown video',
  715.             preview: preview ? preview[1] : null
  716.           });
  717.         }
  718.       });
  719.     }
  720.   },
  721.   'll': {
  722.     patterns: [
  723.       'liveleak.com/view'
  724.     ],
  725.     parse: function (url) {
  726.       return /^https?:\/\/www\.liveleak\.com\/view.+i=([0-9a-z_]+)/i.exec(url) ? {
  727.         vid: RegExp.$1
  728.       }
  729.        : null;
  730.     },
  731.     sizes: [
  732.       [625,
  733.       352],
  734.       [
  735.         852,
  736.         480
  737.       ]
  738.     ],
  739.     embed: function (vid) {
  740.       return 'http://www.liveleak.com/e/' + vid + '?autostart=true';
  741.     },
  742.     icon: 'data:image/gif;base64,R0lGODlhEAAQAIAAAPz8/JcAACH5BAAAAAAALAAAAAAQABAAAAIrjI+pB+1gWoLhRcqurDhqumXcFnoj2FXfNa1ce7IISqb0DcJPPi+f4wsWAAA7',
  743.     request: function (vid, f) {
  744.       net.text('http://www.liveleak.com/view?i=' + vid, [
  745.         /Item not found!/i,
  746.         /<title>LiveLeak\.com - (.+?)<\/title>/i,
  747.         /"og:image" content="(.+?)"/
  748.       ], function (code, m) {
  749.         var notfound = m[0],
  750.         title = m[1],
  751.         preview = m[2];
  752.         if (notfound) {
  753.           window.setTimeout(f, 0, {
  754.             title: 'Video not found',
  755.             status: 4
  756.           });
  757.         } else {
  758.           window.setTimeout(f, 0, {
  759.             title: title ? title[1] : 'Unknown video',
  760.             preview: preview ? preview[1].replace('_thumb_', '_sf_')  : null
  761.           });
  762.         }
  763.       });
  764.     }
  765.   },
  766.   'wh': {
  767.     patterns: [
  768.       'worldstarhiphop.com'
  769.     ],
  770.     parse: function (url) {
  771.       return /^https?:\/\/(www\.|m\.)?worldstarhiphop\.com\/.+v=([a-z0-9]+)/i.exec(url) ? {
  772.         vid: RegExp.$2
  773.       }
  774.        : null;
  775.     },
  776.     sizes: [
  777.       [448,
  778.       374],
  779.       [
  780.         640,
  781.         534
  782.       ]
  783.     ],
  784.     embed: function (vid) {
  785.       return 'http://www.worldstarhiphop.com/videos/ea/16711680/' + vid;
  786.     },
  787.     icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXpJREFUeNpsUt1KAkEY/Ry2yx6gF4gQIXoakZAQkegqQiJ6gIiIJSQkRGSRiPCqNzGjve8JvOoq+Tz2nZnZbakGnf1+ztlz5tuprV9mEpdzIrAHBI7PMnE+BYhIFEowK0kkqGw1m1b7ms2YIHGJYRIDusQIiigALRXC8u8C68QoFVRqoff5PKUHtqVxeJQ/TU2+0WrnVofz73DbrTZ9L6fZjtEVK9X4E1mFNATQkBps+Zg5VV1ko712R+OijxiWgaoBFtnYAp4dQD4Z1zs9ixrdHo+D8BcrWt/2fDKiXdj8YKehrvV3uydmYz4aWnEFzMdDkHNsu6WgPdgASKCxh3t68ONQVOyJsFUUah/DQRiPxI1JUWASZx6HyO+gJaF+2pcCVyXkg7RC8IfjDfB5fpcW4J8VMKHqCYjstYmcUWQj8Ytu/P6e3pSaCeDVHMf4ll47+hd/44J1t9+/QCz5C+cJEmZ/cH4p/y14F/DDSKqN19urvwq/yN8CDAB9dTAcPA3GZgAAAABJRU5ErkJggg==',
  788.     request: function (vid, f) {
  789.       net.text('http://www.worldstarhiphop.com/videos/video.php?v=' + vid, [
  790.         /<title>(Video: )?(.+?)\s*(\(\*Warning|<\/title>)/i,
  791.         /"image_src" href="(.+?)"/
  792.       ], function (code, m) {
  793.         var title = m[0],
  794.         preview = m[1];
  795.         if (title) {
  796.           window.setTimeout(f, 0, {
  797.             title: title[2],
  798.             preview: preview ? preview[1] : null
  799.           });
  800.         } else {
  801.           window.setTimeout(f, 0);
  802.         }
  803.       });
  804.     }
  805.   },
  806.   'dm': {
  807.     patterns: [
  808.       'dailymotion.com/video'
  809.     ],
  810.     parse: function (url) {
  811.       return /^https?:\/\/www\.dailymotion\.com\/video\/([a-z0-9]+)(.+start=([0-9]+))?/i.exec(url) ? {
  812.         vid: RegExp.$1,
  813.         t: RegExp.$3
  814.       }
  815.        : null;
  816.     },
  817.     sizes: [
  818.       [620,
  819.       352],
  820.       [
  821.         853,
  822.         480
  823.       ]
  824.     ],
  825.     embed: function (vid, t) {
  826.       return 'https://www.dailymotion.com/embed/video/' + vid + '?logo=0&autoplay=1' + (t ? '&start=' + t : '');
  827.     },
  828.     url: function (vid, t) {
  829.       return 'https://www.dailymotion.com/video/' + vid + (t ? '?start=' + t : '');
  830.     },
  831.     icon: 'data:image/gif;base64,R0lGODlhEAAQAMQAAGB0hvHXCi5aq6mYZThltsiUCEd1ydmlAXSImMi1g7KCDePUZdO3TjJWl5dpBf7wAT5jpNrPkNCsJyVQnOzBBJ6klcCYLx1Jmdvh62WT5fLiKYV3V9W8Gr27tUlrqjVYlyH5BAAAAAAALAAAAAAQABAAAAWfIAZ5ZGmSkJgZbOuyGQQZRF1Xnl0bMm0jHISOwJv9FhSJ0Mb76CqLg2JAENg+TisBoTk4NoKw9dOoCjyVQOHrERMaDcFk4mEEvIoORAyXQwYcDwcFBxYJewJ9Fx0SAYIHFAoFHxOJDRMXCQWOB5CSCHNwmAMKD48UBQUJFxNwFxcWEqadqIavlwIXHwARCxYWDBEAEBdyGK1YycpkExghADs=',
  832.     request: function (vid, f) {
  833.       net.json('https://www.dailymotion.com/services/oembed?format=json&url=http://www.dailymotion.com/video/' + vid, function (code, obj) {
  834.         if (code == 404) {
  835.           window.setTimeout(f, 0, {
  836.             title: 'Video not found',
  837.             status: 4
  838.           });
  839.         } else if (code == 200 && obj) {
  840.           window.setTimeout(f, 0, {
  841.             title: obj.title ? obj.title : 'Unknown video',
  842.             preview: obj.thumbnail_url
  843.           });
  844.         } else {
  845.           window.setTimeout(f, 0);
  846.         }
  847.       });
  848.     }
  849.   },
  850.   'cb': {
  851.     patterns: [
  852.       'coub.com/view/'
  853.     ],
  854.     parse: function (url) {
  855.       return /^https?:\/\/coub\.com\/view\/([a-z0-9]+)/i.exec(url) ? {
  856.         vid: RegExp.$1
  857.       }
  858.        : null;
  859.     },
  860.     sizes: [
  861.       [640,
  862.       360],
  863.       [
  864.         853,
  865.         480
  866.       ]
  867.     ],
  868.     embed: function (vid, t) {
  869.       return 'http://coub.com/embed/' + vid + '?muted=false&autostart=true&noSiteButtons=true';
  870.     },
  871.     url: function (vid, t) {
  872.       return 'http://coub.com/view/' + vid;
  873.     },
  874.     icon: 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAWlBMVEUAAAADM/8AIP8DMv8AK/8DMv8DMv8AMP8EMv8EMv8EM/8DMv////8UQP+Dmv9kgf/t8P/M1v/j6f8dSP96k//Z4f+Mov/Bzf8MOf+0wv87X/91j/+Yq/9rhv9szalUAAAACnRSTlMAvwjCBpSYKo/huP286QAAAHpJREFUGNNlj9sSgyAMRGkrBQ4R1Kq9//9vCiqOo+ctmWx2V2WMdd47a9RCpVm5X+f5wsatSgvNDp30QD02ItKMDzDKprmVto+hkwhWOQjyfuW7bw1OeXjKh4I/LthL+ixZnw4hhkH+YBfb0GXbX7Y9BjtFP5cr9Sn1JyOZCa2SfTdfAAAAAElFTkSuQmCC',
  875.     request: function (vid, f) {
  876.       net.json('http://coub.com/api/oembed.json?url=http://coub.com/view/' + vid, function (code, obj) {
  877.         if (code == 404) {
  878.           window.setTimeout(f, 0, {
  879.             title: 'Video not found',
  880.             status: 4
  881.           });
  882.         } else if (code == 403) {
  883.           window.setTimeout(f, 0, {
  884.             title: 'Unknown video',
  885.             status: 5
  886.           });
  887.         } else if (code == 200 && obj) {
  888.           window.setTimeout(f, 0, {
  889.             title: obj.title ? obj.title : 'Unknown video',
  890.             preview: obj.thumbnail_url
  891.           });
  892.         } else {
  893.           window.setTimeout(f, 0);
  894.         }
  895.       });
  896.     }
  897.   }
  898. };
  899. var cache = {
  900.   get: function (sid, vid) {
  901.     if (!this.obj) this.load();
  902.     var data = this.obj[sid + vid];
  903.     if (!data) return false;
  904.     data = data.split('\t');
  905.     return {
  906.       title: data[0],
  907.       status: data[1],
  908.       preview: data[2]
  909.     };
  910.   },
  911.   set: function (sid, vid, info) {
  912.     if (!info) return;
  913.     this.load();
  914.     this.obj[sid + vid] = [
  915.       info.title,
  916.       info.status,
  917.       info.preview
  918.     ].join('\t').trim();
  919.     this.save();
  920.   },
  921.   save: function () {
  922.     try {
  923.       cache.clean();
  924.       GM_setValue('cache', JSON.stringify(cache.obj));
  925.     } catch (ex) {
  926.       GM_log('Error while saving cache: ' + ex);
  927.     }
  928.     cache.obj = null;
  929.   },
  930.   load: function () {
  931.     try {
  932.       this.obj = JSON.parse(GM_getValue('cache'));
  933.     } catch (ex) {
  934.     }
  935.     if (this.obj == null || typeof (this.obj) != 'object') this.obj = {
  936.     };
  937.   },
  938.   clean: function (num) {
  939.     var overflow = Object.keys(this.obj).length - 300;
  940.     if (overflow < 1) return;
  941.     var i = 0,
  942.     f = Object.prototype.hasOwnProperty;
  943.     for (var p in this.obj) {
  944.       if (f.call(this.obj, p)) {
  945.         delete this.obj[p];
  946.         if (++i == overflow + 20) return;
  947.       }
  948.     }
  949.   }
  950. };
  951. var cfg = {
  952.   settings: {
  953.     reverse_buttons: {
  954.       title: 'Move buttons to the left',
  955.     default:
  956.       false,
  957.       depends: {
  958.         embed_mode: /player/
  959.       }
  960.     },
  961.     big: {
  962.       title: '480p instead of 360p',
  963.     default:
  964.       false,
  965.       depends: {
  966.         embed_mode: /window|inline/
  967.       }
  968.     },
  969.     embed_mode: {
  970.       title: 'Embed on click',
  971.     default:
  972.       'player',
  973.       options: {
  974.         off: 'off',
  975.         player: 'in-page popup',
  976.         inline: 'inline',
  977.         window: 'popup window'
  978.       }
  979.     },
  980.     rewrite: {
  981.       title: 'Turn links into clean HTTPS URLs if possible',
  982.     default:
  983.       true
  984.     },
  985.     urls_only: {
  986.       title: 'Look up info only when link text is URL',
  987.     default:
  988.       false
  989.     },
  990.     previews: {
  991.       title: 'Show preview image on hover',
  992.     default:
  993.       true
  994.     },
  995.     darken: {
  996.     },
  997.     x: {
  998.     },
  999.     y: {
  1000.     }
  1001.   },
  1002.   load: function () {
  1003.     forEach(cfg.settings, function (n) {
  1004.       cfg[n] = GM_getValue(n, cfg.settings[n].default);
  1005.     });
  1006.   },
  1007.   save: function () {
  1008.     forEach(cfg.settings, function (n) {
  1009.       if (typeof cfg[n] != 'undefined') GM_setValue(n, cfg[n]);
  1010.     });
  1011.   }
  1012. };
  1013. window.setTimeout(onLoad, 100);
Add Comment
Please, Sign In to add comment