NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Intercept YouTube Links // @namespace http://github.com/panzi // @description Inserts a hop to all watch links on YouTube in order to disable auto-play. The link won't be inserted by a normal click, only middle-click/context menu/D'n'D. // @include * // @run-at document-end // @version 1.0 // ==/UserScript== var linkSelector; var linkRegex; var videoTitle; if (/^https?:\/\/(www\.)?youtube(-nocookie)?\.com\//i.test(location.href)) { linkSelector = 'a[href^="/watch?"], a[href^="https://www.youtube.com/watch?"], a[href^="http://www.youtube.com/watch?"], '+ 'a[href^="https://www.youtube-nocookie.com/watch?"], a[href^="http://www.youtube-nocookie.com/watch?"]'; linkRegex = /^(https?:\/\/(www\.)?youtube(-nocookie)?\.com)?\/watch\?/i; videoTitle = function (link) { var title = link.title; if (!title) { title = link.querySelector('.title'); if (title) { title = title.title||title.textContent||link.href; } else { title = link.href; var elem = link.parentNode.parentNode; if (elem && elem.classList && elem.classList.contains('yt-lockup-video')) { elem = elem.querySelector('a[title]'); if (elem) title = elem.title; } } } return title; }; } else { linkSelector = 'a[href^="https://www.youtube.com/watch?"], a[href^="http://www.youtube.com/watch?"], '+ 'a[href^="https://www.youtube-nocookie.com/watch?"], a[href^="http://www.youtube-nocookie.com/watch?"]'; linkRegex = /^https?:\/\/(www\.)?youtube(-nocookie)?\.com\/watch\?/i; videoTitle = function (link) { return link.title||link.textContent||link.href; }; } function isVideoLink (elem) { return elem.nodeType === 1 && elem.nodeName === "A" && linkRegex.test(elem.href); } function insertHops (ctx) { var links = ctx.querySelectorAll(linkSelector); if (isVideoLink(ctx)) { links = Array.prototype.slice.call(links); links.push(ctx); } for (var i = 0; i < links.length; ++ i) { insertHop(links[i]); } } function parseParams (search) { var params = {}; if (search) { search = search.split("&"); for (var i = 0; i < search.length; ++ i) { var param = search[i].split("="); params[decodeURIComponent(param[0])] = decodeURIComponent(param.slice(1).join("=")); } } return params; } function insertHop (link) { var url = link.href; var video_id = parseParams(/^[^\?]*\?([^#]*)/i.exec(url)[1]).v; var thumb = 'https://i1.ytimg.com/vi/'+video_id+'/hqdefault.jpg'; var title = videoTitle(link); var reader = new FileReader(); reader.onload = function () { link.href = this.result; link.addEventListener('click',function (event) { if ('buttons' in event ? event.buttons & 1 : event.button === 0) { location.href = url; event.preventDefault(); event.stopPropagation(); } }, false); }; reader.readAsDataURL(new Blob(['<!DOCTYPE html>', '<html>', '<head>', '<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>', '<title>',escapeHtml(title),'</title>', '<style type="text/css">html, body {margin:0;padding:0;}\n', '.main {width:100%;height:100%;position:absolute;left:0;right:0;top:0;bottom:0;display:table;}\n', '.title {display:block;margin-top:10px;font-size:26px;font-weight:bold;}\n', 'a {display:table-cell;text-align:center;vertical-align:middle;margin:auto;text-decoration:none;}\n', 'img {border:none;}</style>', '</head>', '<body>', '<div class="main">', '<a href="',escapeHtml(url),'">', '<img src="',escapeHtml(thumb),'"/>', '<span class="title">',escapeHtml(title),'</a></span>', '</a>', '</div>', '</body>', '</html>'],{encoding:"UTF-8",type:"text/html;charset=UTF-8"})); } var HTML_CHAR_MAP = { '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }; function escapeHtml (s) { return s.replace(/[<>&"']/g, function (ch) { return HTML_CHAR_MAP[ch]; }); } insertHops(document); var observer = new MutationObserver(function (mutations) { for (var i = 0; i < mutations.length; ++ i) { var mutation = mutations[i]; if (mutation.type === "childList") { for (var j = 0; j < mutation.addedNodes.length; ++ j) { var node = mutation.addedNodes[j]; if (node.nodeType === 1) { insertHops(node); } } } else if (mutation.type === "attributes") { if (mutation.attributeName === "href" && isVideoLink(mutation.target)) { insertHop(mutation.target); } } } }); observer.observe(document.body, {attributes: true, childList: true, subtree: true});