您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Lazy load embedded videos from Youtube/Dailymotion/Vimeo/Rutube/Twitch/Ustream/Coub/Vine/Facebook
当前为
// ==UserScript== // @name Lazy Embedded Video // @namespace [email protected] // @description Lazy load embedded videos from Youtube/Dailymotion/Vimeo/Rutube/Twitch/Ustream/Coub/Vine/Facebook // @version 2.7 // @include * // @resource playIcon https://i.imgur.com/1aybyWN.png // @grant GM_getResourceURL // @run-at document-start // ==/UserScript== (function() { try { if(/^([^.]+\.)?(youtube|dailymotion|vimeo|rutube|twitch|ustream|coub|vine|facebook)\.[^.]+$/.test(top.location.hostname)) return; } catch(e) {} var wnd = typeof(unsafeWindow) != "undefined" ? unsafeWindow : window; var getResourceURL = typeof(GM_getResourceURL) != "undefined" ? GM_getResourceURL : function(name) { switch(name) { case "playIcon" : return "//i.imgur.com/1aybyWN.png"; } }; var CSP = -1; var testCSP = function() { if(CSP == -1) { var script = document.createElement("SCRIPT"); script.innerHTML = "CSP_AllowInlineScript = true;"; document.head.appendChild(script); document.head.removeChild(script); CSP = wnd.CSP_AllowInlineScript ? 1 : 0; } return CSP; }; var html, a; var createHtml = function(url, iframe, api, background_img) { /(.*\/\/(?:[^.\/]+\.)?([^.\/]+)\.[^.\/]+)\//i.test(url); var provider_url = RegExp.$1, provider_name = RegExp.$2, data_convert = "", extra_script = "", button_hsb = []; if(api.includes("yahooapis")) data_convert += "data = data.query.results.json;"; switch(provider_name) { case "youtube" : button_hsb.push( 0, 100, 100); data_convert += "delete data.thumbnail_url;"; extra_script += "var img = new Image();"+ "img.onload = function() {"+ "if(this.naturalWidth > 120) {"+ "document.body.style.backgroundImage = 'url('+this.src+')';"+ "if(this.src.includes('hqdefault_live'))"+ "this.src = this.src.replace('hqdefault', 'maxresdefault');"+ "} else if(this.src.includes('maxresdefault')) {"+ "this.src = this.src.replace('maxresdefault', 'sddefault');"+ "} else if(this.src.includes('hqdefault_live')) {"+ "this.src = this.src.replace('hqdefault_live', 'maxresdefault');"+ "}"+ "};"+ "img.src = '"+background_img.match(/\/(.+)\//)[0]+"hqdefault_live.jpg';"; break; case "dailymotion" : button_hsb.push( 60, 30, 300); data_convert += "var img = new Image();"+ "img.onload = function() { document.body.style.backgroundImage = 'url('+this.src+')'; };"+ "img.src = removeProtocol(data.thumbnail_url.replace(/\\/x240[^.]+/i, ''));"+ "delete data.thumbnail_url;"; break; case "vimeo" : button_hsb.push(220, 50, 220); data_convert += "data.thumbnail_url = data.thumbnail_url.replace(/_\\d+/i, '');"; break; case "rutube" : button_hsb.push( 0, 0, 100); data_convert += "data.thumbnail_url = data.thumbnail_url.replace(/\\?.+/i, '');"; break; case "twitch" : button_hsb.push(270, 50, 100); if(background_img) { // channel live data_convert += "data.title = data.status || 'Untitled Broadcast';"+ "data.author_url = '"+provider_url+"/'+data.name+'/profile';"+ "data.author_name = data.display_name;"+ "data.duration = data.game && 'playing <a target=_blank href=\""+provider_url+ "/directory/game/'+data.game+'\">'+data.game+'</b>';"+ "offline_image = data.video_banner;"; extra_script += "function jsonpCallback2(data) {"+ "if(data.streams.length != 0) return;"+ "document.body.style.backgroundImage = 'url('+removeProtocol(offline_image)+')';"+ "document.getElementById('duration').textContent = 'offline';"+ "}"+ "</script>"+ "<script defer src='https://api.twitch.tv/kraken/streams?channel="+url.match(/[^\/]+$/)[0]+"&callback=jsonpCallback2'>"; } else { // video recorded data_convert += "data.thumbnail_url = data.preview.replace(/\\d+x\\d+/i, '0x0');"+ "data.author_url = '"+provider_url+"/'+data.channel.name+'/profile';"+ "data.author_name = data.channel.display_name;"+ "data.duration = data.length;"; } break; case "ustream" : button_hsb.push( 40, 50, 230); if(background_img) // channel live data_convert += "delete data.thumbnail_url;"; break; case "coub" : button_hsb.push(240, 150, 100); data_convert += "data.author_url = data.channel_url;"; break; case "vine" : button_hsb.push(170, 150, 150); break; case "facebook" : button_hsb.push( 0, 0, 300); data_convert += "if(/<a.*?>(.+)<\\/a><p>/i.test(data.html))"+ "data.title = RegExp.$1;"; break; } if(!html) html = [ "<!doctype html>"+ "<html>"+ "<head>"+ "<title>Lazy Embedded Video</title>"+ "<script defer src='", api, "&callback=jsonpCallback'></script>"+ "<script>"+ "function removeProtocol(url) { return url.replace(/^[a-z]+:/i, ''); };"+ "function jsonpCallback(data) {", data_convert, "if(data.thumbnail_url) document.body.style.backgroundImage = 'url('+removeProtocol(data.thumbnail_url)+')';"+ "if(data.url) document.getElementById('title').href = removeProtocol(data.url);"+ "if(data.title) document.getElementById('title').textContent = "+ "document.getElementById('title').title = data.title;"+ "if(data.author_url) document.getElementById('author').href = removeProtocol(data.author_url);"+ "if(data.author_name) document.getElementById('author').textContent = data.author_name;"+ "if(data.duration) {"+ "if(Number(data.duration))"+ "document.getElementById('duration').textContent = new Date(data.duration*1000).toISOString().substr(11,8);"+ "else document.getElementById('duration').innerHTML = data.duration;"+ "}"+ "}", extra_script, "</script>"+ "<style>"+ "html { height:100%; }"+ "body { margin:0; height:100%; color:white; font:14px sans-serif;"+ "background:black ", background_img, " center/100% no-repeat; }"+ "a { color:inherit; font-weight:bold; text-decoration:none; }"+ "a:hover { text-decoration:underline; }"+ "ul { margin:0; padding:0; list-style:none; }"+ "#infobar { position:absolute; top:0px; width:100%; padding:8px 16px;"+ "box-sizing:border-box; background:rgba(0,0,0,0.5); word-wrap:break-word; }"+ "#infobar_right { float:right; margin-left:16px; text-align:right; text-transform:capitalize; }"+ "#button { height:100%; cursor:pointer; background-position:0px 50%; }"+ "#button:hover { background-position:-70px 50%;"+ (navigator.userAgent.includes("Firefox") ? "" : "-webkit-")+"filter:"+ "hue-rotate(", button_hsb[0], "deg) saturate(", button_hsb[1], "%) brightness(", button_hsb[2], "%);}"+ "#button > div { width:70px; height:100%; margin:auto; background-repeat:no-repeat; background-position:inherit; "+ "background-image:url("+getResourceURL("playIcon")+"); }"+ "#titleBlock { overflow:hidden; max-height:34px; }"+ "</style>"+ "</head>"+ "<body>"+ "<div id=button onclick='location.replace(\"", iframe, "\");'><div></div></div>"+ "<div id=infobar>"+ "<ul id=infobar_right>"+ "<li><a id=author target=_blank></a></li>"+ "<li><a id=provider target=_blank href='", provider_url, "'>", provider_name, "</a></li>"+ "</ul>"+ "<ul>"+ "<li id=titleBlock><a id=title target=_blank href='", url, "'>", url, "</a></li>"+ "<li id=duration></li>"+ "</ul>"+ "</div>"+ "</body>"+ "</html>" ]; html[ 1] = api; html[ 3] = data_convert; html[ 5] = extra_script; html[ 7] = background_img; html[ 9] = button_hsb[0]; html[11] = button_hsb[1]; html[13] = button_hsb[2]; html[15] = iframe; html[17] = provider_url; html[19] = provider_name; html[21] = url; html[23] = url; }; var createOembed = function(api, url) { return api+encodeURIComponent(url); }; var createNOembed = function(api, url) { return createOembed("//noembed.com/embed?url=", url); }; var createYOembed = function(api, url) { return createOembed("//query.yahooapis.com/v1/public/yql?format=json&q=", 'SELECT * FROM json WHERE url="'+createOembed(location.protocol+api,url)+'"'); }; var createLazyVideo = function(elem) { if(elem.tagName == "IFRAME" && elem.srcdoc) return true; var id, args, url = elem.src || elem.data || elem.dataset.src; if(!url) return true; if(!a) a = document.createElement("A"); a.href = url; /([^.]+)\.[^.]+$/i.test(a.hostname); switch(RegExp.$1) { case "youtube" : if(/\/(?:v|embed)\/([^&]*)/i.test(a.pathname)) id = RegExp.$1 || (/[?&]v=([^&]+)/i.test(a.search) && RegExp.$1); if(!id || !testCSP()) return !id; args = "?autoplay=1"; if(/[?&](list=[^&]+)/i.test(a.search)) args += "&"+RegExp.$1; if(/[?&](start=[^&]+)/i.test(a.search)) args += "&"+RegExp.$1; createHtml(url = "//www.youtube.com/watch"+args+"&v="+id, "//www.youtube.com/embed/"+id+args, createNOembed("//www.youtube.com/oembed?format=json&url=", location.protocol+url), "url(//i.ytimg.com/vi/"+id+"/hqdefault.jpg)" ); break; case "dailymotion" : if(/\/(?:swf|embed)\/video\/([^&_]+)/i.test(a.pathname)) id = RegExp.$1; if(!id || !testCSP()) return !id; args = "?autoplay=1"; if(/[?&](mute=[^&]+)/i.test(a.search)) args += "&"+RegExp.$1; if(/[?&](start=[^&]+)/i.test(a.search)) args += "&"+RegExp.$1; createHtml(url = "//www.dailymotion.com/video/"+id+args, "//www.dailymotion.com/embed/video/"+id+args, createOembed("//www.dailymotion.com/services/oembed?format=json&url=", location.protocol+url), "url(//www.dailymotion.com/thumbnail/video/"+id+")" ); break; case "vimeo" : if(/\/(?:moogaloop\.swf|video\/)([^&]*)/i.test(a.pathname)) id = RegExp.$1 || (/[?&]clip_id=([^&]+)/i.test(a.search) && RegExp.$1); if(!id || !testCSP()) return !id; args = "?autoplay=1"; if(/[?&](loop=[^&]+)/i.test(a.search)) args += "&"+RegExp.$1; if(/(\#t=[\dhms]+)/i.test(a.hash)) args += RegExp.$1; createHtml(url = "//vimeo.com/"+id+args, "//player.vimeo.com/video/"+id+args, createOembed("//vimeo.com/api/oembed.json?url=", url) ); break; case "rutube" : if(/\/play\/embed\/([^&.\/]+)/i.test(a.pathname)) id = RegExp.$1; if(!id || !testCSP()) return !id; args = "?autoStart=1"; if(/[?&](bmstart=[^&]+)/i.test(a.search)) args += "&"+RegExp.$1; createHtml(url = "//rutube.ru/"+(isNaN(id) ? "video/"+id+"/" : "tracks/"+id+".html/")+args, "//rutube.ru/play/embed/"+id+args, createOembed("//rutube.ru/api/oembed/?format=jsonp&url=", url) ); break; case "twitch" : if(/[?&](channel|video)=([^&]+)/i.test(a.search)) {args = RegExp.$1; id = RegExp.$2;} else if(/\/(.+)\/embed/i.test(a.pathname)) {args = "channel"; id = RegExp.$1;} if(!id || !testCSP()) return !id; createHtml(url = "//www.twitch.tv/"+(args=="video" ? id.replace("v","c/v/") : id), "//player.twitch.tv/?autoplay=true&"+args+"="+id, "https://api.twitch.tv/kraken/"+args+"s/"+id+"?", args=="channel" ? "url(//static-cdn.jtvnw.net/previews-ttv/live_user_"+id+"-0x0.jpg)" : null ); break; case "ustream" : if(/(?:\/embed)?\/(channel\/|recorded\/)?([^&]+)/i.test(a.pathname)) {args = RegExp.$1 || "channel/"; id = RegExp.$2;} if(!id || !testCSP()) return !id; createHtml(url = "//www.ustream.tv/"+args+id, "//www.ustream.tv/embed/"+(args=="channel/" ? "" : args)+id+"?html5ui=1&autoplay=1", createYOembed("//www.ustream.tv/oembed?format=json&url=", url), args=="channel/" && !isNaN(id) ? "url(//static-cdn1.ustream.tv/i/channel/live/1_"+id+",640x360,b:0.jpg)" : null ); break; case "coub" : if(/\/embed\/([^&]+)/i.test(a.pathname)) id = RegExp.$1; if(!id || !testCSP()) return !id; createHtml(url = "//coub.com/view/"+id, "//coub.com/embed/"+id+"?startWithHD=true&autostart=true", createYOembed("//coub.com/api/oembed.json?url=", url) ); break; case "vine" : if(/\/v\/([^&]+)\/embed\/([^&]+)/i.test(a.pathname)) {args = RegExp.$2; id = RegExp.$1;} if(!id || !testCSP()) return !id; createHtml(url = "//vine.co/v/"+id, "//vine.co/v/"+id+"/embed/"+args+"?audio=1", createOembed("//vine.co/oembed.json?url=", url) ); break; case "facebook" : if(a.pathname.endsWith("/plugins/video.php") && /[?&]href=([^&]+)/i.test(a.search)) { url = decodeURIComponent(RegExp.$1).replace(/^[a-z]+:/i, ''); if(/\/videos.*?\/(\d+)/i.test(url)) id = RegExp.$1; } if(!id || !testCSP()) return !id; createHtml( url, "//www.facebook.com/plugins/video.php?autoplay=1&href="+encodeURIComponent(location.protocol+url), createOembed("//www.facebook.com/plugins/video/oembed.json/?url=", location.protocol+url), "url(//graph.facebook.com/"+id+"/picture)" ); break; default : return true; } if(elem.tagName != "IFRAME") { var iframe = document.createElement("IFRAME"); iframe.id = elem.id; iframe.className = elem.className; iframe.style.cssText = elem.style.cssText; if(!iframe.style.width && elem.width ) iframe.style.width = elem.width+"px"; if(!iframe.style.height && elem.height) iframe.style.height = elem.height+"px"; if(elem.parentNode.tagName == "OBJECT") { elem = elem.parentNode; iframe.style.cssText = elem.style.cssText + iframe.style.cssText; if(!iframe.style.width && elem.width ) iframe.style.width = elem.width+"px"; if(!iframe.style.height && elem.height) iframe.style.height = elem.height+"px"; } if(!iframe.style.borderWidth) iframe.style.borderWidth = (elem.border||0)+"px"; switch(elem.align) { case "left" : case "right" : if(!iframe.style.float) iframe.style.float = elem.align; break; case "top" : case "middle" : case "bottom" : if(!iframe.style.verticalAlign) iframe.style.verticalAlign = elem.align; break; } elem.parentNode.replaceChild(iframe, elem); elem = iframe; } elem.allowFullscreen = true; elem.srcdoc = html.join(""); return true; }; var update = function() { // convert NodeList to Array because for some reason sometimes I wasn't able to read src when iterating directly through NodeList var nodes = ["IFRAME", "EMBED", "OBJECT"].reduce(function(sum, value) { return sum.concat([].slice.call(document.getElementsByTagName(value))); }, frameElement ? [frameElement] : []); for(var i = 0; i < nodes.length; i++) if(!createLazyVideo(nodes[i])) return; if(document.readyState == "loading") requestAnimationFrame(update); }; update(); })();