NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Convert Youtube Embeds to Image Links // @description Tries to turn embedded Youtube videos into thumbnails - this is based on "Stop Overzealous Embedding" https://openuserjs.org/users/ConnorBehan // @namespace http://elundmark.se/code/ // @version 0.2.7 // @date 2016-05-11 // @autor Erik Lundmark // @contact e@3r1k.se // @license MIT; http://opensource.org/licenses/MIT // @supportURL https://github.com/elundmark/Convert-Youtube-Embeds-to-Image-Links-UserScript/issues // @updateURL http://f.3r1k.se/js/convert_youtube_embeds_to_image_links/convert_youtube_embeds_to_image_links.meta.js // @downloadURL http://f.3r1k.se/js/convert_youtube_embeds_to_image_links/convert_youtube_embeds_to_image_links.user.js // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAA1VBMVEUAAAAAAAAFAQEGAQEHAQEIAQENAgIPAwMVBAQaBQUdBQUeBgYhBwcfCgosCQkyCgo3Cws8DAxADQ1GDg49FBRSEBBdExNhFBRwFxd5GBhAKCh6GRk4MjKMHR2PHR1DPT2nIyOtJCREQ0O2JiatKSm5JibBKCjIKirNKyvPKyvQKyvZLS3aLS3eLS3fLS3gLS3dLi7eLi7fLi7gLi7eLy/fLy/gLy/eNTXhNja0VFTkSkrkS0u5dHTpbW3pbm7vl5fwl5fks7PEv7/2wcH74+P++Pj///+XlX/1AAAAAXRSTlMAQObYZgAABERJREFUeAHtm2mT20QYhF8BCUeAbDh2uckSYGGJNLFm1IT7nv//kyirFrrsidc91UWRD34+pVIVPf0e8uFR4sR/y4kTJ4Zh+H/9W+z0jn/FSu/6V6z0hp9Y6Q0/sdIbfmKlN/zE+Nd330dGBsY55zmPUwKmksqIsWBl/WMqCSjTmOdNmr95fTAS5LdeHHZ4cI0+ntwfWt6dsEEcARnA+bDPvUv08Ojt4RncubjClryJQ4wAcEU/eXBp+5kAWIIQrFxdDESYgtB/co4byuaQHxd3BtJMwfMzAVBijxkr5/T39oB+KcEcO0wA52/0gPM/tgdY5PlzEy1/kyDvB7ji/PUpqH7y3mPcQH9q90+cQr//3tdoW4AtH9Kv90DdP/qvQXY38ImU/1KsX9gj3gn9V7DqJ4kBOhJcK/ULfs4g8yr39SnY/edrwaj3kT3w+88AIPom+vXzHcG4llE/l2B2q3HuHq4A5E3k9Xw/pohYmo3SExj9ZwtKu9NyTUb9fC207mqzfhQGIPoeePWvMIC6B3XglT92/QygJ6iVEe56/W8DKJtYKyPY9TOAvomVCZz6GWBGX4J6g18/A3QlqP9i+MkSE4hyN1Zi9n9l5ivxsU1kAGLWv3YgAWoPGIB49QOZOyD2oO5h1Q+U6P22VRscPxAZRJkCxcTwcwfUKVRCev1kYgCxB/XZ9PrZARCpB/UQXX4SY+fvTvUgHX5SooAoU6i3IPtJChBpCvVW6O/cAb0H9XY++/EpeigBlccvM8Bt/PmzEUDYw3qcP37wAxD65QD1r1+f+gFavx6Ac/AD8DNyX4Cf/ACtXw7w+y/+CNr+6wGGdy79JWz9agD+iuMHoF8OIPyman4iEvxdPYgi7R+R9HoPUoySn2h6+V2xhNZ/ovrVBJEEvxCg+5sBA0h+Iuu1PZgiSfMnul+7FyJL9RNNr/cgZslPJL3egxJJ8hPdL21ijkWffxvgI+eUZ2WJRfKTnXfdb/vPF5oAs9r/JsBv35snXeyA7meAT78zzplIRHT4GWD44HPjtKoJIM6fAYY3rt2TLgaQ/ITfv7yTriaA2tHadNTaRAboqcY6NWsCFPtKRoIlIjZ6/f7JKeGhlXH+Z5y1gcfXi1GFsT0cgV9/91kbiS1u/UYHGcCo30jAw2vDb21i+ifAl0b/rT2IFeCrl4z6jSnwMb6HZz257QRfYGXiYzy4esWvX96Ds0d7D7SBCVy/ss9nDzkBBuAUhP47m0g/9h9mOzPr5x5I/hJkYQ+s+oUErH8OIUHjdzeR/hQ7gAn6/fom0o/YozCB7ecmCvWTwgSEfn8K9I9LEILUJKDf7gH9JcdBZhQmoN/uAf0lzXGMV20/N5G8+cmUOh/vf4F/s8wZmNbn+zcTFpQ8oqQFqZQyAiWVhKVMI0rO8wjktGwLfc37Dwbh0+knpp/Q34nlJ34zfVy/D/3PJSdOnDhx4m//OuSgMioX6QAAAABJRU5ErkJggg== // @include * // @exclude http*://youtu.be/* // @exclude http*://*.youtu.be/* // @exclude http*://*.ytimg.com/* // @exclude https://www.youtube.com/feed/* // @exclude https://www.youtube.com/channel/* // @exclude https://www.youtube.com/user/* // @exclude https://www.youtube.com/watch?* // @exclude https://www.youtube.com/playlist?* // @exclude https://www.youtube.com/my_videos?* // @exclude https://www.youtube.com/dashboard?* // @exclude https://www.youtube.com/view_all_playlists* // @grant none // ==/UserScript== // Change iframesLinkTarget / nonIframesLinkTarget to "_blank" if you want to open the videos in a new window (function () { "use strict"; if (!Boolean("getComputedStyle" in window)) return; var ytWatchBaseHref = "https://www.youtube.com/watch?v=", youtubeDomainPatt = /^(?:(?:[a-zA-Z0-9\-]+\.)?youtube(?:\-nocookie)?\.com)$/, riskyTags = ["object", "param", "embed"], youtubeIdPatt = /(?:\/v\/|\?v=|\/embed\/)([a-zA-Z0-9_\-]{11})/, iframesLinkTarget = "_top", nonIframesLinkTarget = "_self", loadedPatt = /^loaded\d{13}$/, replCounter = 0, insideIframeId, MutationObserver, observer, makeArray = function (o) { // Turn array-like objects into Arrays // http://cwestblog.com/2015/02/11/javascript-quirk-array-slicing-with-node-lists/ try { return Array.prototype.slice.call(o); } catch (e) {} for (var i = 0, l = o.length, a = new Array(i); i < l; i+=1) { if (i in o) { a[i] = o[i]; } } return a; }, getIframeTmpl = function (docTitle, th) { // Inline hardcoded style attributes helps weird "leakage" of forced styles to apply to other elements // can't replicate it but it happened before this, even to a top window from an iframe! return [ "<!DOCTYPE html>"+ "<html style='margin:0!important;padding:0!important;overflow:hidden!important;'>"+ "<head>"+ "<meta charset='utf-8'>"+ "<meta name='viewport' content='width=device-width, initial-scale=1'>"+ "<title>"+docTitle+"</title>"+ "</head>"+ "<body style='margin:0!important;padding:0!important;background:#FFF;overflow:hidden!important;'>", th, "</body>"+ "</html>" ]; }, // New icon: https://www.iconfinder.com/icons/410520 (16% auto) // Old icon: https://www.iconfinder.com/icons/669690 (20% auto) youtubeIcon = "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjUwMCIgd2lkdGg9IjUwMCIgeG1sbnM9Imh0dHA6Ly93"+ "d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCAwdjUwMGg1MDBWMHoiIGZpbGw9IiNjYzE4MWUiLz48cGF0aCBkP"+ "SJNNTAwIDI0Ni4yNzJWNTAwSDE4NC4wMThsLTc1Ljc1Mi03NS43NTItLjQxLTE3NS42NzcgOTAuNjEzLTIyLjA0My0yMy"+ "44MjYtMjMuODI1IDMuNTctNzUuOTE2LTcuODU0LTY2LjgxIDI2Ljc5NyAyNi43OTYgMjQuNTg3LTI2LjgwNCA0My43Mzc"+ "gNDMuNzM3IDMuODItMS44IDMyLjA3MyAzMi4wNzMgMTIuNjg1LTM3LjY4NyAyMS44NDUgMjEuODQ1IDE0LjE2LTIxLjh6"+ "IiBzdHJva2U9IiMwMDAiIG9wYWNpdHk9Ii4zIi8+PHBhdGggZD0iTTE0Ny44NzUgNjBjNC41MDIgMTMuMjM1IDkuMjEyI"+ "DI2LjUxIDEzLjcyIDM5Ljc1IDYuODUgMTkuOTAyIDExLjEyNSAzNC44OTIgMTMuMDYgNDUuMTI1djU3LjgxM2gyMS4zNz"+ "Z2LTU3LjgxM0wyMjEuNzIgNjBoLTIxLjU5NWwtMTQuNTYzIDU2LjAzTDE3MC4zNDUgNjBoLTIyLjQ3em0xMDIuNDcgMzU"+ "uMDYzYy05LjYgMC0xNy4wODIgMy42MzQtMjIuNDA3IDEwLjkwNi00LjEgNS4zNy02LjAzMiAxMy42OTUtNi4wMzIgMjUu"+ "MDZ2MzcuMjJjMCAxMS4zIDEuOTMzIDE5LjY4IDYuMDMgMjUgNS4zMjggNy4yNSAxMi44MSAxMC45MDYgMjIuNDA4IDEwL"+ "jkwNiA5LjY1NSAwIDE3LjE3LTMuNjU1IDIyLjUtMTAuOTA2IDQuMDQtNS4zMiA1Ljk3LTEzLjcgNS45Ny0yNWwtLjAwMi"+ "0zNy4yMmMwLTExLjM2NC0xLjkzLTE5LjY5LTUuOTY4LTI1LjA2LTUuMzMtNy4yNzMtMTIuODQ1LTEwLjkwNy0yMi41LTE"+ "wLjkwN3ptNDQuMzEgMS4yOHY4NC4wOTRjMCA3LjUwNi42ODggMTIuNTkgMS43NSAxNS44MTMgMS45MjMgNS4zODYgNi4x"+ "NzUgNy45MDYgMTIuMzc2IDcuOTA2IDcuMDMgMCAxNC4zNjQtNC4yNyAyMi4wMzMtMTMuMDYydjExLjU5NGgxOS4yNVY5N"+ "i4zNDRoLTE5LjI1djgxLjI4Yy00LjI3IDYuMDM1LTguMzM2IDktMTIuMTg4IDktMi41ODYgMC00LjA3NS0xLjUxNi00Lj"+ "UtNC41LS4yMzItLjYzLS4yNS0yLjk4NC0uMjUtNy41di03OC4yOGgtMTkuMjJ6bS00NC4zMSAxNi4wNjNjNi4yMTIgMCA"+ "5LjE4NiA0LjkxMyA5LjE4NiAxNC43NXY0NC43NWMwIDkuODQtMi45NzQgMTQuNzItOS4xODYgMTQuNzJzLTkuMTg4LTQu"+ "ODgtOS4xODgtMTQuNzJ2LTQ0Ljc1YzAtOS44MzcgMi45NzYtMTQuNzUgOS4xODgtMTQuNzV6bS03LjcyIDEwNy42ODhjL"+ "TM3LjAxNSAwLTc0LjE2NC4yNzMtMTEwLjg3NSA0LjM3NS0xNi41MTggMS44NDUtMzAuMjM0IDE0LjI1LTM0LjA5NCAzMS"+ "4wMy01LjQ5IDIzLjg5Ny01LjU2MiA0OS45Ni01LjU2MiA3NC41NjN2MS43OGMuMDAyIDI0LjA4NS4xNCA0OS40NTMgNS4"+ "1IDcyLjc4MiAzLjg2IDE2Ljc4IDE3LjYwNyAyOS4xODYgMzQuMTI1IDMxLjAzIDM2Ljc1MiA0LjExIDczLjkxIDQuMzQ1"+ "IDExMC45NjggNC4zNDVIMjU3YzM3LjA1NyAwIDc0LjIxNy0uMjM2IDExMC45Ny00LjM0NCAxNi41MTctMS44NDUgMzAuM"+ "jY0LTE0LjI1MiAzNC4xMjQtMzEuMDMgNS40MTMtMjMuNTYgNS40OTgtNDkuMjM1IDUuNS03My41MzJ2LTEuMDNjMC0yNC"+ "42MDQuMDU0LTUwLjY2Ny01LjQzOC03NC41NjQtMy44NTgtMTYuNzgtMTcuNTc3LTI5LjE4NS0zNC4wOTQtMzEuMDMtMzY"+ "uNzEzLTQuMTAyLTczLjg1OC00LjM3Ni0xMTAuODc1LTQuMzc2SDI0Mi42MjV6bS0xMjcgMzkuMjVoNjYuNXYxOS44NzVI"+ "MTU5LjI4VjQwMC41NmgtMjEuMjE4VjI3OS4yMmgtMjIuNDM3di0xOS44NzZ6bTE0MC41OTQgMGgxOS4wNnY0Ni4xMjVjN"+ "i4xNTctNy41NzggMTIuNzA4LTExLjQwOCAxOS43Mi0xMS40MDggNy41OSAwIDEyLjY2IDMuOTk1IDE1LjIyIDExLjg3NS"+ "AxLjI2MiA0LjIzNSAxLjkzNiAxMS4yIDEuOTM2IDIxLjE1N3Y0MS44NzVjMCA5LjczOC0uNjc1IDE2Ljc1Ni0xLjkzNyA"+ "yMS4yMTdDMzA3LjY2IDM5OC4wMSAzMDIuNTkgNDAyIDI5NSA0MDJjLTYuNzc4IDAtMTMuMzUtMy43NDMtMTkuNzItMTEu"+ "NjI1djEwLjE4OGgtMTkuMDZ2LTE0MS4yMnptOTkuNDY3IDM0LjcyYzkuNTY2LS4wMDIgMTcuMTkyIDMuNTc3IDIyLjUzM"+ "iAxMC43OCAzLjk5MiA1LjMyIDUuODc0IDEzLjUzNiA1Ljg3NCAyNC43OHYyMS43ODJIMzQ1Ljk3djE4LjY1NmMwIDkuNz"+ "QgMy4xNjcgMTQuNjI1IDkuNzE3IDE0LjYyNSA0LjcgMCA3LjQ3NC0yLjU1NCA4LjU2My03LjY1Ni4xNzMtMS4wMzguNDA"+ "2LTUuMjkuNDA2LTEyLjkzNmgxOS40Mzh2Mi44MTJjMCA2LjEzMy0uMjI3IDEwLjM4LS40MDYgMTIuMjgtLjYzNiA0LjIz"+ "Ni0yLjExNSA4LjAzNi00LjQzOCAxMS40MDgtNS4yNyA3LjY0LTEzLjEwNSAxMS40MDYtMjMuMDYzIDExLjQwNi05Ljk3M"+ "yAwLTE3LjU4LTMuNTkzLTIzLjA5My0xMC43OC00LjA1Mi01LjI2Ny02LjA5NC0xMy41NC02LjA5NC0yNC43MnYtMzYuOD"+ "c1YzAtMTEuMjQ1IDEuODI2LTE5LjQ2IDUuODc1LTI0Ljc4IDUuNTE1LTcuMjA0IDEzLjA4Mi0xMC43ODMgMjIuODEzLTE"+ "wLjc4M3ptLTE3MC43OCAxLjI4aDE5LjAzdjc3LjQ3YzAgNC40NjcuMDEgNi43NzUuMTg4IDcuNDA1LjQ2NCAyLjk1MiAx"+ "LjkyIDQuNDM2IDQuNDcgNC40MzYgMy44MjUgMCA3LjgzLTIuOTAyIDEyLjA2LTguODc1di04MC40MzZoMTkuMDY0djEwN"+ "S4yMmwtMTkuMDY0LS4wMDJ2LTExLjQ2OGMtNy41OCA4LjY5NC0xNC43NzIgMTIuOTA2LTIxLjc4IDEyLjkwNi02LjE0My"+ "AwLTEwLjQwNi0yLjQ4NS0xMi4zMTQtNy44MTMtMS4wMzgtMy4xODctMS42NTYtOC4xOTgtMS42NTYtMTUuNjI1di04My4"+ "yMTh6bTk5Ljg3NCAxNS44NzVjLTMuMTMzIDAtNi4zMDggMS40NzgtOS41IDQuNjI0djY0LjEyNWMzLjE5MiAzLjE4NiA2"+ "LjM2NiA0LjY4NiA5LjUgNC42ODYgNS41IDAgOC4zMTQtNC42NSA4LjMxNC0xNC4xNTZ2LTQ0LjkzOGMwLTkuNTA2LTIuO"+ "DEzLTE0LjM0My04LjMxMy0xNC4zNDN6bTcwLjc4MyAwYy02LjM3OCAwLTkuNTk0IDQuODYtOS41OTQgMTQuNTkydjkuNz"+ "JoMTkuMDZ2LTkuNzJjLjAwMi05LjczMy0zLjE1NS0xNC41OTMtOS40NjctMTQuNTkzeiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==", isPartOfOBJECT = function (el) { var parent; if (!el) return parent; while ( (parent=el.parentNode) ) { if ( parent.nodeName === "BODY" || parent.nodeName === "HTML" ) { parent = false; break; } else if (parent.nodeName === "OBJECT") { break; } el = parent; } return parent; }, removeBackgroundRules = (function () { var patt = /^(?:[\-_][a-zA-Z0-9]+[\-_])?background(?:$|\-)/; return function (a) { // Remove all -x-|background|- return !patt.test(a[0]); }; }()), validateStyleArray = function (a) { a = Array.isArray(a) && a[0] && a[1] ? a : null; return !!a; }, sortMultiArray = function (a, b) { // Sort so vendor prefixes goes at the top // www.w3.org/TR/CSS2/syndata.html - "An initial dash or underscore [...]" return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; }, copyAllStyles = function (element, psuedoSelector, property) { // stackoverflow.com/questions/2558426 var styles = [], cs; // The DOM Level 2 CSS way cs = getComputedStyle(element, psuedoSelector); if (cs.length !== 0) { for (var i = 0, len = cs.length; i < len; i+=1) { if (!property || (property && cs.item(i) === property)) { styles.push([cs.item(i), cs.getPropertyValue(cs.item(i))]); if (property) break; } } } else { // Opera workaround. Opera doesn't support `item`/`length` on CSSStyleDeclaration. for (var k in cs) { if (cs.hasOwnProperty(k)) { if (!property || (property && k === property)) { styles.push([k, cs[k]]); } if (property) break; } } } // Return single rule if (property) return styles[0]; // Remove falsies styles = styles.filter(validateStyleArray); // Link has its own background, leave psuedo-selectors as they are though if (!psuedoSelector) styles = styles.filter(removeBackgroundRules); styles.sort(sortMultiArray); return styles; }, getDim = (function () { var numPatt = /^\d+$/; return function (dim, el, y) { var clientDim = "client"+(y[0].toUpperCase())+(y.substr(1)); dim = parseInt(dim, 10) === 0 ? (el.getAttribute(y) || el[clientDim]) : "auto"; return (numPatt.test(dim+"")) ? dim+"px" : dim+""; }; }()), makeStyles = function (o, type, psIds) { o[type] = {}; if (psIds) { // (Object) <A> Psuedo elements :before { rule: 1; } :after { rule: 1; } o[type].styleTagContent = "a[data-cyetoil='loaded"+psIds[0]+"'][data-cyetoil-uid='"+psIds[1]+"']:"+type+" {\n"; o[type].styleTagContent += (copyAllStyles(o.node, ":"+type).map(function (a) { return a ? a.join(":")+"!important;\n" : ""; }).join("")+"\n}\n"); o[type].styleTag = document.createElement("STYLE"); o[type].styleTag.textContent = o[type].styleTagContent; o[type].styleTag.dataset.cyetoilStyleFor = type+psIds[1]; document.querySelector("head").appendChild(o[type].styleTag); } else { // (Object) <A> styles o[type].styles = (copyAllStyles(o.node, null).concat([ [ "background", "url('https://i.ytimg.com/vi/"+o.videoId+"/0.jpg') no-repeat scroll 50% 50% / 133% auto transparent" // 320x180 widescreen version //"url('https://img.youtube.com/vi/"+o.videoId+"/mqdefault.jpg') no-repeat scroll 50% 50% / 100% 100% transparent" ] ]).map(function (a) { // Must be able to set an absolute positioned SPAN inside it if (a[0] === "position" && a[1] !== "fixed" && a[1] !== "absolute") a[1] = "relative"; // It's an inline <A> tag, so it must be block-ish if (a[0] === "display" && a[1] === "inline") a[1] = "inline-block"; // Force cursor back to pointer if (a[0] === "cursor") a[1] = "pointer"; // <A> must have a set dimension if (a[0] === "width") { if (a[1] === "auto" || a[1] === "0px") a[1] = getDim(a[1], o.node, "width"); // Force a minimum width - usually the object hasn't loaded yet, hence the 200ms delays if (a[1] === "auto" || a[1] === "0px") a[1] = "320px"; o.forceObjectWidth = a[1]; } if (a[0] === "height") { if (a[1] === "auto" || a[1] === "0px") a[1] = getDim(a[1], o.node, "height"); a[1] = ( (a[1] === "auto" || a[1] === "0px" ? (o.forceObjectWidth !== "auto" && o.forceObjectWidth !== "0px" ? // forces a 16:9 resolution for objects with forced dimensions Math.ceil((parseInt(o.forceObjectWidth, 10)/16)*9) : "180")+"px" : a[1]) ); } return a ? a.join(":")+"!important;" : ""; }).join("")); } return o; }, makeImageAnchor = (function () { var linkCss = [ "margin:0", "padding:0", "position:absolute", "top:0", "bottom:0", "left:0", "right:0" ], bannerCss = [ "position:absolute", "bottom:0", "left:0", "height:30px", "width:100%", "box-sizing:border-box", "padding:8px 0 0 12px", "text-shadow:0 1px 0 #000000", "font:13px/1 sans-serif", "color:rgb(255,255,255)", "background-color:rgba(0,0,0,0.75)", "overflow:hidden", "white-space:nowrap", "text-overflow:ellipsis", "border-bottom:1px solid #000000" ], spanCss = [ "margin:0", "padding:0", "opacity:0.85", "position:absolute", "top:0", "bottom:0", "left:0", "right:0" ], makeinfoBar = function (first, middle, last, target) { var firstEl = first ? document.createElement("EM") : null, middleEl = document.createTextNode(middle), lastEl = last ? document.createElement("EM") : null; if (firstEl) { firstEl.textContent = first; firstEl.style.setProperty("font-style", "normal", "important"); firstEl.style.setProperty("color", "rgba(255,255,255,0.8)", "important"); target.appendChild(firstEl); } target.appendChild(middleEl); if (lastEl) { lastEl.textContent = last; lastEl.style.setProperty("font-style", "normal", "important"); lastEl.style.setProperty("color", "rgba(255,255,255,0.8)", "important"); target.appendChild(lastEl); } return target; }; return function (o, isIframe) { var url = ytWatchBaseHref+o.videoId, link = document.createElement("A"), shield = document.createElement("SPAN"), infoBar; link.href = url; link.title = (o.atitle ? o.atitle+" - "+o.videoId : url); link.setAttribute( "onmouseup", "this.querySelector('span').style.setProperty('background-color','rgba(0,0,0,0.6)','important');"+ "this.querySelector('span').style.setProperty('opacity','1','important');"+ "this.querySelector('i').style.setProperty('background-color','rgb(0,0,0)','important');" ); if (isIframe) { infoBar = makeinfoBar( (o.stats.time ? o.stats.time+" " : ""), link.title, (o.stats.views ? " - "+o.stats.views : ""), document.createElement("I") ); link.title = infoBar.textContent; link.target = iframesLinkTarget; infoBar.setAttribute("style", bannerCss.concat([""]).join("!important;")); shield.setAttribute("style", spanCss.concat([ "background:url('"+youtubeIcon+"') no-repeat scroll 50% 50% / 16% auto rgba(0,0,0,0.08)", "bottom:25px", "" ]).join("!important;")); } else { link.target = nonIframesLinkTarget; shield.setAttribute("style", spanCss.concat([ "background:url('"+youtubeIcon+"') no-repeat scroll 50% 50% / 16% auto rgba(0,0,0,0.08)", "bottom:0", "" ]).join("!important;")); } if (isIframe) { link.setAttribute("style", linkCss.concat([ "background:url('https://i.ytimg.com/vi/"+o.videoId +"/0.jpg') no-repeat scroll 50% 50% / 133% auto transparent", "" ]).join("!important;")); link.appendChild(shield); link.appendChild(infoBar); } else { link.setAttribute("style", o.main.styles); shield.innerHTML = " "; link.appendChild(shield); } return link; }; }()), linkClickHandler = function (event) { var link = event.currentTarget; if (link.nodeName === "A") { link = link.querySelector("span"); } link.style.setProperty("background-color", "rgba(0,0,0,0.6)", "important"); }, init = function (dynamicNodes, done) { var nowNum = Date.now(), risky = !dynamicNodes ? document.querySelectorAll(riskyTags.join(", ")) : dynamicNodes, badElements = [], selector, paramParent, videoLink, riskyNode, riskyAttributes, fauxLink, videoId, linkHolder; if (risky.length === 0) return; // Loop bad elements for (var j = 0, jLen = risky.length; j < jLen; j+=1) { riskyAttributes = risky[j].attributes; // Loop each elements attributes for (var k = 0, kLen = riskyAttributes.length; k < kLen; k+=1) { paramParent = null; // http://alistapart.com/article/flashsatay // EMBED is part of object, skip this EMBED entirely if (risky[j].nodeName === "EMBED" && isPartOfOBJECT(risky[j])) { break; } if (risky[j].nodeName === "PARAM") { // Save parent OBJECT for later use as replace & css target paramParent = isPartOfOBJECT(risky[j]); // Break if PARAM is not part of an OBJECT (invalid html) if (!paramParent) break; } riskyNode = riskyAttributes[k].value; if (!fauxLink) fauxLink = document.createElement("A"); fauxLink.href = riskyNode; // Get id if ((videoId=(fauxLink.pathname+fauxLink.search).match(youtubeIdPatt)) === null) continue; // Check domain if (fauxLink.hostname.indexOf("youtube.com") >= 0 || fauxLink.hostname.indexOf("youtube-nocookie.com") >= 0) { badElements.push({ "node": paramParent || risky[j], "videoId": videoId[1] }); break; } } } if (badElements.length === 0) return; // Create hidden placeholder linkHolder = document.createElement("DIV"); linkHolder.style.setProperty("display", "none", "important"); linkHolder.setAttribute("hidden", true); linkHolder.dataset.cyetoilPlaceholder = nowNum+""; badElements.forEach(function (el) { var content; // This prevents collisions, and PARAMs inside OBJECTs from duplicating if (loadedPatt.test(el.node.dataset.cyetoil+"")) return; replCounter += 1; // Copy all styles that the original video element had el = makeStyles(el, "main"); // Skip pseudo styles if (not or) content is <none> if ((content=copyAllStyles(el.node, ":before", "content")) && content[1] !== "none") { el = makeStyles(el, "before", [nowNum, replCounter]); // console.log(content, el.before.styleTagContent); } if ((content=copyAllStyles(el.node, ":after", "content")) && content[1] !== "none") { el = makeStyles(el, "after", [nowNum, replCounter]); } videoLink = makeImageAnchor(el); el.node.setAttribute("data-cyetoil", "loaded"+nowNum); videoLink.setAttribute("data-cyetoil", "loaded"+nowNum); el.node.setAttribute("data-cyetoil-uid", replCounter+"org"); videoLink.setAttribute("data-cyetoil-uid", replCounter+""); videoLink.onmouseup = linkClickHandler; // Dump in placeholder linkHolder.appendChild(videoLink); }); // Replace after collecting to preserve css styles // Reason: Example: Removing any element causes rules such as :nth-of-type(x) to change document.body.appendChild(linkHolder); selector = "[data-cyetoil='loaded"+nowNum+"'][data-cyetoil-uid]"; makeArray(linkHolder.querySelectorAll(selector)).forEach(function (node) { var moved = node.parentNode.removeChild(node), // Remove AND copy it old = document.querySelector("[data-cyetoil-uid='"+(moved.dataset.cyetoilUid)+"org']"); old.parentNode.replaceChild(moved, old); }); // Clean up linkHolder.parentNode.removeChild(linkHolder); if (typeof done === "function") { return done(); } }; // Start if (youtubeDomainPatt.test(document.location.hostname)) { if (top.window != self.window // Are we inside a Youtube IFRAME embed? && (insideIframeId=(document.location.pathname+document.location.search).match(youtubeIdPatt)) !== null) { // 2015-05-05 Make sure we're not an iframe on youtube.com, it _can_ happen try { if (top.window.document.domain === "www.youtube.com") return; } catch (err) {} (function () { var iframeFlashvars = "", iframeStats, pageTitle = document.title, insideIframeLink, iframeHtml, formatVideoLength = function (n, isMs) { n = Number(n); if (isMs) { n = (n/1000).toFixed(0); } var sForm = (n%60), hours = "", minutes = ((n-sForm)/60), seconds = sForm < 10 ? "0"+sForm : sForm; if (minutes > 60) { hours = ((minutes-(minutes%60))/60)+"."; minutes = (minutes%60); if (minutes < 10) { minutes = "0"+minutes; } } return hours+minutes+":"+seconds; }; makeArray(document.querySelectorAll("div")).forEach(function (node) { iframeFlashvars += (node.outerHTML || ""); }); if (!iframeFlashvars || iframeFlashvars.indexOf("flashvars=") === -1) { // Probably HTML5 player iframeFlashvars = document.body.textContent; iframeStats = { "views": iframeFlashvars.match(/view_count\D*?(\d+)/), "time": iframeFlashvars.match(/length_seconds\D*?(\d+)/) }; } else { // Probably not the HTML5 Player iframeStats = { "views": iframeFlashvars.match(/flashvars=.+?view_count=(\d+)/), "time": iframeFlashvars.match(/flashvars=.+?length_seconds=(\d+)/) }; } if (iframeStats.views) { iframeStats.views = (iframeStats.views[1] .replace(/^(\d+)(\d{3})(\d{3})$/, "$1.$2,$3") .replace(/^(\d+)(\d{3})$/, "$1,$2"))+" views"; } if (iframeStats.time) { iframeStats.time = formatVideoLength(iframeStats.time[1]); } if (!iframeStats.time && !iframeStats.views && document.querySelector("#player-unavailable")) { // Private or removed video pageTitle = "Unavailable / Private / Removed - YouTube"; } insideIframeLink = makeImageAnchor({ "stats": iframeStats, "videoId": insideIframeId[1], "atitle": pageTitle.trim() /*.replace(/(?:\s|-)+Youtube$/i, "")*/ }, true); iframeHtml = getIframeTmpl(pageTitle, insideIframeLink.outerHTML).join(""); // 2015-02-14 00:35 Removed base64 encoding which I used to safeguard the uri, but // a bug in firefox makes it break for non ascii characters // https://bugzilla.mozilla.org/show_bug.cgi?id=213047 document.location.replace("data:text/html;utf8,"+encodeURIComponent(iframeHtml)); }()); } } else { window.addEventListener("load", function () { // Continue looking for OBJECTs and EMBEDs with Youtube videos MutationObserver = window.MutationObserver || window.WebKitMutationObserver; // https://developer.mozilla.org/en/docs/Web/API/MutationObserver // https://dev.opera.com/articles/mutation-observers-tutorial/ observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { var nodes = []; if (!mutation.addedNodes || mutation.addedNodes.length === 0) return; makeArray(mutation.addedNodes).forEach(function (node) { if (node.nodeName && riskyTags.indexOf(node.nodeName.toLowerCase()) !== -1) { nodes.push(node); makeArray(node.querySelectorAll("*")).forEach(function (child) { // Add all nodes inside the new one nodes.push(child); }); setTimeout(function () { // Allow OBJECTs and EMBEDs to reflow the document init(nodes); }, 200); } }); }); }); init(null, function () { observer.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false }); }); }); } }());