在您安装前,Greasy Fork 希望您知道此脚本声明其包含了一些负面功能。这些功能也许会使脚本作者获利,而不能给您带来任何直接的金钱收益。
此脚本会在您访问的网站中插入广告。
Greasy Fork is available in English.
功能包含:1、自动嗅探页面上的视频、音频资源,列出链接,并提供播放、复制和下载功能(提供 mp3、mp4 和 m3u8 资源下载);2、录屏;3、解除页面复制限制。
// ==UserScript== // @name 媒体资源嗅探及下载(支持下载m3u8和mp4视频和音频) // @namespace http://tampermonkey.net/ // @version 1.985 // @description 功能包含:1、自动嗅探页面上的视频、音频资源,列出链接,并提供播放、复制和下载功能(提供 mp3、mp4 和 m3u8 资源下载);2、录屏;3、解除页面复制限制。 // @author geigei717 // @license Copyright geigei717 // @antifeature ads // @match https://*/* // @match http://*/* // @icon https://greasyfork.s3.us-east-2.amazonaws.com/fc67t00gsk98w7pbhs97xr94g1hl // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/dplayer/1.27.1/DPlayer.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/layui/2.9.14/layui.js // @require https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.13/hls.js // @require https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.6.2/flv.js // @require https://update.greasyfork.icu/scripts/433051/Trusted-Types%20Helper.user.js // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js // @resource LayuiCss https://cdnjs.cloudflare.com/ajax/libs/layui/2.9.14/css/layui.css // @resource qbMediaRecorderJS https://quickblox.github.io/javascript-media-recorder/qbMediaRecorder.js // @grant unsafeWindow // @grant GM_download // @grant GM_setClipboard // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_addElement // @grant GM_getResourceText // @grant GM_webRequest // @connect * // @supportURL 【Greasy Fork 脚本技术交流】:http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=IkMlupLSzK9E2MheU0ngdDHHnnzojNYx&authKey=v1p%2BI3vfp3Bw60DIGgWxTtQSQ0NAz4ib%2FC6lTF0LjIi8dteVCtihitq5zID%2FoM0N&noverify=0&group_code=674604829 // ==/UserScript== (function() { "use strict"; // # 功能设置: 0 关闭,1 开启; 注:此处设置值如果改为(0 or 1)以外的值,会导致相应功能关闭(油猴脚本菜单中的选项也不会起效) // 此处的设置主要考虑到手机端使用时没有油猴脚本菜单可以 开启/关闭 功能,故添加于此。 var set = []; set['auto_n'] = 0 // 默认不会在嗅探出资源后自动打开列表 set['ffmpeg_n'] = 0 // 默认不会在浏览器下载完m3u8视频后进行视频转码 (解码需要浏览器开启特定功能并且会占用大量资源) set['ad_n'] = 1 // 默认会在下载m3u8视频时自动过滤其中夹杂的广告,但注意 有些广告使用了混淆 会导致视频片段会被误当做广告而去除,下载的视频不完整,这种情况关闭此功能即可。 set['checked_n']= 1 // 默认解除特殊网站对文本选中的限制,对开启此功能但仍无法解除选择限制的网站 可以提交网站给作者进行相应优化。 解除限制后可以进行复制等操作(1.70新加功能)。 var xcNum = 15 if (window.self == window.top) { GM_addElement('script', { textContent: GM_getResourceText('qbMediaRecorderJS') }); GM_addStyle( GM_getResourceText("LayuiCss").toString() .replace(/([^.@-]+{[^}]*}\s*)*/im , '') .replaceAll(/@font-face\s*\{\s*font-family:\s*layui-icon;[^}]*}/img, "@font-face { "+ "font-family: layui-icon; "+ "src: url(https://cdn.bootcdn.net/ajax/libs/layui/2.8.17/font/iconfont.eot); "+ "src: url(https://cdn.bootcdn.net/ajax/libs/layui/2.8.17/font/iconfont.eot) format('embedded-opentype'),"+ " url(https://cdn.bootcdn.net/ajax/libs/layui/2.8.17/font/iconfont.woff2) format('woff2'),"+ " url(https://cdn.bootcdn.net/ajax/libs/layui/2.8.17/font/iconfont.woff) format('woff'),"+ " url(https://cdn.bootcdn.net/ajax/libs/layui/2.8.17/font/iconfont.ttf) format('truetype'),"+ " url(https://cdn.bootcdn.net/ajax/libs/layui/2.8.17/font/iconfont.svg) format('svg')}") ); unsafeWindow.GM = GM; try { unsafeWindow.$('body') } catch(err) { unsafeWindow.$ = $; } } else { } var userAgent = navigator.userAgent.toLowerCase(); var platform,weight,weight1,offset; if(userAgent == null || userAgent == ''){ platform = 'pc' ; }else{ if(userAgent.indexOf("android") != -1 ){ platform = 'phone'; }else if(userAgent.indexOf("ios") != -1 || userAgent.indexOf("iphone") != -1 || userAgent.indexOf("ipad") != -1){ platform = 'phone'; }else if(userAgent.indexOf("windows phone") != -1 ){ platform = 'phone'; }else{ platform = 'pc' ; } } if(platform == 'pc'){ var menuList = [] var info = ['❌ 已禁用','✅ 已启用'] mkMenu([ { No : 0 , key: "支持作者的创作 ", KeyName : "me()"}, { No : 1 , key: "新资源自动打开:", keyName : "auto_n"}, { No : 2 , key: "是否将视频转码:", keyName : "ffmpeg_n"}, { No : 3 , key: "是否下载去广告:", keyName : "ad_n"}, { No : 4 , key: "除文本选中限制:", keyName : "checked_n"}, ]) } var w = window.innerWidth; var h = window.innerHeight; if(platform == 'pc'&& w > 800 && h >600){ weight = ['800px', '600px']; weight1 = ['550px', '700px']; offset = (h-600)/2+"px" }else{ if(w < 490){ var z = w/490; GM_addStyle( '#MyUpDown{zoom: '+z+';-moz-transform: scale('+z+');-moz-transform-origin:right top;;} '+ '#MyUrls{zoom: '+z+';-moz-transform: scale('+z+');-moz-transform-origin:right top;;} '+ '#Allurl{zoom: '+z+';-moz-transform: scale('+z+');-moz-transform-origin: right top;;}; ') } if(platform == 'pc'){ offset = w < h ? (h-w)/2+"px" : 0.1*h+"px"; weight = w < h ? [0.8*w+"px", 0.8*w+"px"] : [0.8*h+"px", 0.8*h+"px"]; weight1 = w < h ? [0.8*w+"px",0.8*w+94+"px"] : [0.8*h+"px",0.8*h+94+"px"]; }else{ offset = w < h ? (h-w)/2+"px" : 0.01*h+"px"; weight = w < h ? [0.98*w+"px", 0.98*w+"px"] : [0.98*h+"px", 0.98*h+"px"]; weight1 = w < h ? [0.98*w+"px",0.98*w+94+"px"] : [0.98*h+"px",0.98*h+94+"px"]; } } let URLAs = [],videos=[],play = 0,hzh = false;; var firstVideo = 0, mn = -1; unsafeWindow.GM_D = []; var href = location.href; var origin = location.origin $("body").attr("id","Top") .append(["<div id='MyUrls' style=' text-align: left;font-family: \"Times New Roman\",Georgia,Serif !important;;width: 490px;background-color: #ffffff;color: black;position: fixed;top: 1px;right: 1px;z-index: 999999999999999;border-radius: 4px;display: none;'>" + " <div id='Allurl' style=''>" + " <span id='LupinStart' title='录屏'>🔴</span>" + " <span id='LupinStop' title='停止录屏' style='display:none;'>⏹️</span>" + " <span id='Alldownload' title='下载全部资源'>⬇️</span>" + " <span id='Allcopy' title='复制全部链接'>📋</span>" + " <span id='Alldel' title='清除列表'>🗑️</span>" + " </div>"+ " <hr style='border-color: black;margin: 5px;height: 2px;background: black;border-width: 0;'>" + " <div class='MyUrls' style='background-color: #ffffff;border-radius: 4px;margin: 10px 10px;max-height: 500px;text-align: left;'>" + " <div id='tab-container'>"+ " <div id='MyVideo' class='my-tab'>🎬视频</div>"+ " <div id='MyAudio' class='my-tab'>🎧音频</div>"+ " </div> "+ " <div class='MyNR'>"+ " <div class='MyVideo'></div> <div class='MyAudio'></div>"+ " </div> "+ " </div>" + "</div>"][0]) .append(["<div id='MyUpDown' style='color: black;position: fixed;top: 1px;right: 1px;z-index: 1000009999999999999;font-size: 20px;line-height: 30px;text-align: center;cursor: pointer;'>" + " <div id='redPoint' style='width: 8px; height: 8px; background-color: red; border-radius: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display:none;'></div>"+ " <div id='downIcon' style='width: 30px!important;height: 30px!important;line-height: 30px!important;font-size: 16px !important;font-family: Helvetica!important;'>⤵️</div>"+ "</div>"][0]) .append() .append(["<a href='#Top' id='GoTop' target='_self' style='text-decoration: none;display: none; width: 30px;height: 30px;color: black;background-color:rgb(149, 228, 246);position: fixed; bottom: 50px;right: 1px;z-index: 9999999100000;font-size: 20px;line-height: 30px;text-align: center;cursor: pointer;border-radius: 30px;'>" + " <div id='GoTopIcon' style='width: 30px!important;height: 30px!important;line-height: 30px!important;font-size: 25px !important;font-family: Helvetica!important;' title='回到顶部'>⇡</div>"+ "</a>"][0]) GM_addStyle([ '#tab-container { display: flex; border-bottom: 2px solid #dee2e6; margin: 5px 5px 10px 5px; }'+ '.my-tab { flex: 1; text-align: center; padding: 2px 0; font-size: 16px; font-weight: bold; cursor: pointer; border-radius: 8px 8px 0 0; transition: all 0.2s ease; line-height: normal !important; border: 1px solid transparent; border-bottom: none; margin-bottom: -2px; }'+ '.my-tab.tab-active { background-color: #228be6; color: #ffffff; border-color: #228be6; }'+ '.my-tab:not(.tab-active) { background-color: #f1f3f5; color: #495057; }'+ '.my-tab:not(.tab-active):hover { background-color: #e9ecef; }'+ '#downIcon img { width: 90%!important; height: 90%!important; margin: 5%!important; padding: 0!important; line-height: 90%!important;}'+ '#Allurl { display: flex; justify-content: flex-end; align-items: center; width: 94%; height: 20px; box-sizing: border-box; padding-right: 10px; padding-top: 4px; }'+ '#Allurl>span { font-size: 16px; margin: 0 5px; cursor: pointer; }'+ '#MyUrls div,#MyUrls input { box-sizing: content-box!important;line-height: 100%; }'+ '.MyUrls hr { background: #837b7b; border-color: #837b7b; border-width: 0;height: 1px;margin: 0; padding: 0; border: none !important; }'+ '.MyNR { max-height: 465px; overflow-y: auto; }'+ '.MyNR>div { display: none }'+ '.MyNR div[class^=No-isUrl] { width: 30px;text-align: right;display: inline-block; height: 30px;line-height: 30px !important;}'+ '.MyNR input[class^=downUrl] { pointer-events: auto !important; opacity: 1 !important; cursor: text !important;font-size: 12px;width: 145px;display: inline-block;margin: 0px;height: 22px;border: 1px solid black;border-radius: 5px;padding: 0 5px;background: white;color: #000000 !important;}'+ '.MyNR input[class^=downName]{ font-size: 12px;width: 35px;display: inline-block;margin: 0px;height: 22px;border: 1px solid black;border-radius: 5px;padding: 0 5px;background: white;color:black;}'+ '.But { margin-left: 5px;height:20px;width: 40px;padding: 0;border: none;background: #228be6;color: #ffffff;border-radius:10px;cursor: pointer;line-height: 20px!important;font-size: 10px;text-align: center; }'+ '.MyNR div[class^=rmUrl] { display: inline-block;cursor: pointer;color:red; width: 30px; height: 30px;line-height: 30px !important; }'+ '#giegei717dplayer .dplayer-controller button{ background: black; }'+ '.dplayer-controller .dplayer-bar-wrap .dplayer-bar { height: 15px!important;top: -10px!important;}'+ '.dplayer-controller .dplayer-bar-wrap .dplayer-bar>[class^=dplayer-] { height: 15px!important;}'+ '.dplayer-controller .dplayer-bar-wrap .dplayer-bar .dplayer-played .dplayer-thumb { height: 22px!important; width: 22px!important;}' ][0]); $(".MyNR div").append(["<div class='urlnone' style='height: 22px;color: red;padding: 9px 0 0 20px;font-size: 15px;'> 暂时没有嗅探到资源</div>"+ "<div class='downloadUrl' style='height: 31px; line-height: 30px;'>"+ "<hr class='urlnone' > " + "<div class='No-isUrl'> 0、</div>"+ "<input class='downUrl' autocomplete='on' placeholder='请输入要下载的资源链接:' title='自定义资源下载项'> "+ "<input class='downName' style=' width: 125px;' placeholder='请输入文件名(下载用)' title='默认文件名为当前页面标题'>"+ "<div class='But SaveUrl' style='display: inline-block; '>下载</div>"+ "<div class='But StopSaveUrl' style='display: none; '>0%</div>"+ "<div class='But playUrl' style='display: inline-block; '>播放</div> "+ "<div class='rmUrl_input' title='清空' > x </div>"+ "</div>"][0]) var ad = 0,angle = 0; $("#MyUpDown").click(function () { var that = $(this) $("#MyUrls").slideToggle("slow",function(){ if (mn=="1"||mn==1){ }else { $("#redPoint").css("display","none") }; mn = -mn; }); if (mn=="1"||mn==1){ } var a = angle var setXZ = setInterval(function(){ $("#MyUpDown #downIcon").css( 'transform', 'rotate('+a+'deg)'); if ( a>=angle+45 ){ stop_XZ() } },5); function stop_XZ(){ clearInterval(setXZ); angle += 45 }; if(ad==0){ FirstOpen() ad = 99; } }) $(window).click(function (e) { var x =$(e.target).is('#MyUrls *,#MyUpDown *,#GoTop *,#MyUrls,#MyUpDown,#GoTop') if( !x && $("#MyUrls").css("display")!="none" && $("#MyUpDown").css('pointer-events') != 'none'){ $("#MyUpDown").click() $("#MyUpDown").css( 'pointer-events','none') setTimeout(function(){ $("#MyUpDown").css( 'pointer-events','all') },500) } }) $("#tab-container > .my-tab").click(function (){ $(this).addClass('tab-active').siblings().removeClass('tab-active'); $('.MyNR>div').css('display', 'none').attr('id',''); $('.MyNR .'+$(this).attr('id')).css('display', 'block').attr('id','My_VorA'); }); $("#MyVideo").addClass('tab-active'); $("#MyVideo").click(); $("#Alldownload").click(function (){ $('#My_VorA .isUrl').each(function(){ $(this).find("div.But:nth-last-of-type(4)").click() }) layer.msg("开始下载") }) $("#Allcopy").click(function (){ var urlss =""; $('#My_VorA .isUrl').each(function(){ urlss = urlss + $(this).find("[class^=downUrl]").attr('title').trim()+ "\n\n" }) GM_setClipboard(urlss); layer.msg("已复制") }) window.onload = ()=>{ if(GM_getValue("checked_n", 1) == set['checked_n']){ $('body :not(body)').css('user-select','auto') $('body #MyUrls[class=jianbian]').css('user-select', 'none') document.onselectstart = function(){ event.returnValue = true; return true; } document.oncopy = function(){ event.returnValue = true; return true; } document.onbeforecopy = function(){ event.returnValue = true; return true; } document.onkeydown = function(){ event.returnValue = true; return true; } document.onkeyup = function(){ event.returnValue = true; return true; } document.onkeypress = function(){ event.returnValue = true; return true; } function MyCopy(event){ var text = window.getSelection().toString() if ( text != undefined && text != null && text.trim() != '') { navigator.clipboard.writeText(text) .then(() => { layer.msg("已复制");console.log("已复制,由 copy 触发") }) .catch((error) => { GM_setClipboard( text );}) } } function MyKeydown(event){ var text = window.getSelection().toString() if ( (event.keyCode == 67 || event.keyCode == 88) && event.ctrlKey && text != undefined && text != null && text.trim() != '') { navigator.clipboard.writeText(text) .then(() => { layer.msg("已复制");console.log("已复制,由 keydown 触发") }) .catch((error) => { GM_setClipboard( text );}) } } $(window).keydown( MyKeydown(event) ).on("copy", function(event){ MyCopy(event)} ) var set$ = setInterval(function(){ try { $("body :not(button,input[type=button])").unbind("keypress keyup keydown copy").off( "keypress keyup keydown copy") stopSet() } catch(err) { unsafeWindow.$ = $; }},1000); function stopSet(){ clearInterval(set$); }; } } $("#Alldel").click(function (){ $('#My_VorA .isUrl').remove() GM_D.forEach(function(item){ item.forEach(function(i){ i.abort() }) }) layer.msg("已清除") }) $("#LupinStart").click( function (){ var constraints ={ audio:{ echoCancellation: true, autoGainControl: true, noiseSuppression:true }, surfaceSwitching: "include", video: { frameRate: { ideal: 30}, width: { ideal: 1920 }, height: { ideal: 1080 }, } }; var time = 0; var opts = { onstart: function onStart() { time = new Date().getTime() console.log('Recorder is started'+"\n"+'开始录屏'); $("#LupinStart").css('display','none') $("#LupinStop").css('display','inline-block') }, onstop: function onStop(blob) { time = new Date().getTime() - time; console.log('Recorder is stop'+"\n"+'录屏结束'+'\n'+'时长:'+time); stream.getTracks().forEach((track) => track.stop()); var link = document.createElement("a"); link.href = window.URL.createObjectURL(new Blob([blob])) link.download = "录屏 "+ new Date().toLocaleString().replaceAll("/",'-').replaceAll(":",'-') +".mp4"; link.click(); link.remove(); $("#LupinStop").css('display','none') $("#LupinStart").css('display','inline-block') }, mimeType: "video/webm; codecs=h264" }; try { window.rec = new QBMediaRecorder(opts); } catch(err) { console.log(err) } navigator.mediaDevices.getDisplayMedia(constraints).then((stream) => { window.stream = stream rec.start(stream); }); }) $("#LupinStop").click(function (){ rec.stop() }) $(".downUrl").on( 'input' ,function (){ $(this).attr("title",$(this).val()) }) $(".downName").on( 'input' ,function (){ $(this).attr("title",$(this).val()) }) $(".rmUrl_input").click(function (){ $(this).prevAll("input").val('') $(this).prevAll(".downUrl").attr("title","自定义视频下载项") $(this).prevAll(".downName").attr("title","默认文件名为当前页面标题") }) GoTop() window.onscroll = function(){ GoTop()} function GoTop(){ var t = document.documentElement.scrollTop || document.body.scrollTop; if( t >= 100 ) { $("#GoTop").css("display","block") } else { $("#GoTop").css("display","none") } } $(".MyNR .playUrl").click(function (){ var url = $(this).prevAll(".downUrl").attr("title") var type = $(this).prevAll(".downUrl").data('type') if(url == undefined || url.trim()=="" || url.trim().length == 0 || url.trim().split(".").filter(function(item){return item.trim() != "";}).length < 2){ layer.msg("无有效链接") }else{ dplayerUrl(url,0,type) $(".But:nth-last-of-type(2)").text('播放') $(this).text("播放中") } }) function functionAll(u,VorA="MyVideo"){ $(".MyNR ."+VorA+" .GoUrl"+u).click(function (){ var url = $(this).prevAll(".downUrl"+u).attr("title") var link = document.createElement('a'); link.href = url; link.target="_blank"; link.click(); link.remove(); }) $(".MyNR ."+VorA+" .CopyUrl"+u).click(function (){ var url = $(this).prevAll(".downUrl"+u).attr("title") GM_setClipboard(url); var aux = document.createElement("input"); aux.setAttribute("value", url); document.body.appendChild(aux); aux.select(); document.execCommand("copy"); document.body.removeChild(aux); $(this).text("已复制") }) $(".MyNR ."+VorA+" .playUrl"+u).click(function (){ var url = $(this).prevAll(".downUrl"+u).attr("title") var type = $(this).prevAll(".downUrl"+u).data('type') if(url == undefined || url.trim()=="" || url.trim().length == 0 || url.trim().split(".").filter(function(item){return item.trim() != "";}).length < 2){ layer.msg("无有效链接") }else{ var ui = u==''? 0 : u dplayerUrl(url,ui,type) $(".But:nth-last-of-type(2)").text('播放') $(this).text("播放中") } }) $(".MyNR ."+VorA+" .rmUrl"+u).click(function (){ var num = $(this).prevAll('.StopSaveUrl'+u).data('num') if(num != undefined){ GM_D[num].forEach(function(item){ item.abort() }) } $(this).parent(".isUrl").remove() var list = $('.isUrl') list.each(function(i){ $(this).children("#No-isUrl").text(i+1+'、') }) }) $(".MyNR ."+VorA+" .downName"+u).on( 'input' ,function (){ $(this).attr("title",$(this).val()) }) $(".MyNR input").dblclick( function () { this.select() }) $(".MyNR ."+VorA+" .SaveUrl"+u).click(function (){ var that = $(this) var url = $(that).prevAll(".downUrl"+u).val() if(url==undefined||url.trim()==''){ url = $(that).prevAll(".downUrl"+u).attr('title') if(url==undefined||url.trim()==''||url.trim()=="自定义资源下载项"){ layer.msg("无有效链接"); return; } } var name = $(that).prevAll(".downName"+u).val() if(name==undefined||name.trim()==""){ name = $('title').text() if(name==undefined||name.trim()==""){ name = url.split("/").pop().split("?")[0] if(name==undefined||name.trim()==""){ name = "文件未命名" } } } name = name.replaceAll(/\s+/ig," ").trim().replace(/(\.mp4)*$/igm,"") if( $(that).parents('.MyNR>div').find('.isUrl').length>5){ name = $(that).prevAll(".No-isUrl").text().trim() + name } $(that).css("display","none").next('.StopSaveUrl'+u).css("display","inline-block").text("解析中"); var request = []; var head_i = $(that).data('head_i') var head = $(that).data('head') console.log(head) delete head['Range']; delete head['Cache-Control'] var blob = []; var loadSize = []; var xhrs = 0 var num = -1 var href = $(that).data('head_href') var origin = head_i == 1 ? location.origin : $(that).data('head_origin') var Length =$(that).data('length') var Headers = $(that).data('headers') var Type = $(that).data('type') if(VorA == "MyVideo"){ name = name+".mp4" if( Length==null||Length==undefined||Length==""||Length<=0 && Type !="hls"){ console.log("mp4视频单线程下载中ing。") mp4Download(url) return; } if( Type == "hls"){ m3u8Download(url) }else{ console.log("mp4视频多线程下载中ing。") var RangeSize = parseInt((Length/ xcNum).toFixed(0)) for(var i=0,z=0;i<Length;i=i+RangeSize,z++){ var range_start=i,range_end=i+RangeSize-1; if (range_end + 1 >=Length) {range_end = Length} DownloadThread( z , range_start , range_end) } num =GM_D.push(request) $(that).next('.StopSaveUrl'+u).data('num',num-1) function DownloadThread( z, range_start , range_end){ function onprogress (event){ loadSize[z] = event.loaded; var all_length =0; loadSize.forEach( function(item){ all_length = all_length + item }); var loaded = ( parseFloat( all_length / Length * 100)).toFixed(1); if(loaded <= 100){ $(that).next(".StopSaveUrl"+ u ).text( loaded +"%"); console.log(u+"、线程 "+z+" : 已下载"+ event.loaded +" 总" +event.total); } } head.Range = "bytes=" +range_start +"-"+ range_end; request[z] = GM_xmlhttpRequest({ method: "GET", url: url, fetch: false, responseType: "arraybuffer", headers: head , onprogress: onprogress , onload: function(response) { blob[z] = new Blob([response.response], { type: 'video/mp4' }); var x=0,y=0; loadSize.forEach(function(item){ x = x + item }); blob.forEach(function(item){ y = y + item.size }); console.log(u +"、线程 "+z+" : 下载结束 下完线程的文件大小:"+ y +" 已下载的文件大小:"+ x +" 总:"+ Length); if (y >= Length) { var link = document.createElement("a"); link.href = window.URL.createObjectURL(new Blob(blob, { type: 'video/mp4' })); link.download = name; link.click(); link.remove(); $(that).text("已下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+ u).css("display","none").text("0%");console.warn(u +"、文件下载完成:" +name) } }, onabort: function(){ console.log("abort!"); }, onerror: function(x) { console.log("error!更换线路ing"); request.forEach(function(item){ item.abort() }); mp4Download(url); var numi = parseInt( $(that).next(".StopSaveUrl"+u ).data("num") ); GM_D[numi] = request; }, }); } } }else if(VorA == "MyAudio"){ name = name+".mp3" mp4Download(url) } function mp4Download(url){ console.log("资源单线程下载中ing。") head['If-Modified-Since'] = '0'; request.push(GM_download({ url: url, name: name, headers: head, onprogress : function (event) { if (event!=null) { var loaded = parseFloat(event.loaded / event.total * 100).toFixed(2); if(loaded >= 100){ $(that).text("已下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+u).css("display","none"); }else{ $(that).css("display","none").next(".StopSaveUrl"+u).css("display","inline-block").text(loaded+"%"); console.log(u+"、单线程: 已下载"+event.loaded+" 总"+event.total+ " 比 "+loaded +"%"); } } }, onload : function () { $(that).text("已下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+u).css("display","none").text("0%"); console.warn(u+"、文件下载完成:"+name) }, onerror : function (x) { console.log(x) $(that).text("错误").css("display","inline-block").attr("title","下载出错。").next(".StopSaveUrl"+u).css("display","none").text("0%"); } })) num =GM_D.push(request) $(that).next('.StopSaveUrl'+u).data('num',num-1); } function m3u8Download(url){ console.log("m3u8解析下载中ing。") GM_xmlhttpRequest({ method: "GET", url: url, headers: head, onerror: function(x) { console.log("m3u8 GET出错onerror") $(that).text("错误").css("display","inline-block").attr("title","下载出错。").next(".StopSaveUrl"+u).css("display","none").text("0%"); }, onload: function(response) { var err = [] var tsNum=0 var tsS = 0 var tsi =0 var tsLength var list0 var IV="",keyData=null; async function syncRequest(url) { var r = ''; head['If-Modified-Since'] = '0' await GM.xmlHttpRequest({ method: "GET", url: url , headers: head, responseType: "arraybuffer", }).then((value) => {console.log(value);r = value.response; }).catch(e => {console.error(e);return null}); return r; } function jiemi(pwdBlob){ IV = IV==null ? keyData : IV ; return aesDecryptArrayBuffer(keyData, IV, pwdBlob) function aesDecryptArrayBuffer(key, iv, encryptedArrayBuffer) { var encryptedWords = CryptoJS.lib.WordArray.create(encryptedArrayBuffer); if (typeof iv === 'string') { iv = stringToArrayBuffer(iv) } if (typeof key === 'string') { key = stringToArrayBuffer(key) } iv = CryptoJS.lib.WordArray.create(iv); key = CryptoJS.lib.WordArray.create(key); var decryptedWords = CryptoJS.AES.decrypt( { ciphertext: encryptedWords }, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } ); var decryptedBytes = CryptoJS.enc.Base64.stringify(decryptedWords); var decryptedArrayBuffer = base64ToArrayBuffer(decryptedBytes); return decryptedArrayBuffer; } function pad(key) { var x = 0b0 while (key.length % 16 !== 0) { key += 0b0; } return key; } function base64ToArrayBuffer(base64) { var binaryString = window.atob(base64); var len = binaryString.length; var bytes = new Uint8Array(len); for (var i = 0; i < len; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; } function arrayBufferToBase64(buffer) { var binary = ''; var bytes = new Uint8Array(buffer); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); } function stringToArrayBuffer(str) { let encoder = new TextEncoder(); return encoder.encode(str).buffer; } } function downTs(list,tsUrl,i,status){ head['If-Modified-Since'] = '0'; request[i] = GM_xmlhttpRequest({ method: "GET", url: tsUrl, headers: head, responseType: "arraybuffer", onloadstart: function(){ }, onload: function(response) { var buf = response.response blob[i] = buf if( status == "key"){ var setjm = setInterval(function(){ if(keyData != null ){ stopjm() blob[i] = ( new Blob([jiemi(response.response)], { type: 'video/mp4' }) ) }},50); function stopjm(){ clearInterval(setjm); }; }else{ blob[i] = ( new Blob([response.response], { type: 'video/mp4' }) ) } list0.splice(list0.indexOf(tsUrl),1) if (list0.length>0) { tsNum = parseFloat(tsNum) + 1 / tsS * 100; tsNum = tsNum >100 ? 100 : parseFloat(tsNum).toFixed(2); tsi = tsi+1 console.log(u+"、已下完的视频切片数:"+ tsi +" 总数:"+ tsS); $(that).next(".StopSaveUrl"+u).text(tsNum+"%"); if(list.length > 0 ){ downTs(list,list.shift(),i+1,status) } }else { $(that).next(".StopSaveUrl"+u).text("100%"); var is = true; try { var sab = new SharedArrayBuffer(1); } catch(err) { console.log( err.message +"\n 浏览器不支持SharedArrayBuffer") is = false } var link = document.createElement("a"); if(GM_getValue("ffmpeg_n", 1) == set['ffmpeg_n'] && is){ (async () => { try { FFmpeg; } catch(err) { console.log( err.message +"\n 没有加载FFmpeg"); await $.ajax({ async: false, url: "https://unpkg.com/@ffmpeg/[email protected]/dist/ffmpeg.min.js", dataType: "script" }); } $(that).next(".StopSaveUrl"+u).text("转码中"); const { createFFmpeg, fetchFile } = FFmpeg; const ffmpeg = createFFmpeg({ log: true, progress: ({ ratio }) => { tsNum = (ratio * 100.0).toFixed(2) $(that).next(".StopSaveUrl"+u).text(tsNum+"%").attr("title",'转码中'); }, }); console.log( '正在加载 ffmpeg-core.js'); await ffmpeg.load(); console.log('开始转码'); ffmpeg.FS('writeFile', 'video.ts', await fetchFile(new Blob(blob)) ); await ffmpeg.run('-i', 'video.ts' ,'output.mp4'); console.log('转码完成'); const data = ffmpeg.FS('readFile', 'output.mp4'); $(that).text("已下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+u).css("display","none").attr("title","下载中"); link.href = window.URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })); link.download = name; link.click(); link.remove(); ffmpeg.exit() })(); }else{ $(that).text("已下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+u).css("display","none").attr("title","下载中"); link.href = window.URL.createObjectURL(new Blob(blob, { type: 'video/mp4' })); link.download = name; link.click(); link.remove(); } console.warn(u+"、文件下载完成:"+name) } }, onabort: function(){ console.log("abort!"); }, onerror: function(x) { console.log("ts GET出错onerror!") console.log(x) if (err<10){ err = err+1 downTs(list,tsUrl,i) }else{ err = 0 $(that).text("错误").css("display","inline-block").attr("title","下载出错").next(".StopSaveUrl"+u).css("display","none").text("0%"); var num = $(that).next(".StopSaveUrl"+u).data("num") GM_D[num].forEach(function(item){ item.abort() }) } } }); } var Ts = response.responseText.trim() var TsStart = Ts.split(/(#EXTINF[^\n]*|#EXT-X-STREAM-INF[^\n]*)/)[0]; if(/^#EXTM3U/.test(TsStart)){ console.log("m3u8解析中") var num1,num2,ad_ts if(GM_getValue("ad_n", 1)== set['ad_n']){ while( Ts.search(/#EXT-X-DISCONTINUITY/i) != -1 ){ num1 = Ts.search(/#EXT-X-DISCONTINUITY/i); Ts = Ts.replace(/#EXT-X-DISCONTINUITY/i,'这是要去除的部分') num2 = Ts.search(/#EXT-X-DISCONTINUITY/i); ad_ts = num2 != -1 ? Ts.slice( num1,num2+20) : Ts.slice(num1) Ts = Ts.replace(ad_ts,"") if( Ts.search(/#EXT-X-DISCONTINUITY/i) == -1){ break } } } Ts = Ts.replaceAll(/^#(?!(EXTINF[^\n]*|EXT-X-STREAM-INF[^\n]*))[^\n]*/img,"").trim().replaceAll(/\n#/img,'??#').split('??') Ts = Ts.filter(function(item){ return item.trim() != ""; }); var status = "",bool = "false",mapURI = "false",keyUrl,keytext; TsStart.split("\n").forEach(function(item){ if(/#EXT-X-KEY/.test(item.trim())){ status = item.match(/METHOD=[\w-]{4,10}/im)[0] if( status!=undefined && status!= null && status!=''){ status = status.replaceAll(/METHOD=/igm,'').trim() if (status=='None'||status=="NONE"||status=='none'||status==''){ status = "" }else{ status = "key" keytext = item.match(/URI="[^"'\s]*"/i)[0].replaceAll(/(URI="|")/ig,'').trim() keyUrl = keytext if(/[\w]*\.key/.test(keyUrl)){ if( /^http[s]?:\/\/\w*\./.test(keyUrl)){ keyUrl = keyUrl }else if( /^\/\/\w*\./.test(keyUrl) | /^\w*\.\w*/.test(keyUrl)){ keyUrl = (new URL(url)).protocol + '//'+keyUrl.replaceAll(/(^\/\/)/ig,'') }else{ tsUrl1 = url.split("?")[0].split("/"); tsUrl1.pop(); keyUrl = tsUrl1.join("/")+"/"+keyUrl.replaceAll(/\s*/img,"") } } IV = item.match(/IV=[\wx]*/i)[0] IV = IV==null|IV==undefined|IV=="" ? null : IV.replaceAll(/(IV=)/ig,'').trim() } return; } } if(/#EXT-X-TARGETDURATION/.test(item.trim())){ bool = "true" } if(/#EXT-X-MAP:URI=/.test(item.trim())){ mapURI = Ts[0].split("\n")[0]+"\n"+item.replaceAll('#EXT-X-MAP:URI=','').replaceAll('"','').replaceAll("'","").trim() Ts.unshift(mapURI) var list = [] Ts.forEach(function(item,i){ list.push(item) list.push(mapURI) }) Ts = list.slice(); } }) if(status == "key"){ if( /^(http:|https:)?(\/{0,2}([^\.\s\/]*\.){1,2}[\w]{1,8})/.test(keyUrl) ){ keyData = syncRequest(keyUrl).then(val => { keyData = val console.log( "m3u8加密,启用解密") }).catch(e => { keyData = keytext console.log(e) console.log( "m3u8加密,解密困难,尝试中") }) }else{ $(that).text("错误").css("display","inline-block").attr("title","m3u8加密,暂时无法解决。").next(".StopSaveUrl"+u).css("display","none").text("0%"); console.log("m3u8加密,暂时无法解决。") layer.msg("m3u8加密,暂时无法解决。", {icon: 2}); return; } } var tsUrl,tsUrl1; Ts.forEach(function(item,i){ if(/^(#EXTINF[^\n]*|#EXT-X-STREAM-INF[^\n]*)/.test(item.trim())){ tsUrl = item.trim().match(/\n.*/img)[0].trim() if(/^(http:|https:)/.test(tsUrl)){ tsUrl = item.trim() }else if( /^(\/{0,2}([^\.\s\/]*\.){1,3}[\w]{1,8}(:[\d]{1,5})?)\/.*/.test(tsUrl) ){ tsUrl = href.trim().match(/^(http:|https:)/im)[0]+"//"+tsUrl.replace(/^(\/{0,2})/img,"") }else if( /^(\/)/.test(tsUrl)){ tsUrl1 = url.replace("://",":\\"). split(/\//)[0].replace(":\\","://") tsUrl1 = tsUrl1 + tsUrl.replaceAll(/\s*/img,"") tsUrl = item.trim().replaceAll(tsUrl.trim(),tsUrl1) }else{ tsUrl1 = url.split("?")[0].split("/"); tsUrl1.pop(); tsUrl1 = tsUrl1.join("/")+"/"+tsUrl.replaceAll(/\s*/img,"") tsUrl = item.trim().replaceAll(tsUrl.trim(),tsUrl1) } Ts[i] = tsUrl } }) if(bool == "true"){ console.log("m3u8没有嵌套,直接解析。") Ts.forEach(function(item,i){ Ts[i] = item.trim().match(/\n.*/img)[0].trim(); }); tsLength = Ts.length; tsS = tsLength; var TssSize = parseInt( ( tsLength/ xcNum).toFixed(0) ) TssSize = TssSize < 1 ? 1 : TssSize; list0 = Ts.slice(); for(var i=0,z=0;i < tsLength; i = i+TssSize, z++){ var range_start = i,range_end = i+TssSize; if (range_end > tsLength) {range_end = tsLength} var tslist = Ts.slice(range_start,range_end); downTs(tslist, tslist.shift(),i,status) } num =GM_D.push(request) $(that).next('.StopSaveUrl'+u).data('num',num-1); }else{ console.log("这下边嵌套了m3u8。") var maxP='0x0',maxUrl=''; Ts.forEach(function(item,i){ tsUrl = item.split("\n",2) if( /RESOLUTION=\d+\D\d+/igm.test( tsUrl[0] )){ var P = tsUrl[0].match(/RESOLUTION=\d+\D\d+/igm)[0].match(/\d+\D\d+/igm)[0] if( maxP.split(/\D/).reduce(function(val1,val2){return val1*val2}) < P.split(/\D/).reduce(function(val1,val2){return val1*val2}) ){ maxUrl = tsUrl[1] ; maxP = P } }else{ maxUrl = tsUrl[1] return; } }) GM_xmlhttpRequest({ method: "GET", url: maxUrl, onerror: function(x) { $(that).text("错误").css("display","inline-block").attr("title","下载出错。").next(".StopSaveUrl"+u).css("display","none").text("0%"); console,log(x) }, onload: function(response) { url = maxUrl var Ts = response.responseText.trim() var TsStart = Ts.split(/(#EXTINF[^\n]*)/)[0]; if(/^#EXTM3U/.test(TsStart)){ console.log("嵌套m3u8解析中") var num1,num2,ad_ts if(GM_getValue("ad_n", 1)== set['ad_n']){ while( Ts.search(/#EXT-X-DISCONTINUITY/i) != -1 ){ num1 = Ts.search(/#EXT-X-DISCONTINUITY/i); Ts = Ts.replace(/#EXT-X-DISCONTINUITY/i,'这是要去除的部分') num2 = Ts.search(/#EXT-X-DISCONTINUITY/i); ad_ts = num2 != -1 ? Ts.slice( num1,num2+20) : Ts.slice(num1) Ts = Ts.replace(ad_ts,"") if( Ts.search(/#EXT-X-DISCONTINUITY/i) == -1){ break } } } Ts = Ts.replaceAll(/^#(?!(EXTINF[^\n]*))[^\n]*/img,"").trim().replaceAll(/\n#/img,'??#').split('??') Ts = Ts.filter(function(item){ return item.trim() != ""; }); var status = "",bool = "false",mapURI = "false",keyUrl,keytext; TsStart.split("\n").forEach(function(item){ if(/#EXT-X-KEY/.test(item.trim())){ status = item.match(/METHOD=[\w-]{4,10}/im)[0] if( status!=undefined && status!= null && status!=''){ status = status.replaceAll(/METHOD=/igm,'').trim() if (status=='None'||status=="NONE"||status=='none'||status==''){ status = "" }else{ status = "key" keytext = item.match(/URI="[^"'\s]*"/i)[0].replaceAll(/(URI="|")/ig,'').trim() keyUrl = keytext if(/[\w]*\.key/.test(keyUrl)){ if( /^http[s]?:\/\/\w*\./.test(keyUrl)){ keyUrl = keyUrl }else if( /^\/\/\w*\./.test(keyUrl) | /^\w*\.\w*/.test(keyUrl)){ keyUrl = (new URL(url)).protocol + '//'+keyUrl.replaceAll(/(^\/\/)/ig,'') }else{ tsUrl1 = url.split("?")[0].split("/"); tsUrl1.pop(); keyUrl = tsUrl1.join("/")+"/"+keyUrl.replaceAll(/\s*/img,"") } } IV = item.match(/IV=[\wx]*/i)[0] IV = IV==null|IV==undefined|IV=="" ? null : IV.replaceAll(/(IV=)/ig,'').trim() } return; } } if(/#EXT-X-MAP:URI=/.test(item.trim())){ mapURI = Ts[0].split("\n")[0]+"\n"+item.replaceAll('#EXT-X-MAP:URI=','').replaceAll('"','').replaceAll("'","").trim() Ts.unshift(mapURI) var list = [] Ts.forEach(function(item,i){ list.push(item) list.push(mapURI) }) Ts = list.slice(); } }) if(status == "key"){ if( /^(http:|https:)?(\/{0,2}([^\.\s\/]*\.){1,2}[\w]{1,8})/.test(keyUrl) ){ keyData = syncRequest(keyUrl).then(val => { keyData = val console.log( "m3u8加密,启用解密") }).catch(e => { keyData = keytext console.log(e) console.log( "m3u8加密,解密困难,尝试中") }) }else{ $(that).text("错误").css("display","inline-block").attr("title","m3u8加密,暂时无法解决。").next(".StopSaveUrl"+u).css("display","none").text("0%"); console.log("m3u8加密,暂时无法解决。") layer.msg("m3u8加密,暂时无法解决。", {icon: 2}); return; } } var tsUrl,tsUrl1; Ts.forEach(function(item,i){ if(/^(#EXTINF[^\n]*|#EXT-X-STREAM-INF[^\n]*)/.test(item.trim())){ tsUrl = item.trim().match(/\n.*/img)[0].trim() if(/^(http:|https:)/.test(tsUrl)){ tsUrl = item.trim() }else if( /^(\/{0,2}([^\.\s\/]*\.){1,3}[\w]{1,8}(:[\d]{1,5})?)\/.*/.test(tsUrl) ){ tsUrl = href.trim().match(/^(http:|https:)/im)[0]+"//"+tsUrl.replace(/^(\/{0,2})/img,"") }else if( /^(\/)/.test(tsUrl)){ tsUrl1 = url.replace("://",":\\"). split(/\//)[0].replace(":\\","://") tsUrl1 = tsUrl1 + tsUrl.replaceAll(/\s*/img,"") tsUrl = item.trim().replaceAll(tsUrl.trim(),tsUrl1) }else{ tsUrl1 = url.split("?")[0].split("/"); tsUrl1.pop(); tsUrl1 = tsUrl1.join("/")+"/"+tsUrl.replaceAll(/\s*/img,"") tsUrl = item.trim().replaceAll(tsUrl.trim(),tsUrl1) } Ts[i] = tsUrl } }) Ts.forEach(function(item,i){ Ts[i] = item.trim().match(/\n.*/img)[0].trim(); }); tsLength = Ts.length; tsS = tsLength; var TssSize = parseInt( ( tsLength/ xcNum).toFixed(0) ) TssSize = TssSize < 1 ? 1 : TssSize; list0 = Ts.slice(); for(var i=0,z=0;i < tsLength; i = i+TssSize, z++){ var range_start = i,range_end = i+TssSize; if (range_end > tsLength) {range_end = tsLength} var tslist = Ts.slice(range_start,range_end); downTs(tslist, tslist.shift(),i,status) } num =GM_D.push(request) $(that).next('.StopSaveUrl'+u).data('num',num-1); }else{ var blob = new Blob([response.response], { type: 'video/mp4' }) if( blob.size< 1024*1024/2 ){ $(that).text("错误").css("display","inline-block").attr("title","URL链接异常").next(".StopSaveUrl"+u).css("display","none").text("0%"); console.log("URL链接异常") layer.msg("URL链接异常,请检查链接后重试", {icon: 2}); return; } var link = document.createElement("a"); link.href = window.URL.createObjectURL(blob ); link.download = name; link.click(); link.remove(); $(that).text("下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+u).css("display","none").text("0%"); } } }) } }else{ var link = document.createElement("a"); link.href = window.URL.createObjectURL(new Blob([response.response], { type: 'video/mp4' })); link.download = name; link.click(); link.remove(); $(that).text("已下载").css("display","inline-block").attr("title","下载").next(".StopSaveUrl"+u).css("display","none").text("0%"); } } }) } }) $(".MyNR ."+VorA+" .StopSaveUrl"+u).click(function (){ var num = $(this).data("num") GM_D[num].forEach(function(item){ item.abort() }) $(this).data("num","").css("display","none").text("0%").prev(".SaveUrl"+u).text("继续").attr("title","下载中断").css("display","inline-block"); }) } try { GM.webRequest() GM_webRequest([ { selector: '*://*/*.m3u8*', action: { redirect: { from: "(.*)", to: "\$1" } } }, { selector: '*://*/*m3u8*', action: { redirect: { from: "(.*)", to: "\$1" } } }, ], function(info, message, details) { var z = details.url; if(z == $('#MyUrls .downUrl').val().trim() ){ return; } if(z !=undefined && z.trim()!="" ){ addUrl( z ) } }); if( location.host == 'www.douyin.com' ){ GM_webRequest([ { selector: 'https://v3-web-prime.douyinvod.com/video/*', action: { redirect: { from: "(.*)", to: "\$1" } } }, { selector: 'https://v26-web-prime.douyinvod.com/video/*', action: { redirect: { from: "(.*)", to: "\$1" } } }, { selector: 'https://www.douyin.com/aweme/v1/play/?file_id=*', action: { redirect: { from: "(.*)", to: "\$1" } } }, ], function(info, message, details) { var z = details.url.trim(); if(z == $('#MyUrls .downUrl').val().trim() ){ return; } if(z !=undefined && z.trim()!="" ){ addUrl( z ) } }); } } catch(err) { console.log("当前浏览器不支持 GM_webRequest()"); } if( location.host == 'www.bilibili.com' && ( /https:\/\/www\.bilibili\.com\/video\/BV\w*/i.test(location.href)||/https:\/\/www\.bilibili\.com\/bangumi\/play\/\w*/i.test(location.href) ) ){ window.addEventListener("pushState", function () { biliVideo (1) }); if (window.self == window.top) { biliVideo (0) } } var bili_url = '' var New_bili_url='' function biliVideo (i){ var set$ = setInterval(function(){ var videoData switch( location.href.trim().match(/(www\.bilibili\.com\/(video|bangumi))/im)[0] ) { case "www.bilibili.com/video": videoData = unsafeWindow.__INITIAL_STATE__.videoData var name = new URLSearchParams(window.location.search); var page = name.get('p'); if(page == null||page ==undefined||page ==''){ page = 1 } for (let i = 0; i < videoData.pages.length; i++) { if (videoData.pages[i].page == page) { New_bili_url = 'https://api.bilibili.com/x/player/playurl?avid='+ videoData.aid+'&cid='+ videoData.pages[i].cid+'&qn=120' name = videoData.pages[i].part if( name.trim() != $('.video-title').text().trim() ){ name = $('.video-title').text().trim()+" —— "+ name.trim() } break; } } break; case "www.bilibili.com/bangumi": if(i==0){ videoData = playurlSSRData.result.play_view_business_info.episode_info }else{ videoData = $($.get({url:location.href,async:false}).responseText).last().text() videoData = JSON.parse(videoData).props.pageProps.dehydratedState.queries[0].state.data.result.play_view_business_info.episode_info } New_bili_url = 'https://api.bilibili.com/x/player/playurl?avid='+ videoData.aid+'&cid='+ videoData.cid+'&qn=120' name = $('[class^=mediainfo_mediaTitle__]').text()+" ["+videoData.title+"] : "+videoData.long_title break; default: break; } if( location.host == 'www.bilibili.com' && ( /https:\/\/www\.bilibili\.com\/video\/BV\w*/i.test(location.href)||/https:\/\/www\.bilibili\.com\/bangumi\/play\/\w*/i.test(location.href) ) && New_bili_url!=bili_url ){ bili_url = New_bili_url stopSet() GM_xmlhttpRequest({ method: "GET", url: bili_url , headers: {'Referer': location.href,'If-Modified-Since': '0',"Cache-Control":"no-store"}, onerror: function(x) { console.log("bili接口数据出错: url="+bili_url) console.log(x) }, onload: function(response) { if( response.status>400){ return; } var data = response.responseText; New_bili_url = JSON.parse(data).data.durl[0].url; url_lists.push( New_bili_url ) addUrl(New_bili_url, name ) } }) } },100); function stopSet(){ clearInterval(set$); }; } var _wr = function(type) { var orig = history[type]; return function() { var rv = orig.apply(this, arguments); var e = new Event(type); e.arguments = arguments; window.dispatchEvent(e); return rv; }; }; unsafeWindow.history.pushState = _wr('pushState'); unsafeWindow.history.replaceState = _wr('replaceState'); function getNetworkRequsts(){ return performance.getEntriesByType("resource") .filter((entry) => { return (entry.initiatorType === "audio"||entry.initiatorType === "video" || entry.initiatorType=== "xmlhttprequest" || entry.initiatorType=== "fetch"); }); } var observer = new PerformanceObserver(perf_observer); observer.observe({entryTypes: ["resource"]}) unsafeWindow.scriptsList = [] unsafeWindow.url_lists = [] function perf_observer(list,observer){ var z,m,length= 0; length = $('.MyUrls .isUrl').length var scripts =getNetworkRequsts() scripts = scripts.filter(function(i){ return !scriptsList.includes(i); } ) if(scripts.length<1){ scripts.push('') } scripts.forEach(function (x,i) { if( x != ""){ z = x.name.trim() if($('.MyNR div.downloadUrl > input.downUrl').map(function() {return $(this).val();}).get().includes(z) ){console.log('此链接是0、框里的'); return; } url_lists.push( z ) if( (/m3u8/i.test(z) && !/\.ts/i.test(z.replaceAll(/\?.*/g,''))) || /mp4\??.*/i.test(z) || /\.ogg\??.*/i.test(z) || /.*\.m4a\??.*/i.test(z) || /.*\.mp3\??.*/i.test(z) || !( /\.\w{1,5}$/i.test(z.replaceAll(/\?.*/g,'')) )){ if(z !=undefined && z.trim()!="" ){ var name = "" switch( location.host ) { case 'y.qq.com': if(location.href== 'https://y.qq.com/n/ryqq/player' ){ name = $('.player_music__info').text() } break; case 'www.iwara.tv': name = '['+$('a[class=username]').attr('title') +'] '+ $('title').text() break; case 'www.douyin.com' : default: break; } addUrl( z,name) } } } $("video").each(function () { var that = $(this) if( that.parents("#giegei717dplayer").length!=0){ return; } if(!/^blob:/i.test( that.attr('src') ) ){ z = that.attr('src') if(z !=undefined && z.trim()!="" ){ var name = "" switch( location.host ) { case 'buyin.jinritemai.com' : if( /https\:\/\/buyin\.jinritemai\.com\/dashboard\/merch-picking-library\/merch-promoting\?/i.test( location.href ) ){ var title =$(that).parents('[class^=index_module__contentCard____]').find('div[class^=index_module__authorInfo____]') name = title.find('[class^=index_module__name____]').text() var show = title.find('[class^=index_module__descLine____]').text() name = name+' --- '+show } break; default: break; } addUrl( z,name) } } }) $("audio").each(function () { var that = $(this) z = $(this).attr('src') if( that.parents("#giegei717dplayer").length!=0){ return; } if(z !=undefined && z.trim()!="" ){ var name = "" if( /https:\/\/y\.qq\.com\/n\/ryqq\/player/i.test(location.href) ){ name = $('.player_music__info').text() } addUrl( z,name) } }) $("source").each(function () { if( $(this).parents("#giegei717dplayer").length!=0){ return; } if($(this).attr('src')!=undefined && $(this).attr('src').trim()!='' && !/^blob:/.test($(this).attr('src')) ){ if(!/^(http:|https:)/.test($(this).attr('src'))){ z = location.href.split("://")[0] +':'+ $(this).attr('src') }else{ z = $(this).attr('src') } addUrl( z,"" ) } }) }) scriptsList = scriptsList.concat(scripts); if($('.MyUrls .isUrl').length > length){ } } var ul_li = 0 window.addEventListener('message', function(event) { var url = event.data if( url.url== undefined || url.url == null || url.url ==""){ return; } addUrl(url.url, url.name , url.href) }, true) if (window.self !== window.top && ($('#MyUpDown').css("display")!="none" || $('#MyUrls').css("display")!="none") ) { $('#MyUpDown,#MyUrls').css("display","none") } unsafeWindow.url_info = [] unsafeWindow.urls = [] function addUrl( url ,name='',href = location.href){ if( url == undefined || url == null || url.length < 1){ console.log("addurl=null, return.") return; } if (window.self != window.top) { var message = { url:url,name:name, href:location.href }; window.parent.postMessage(message, "*"); return; } else { url = url.toString().trim() if(/^(http:|https:)/.test(url)){ }else if( /^(\/{0,2}([^\.\s\/]*\.){1,3}[\w]{1,8}(:[\d]{1,5})?)\/.*/.test(url) ){ url = href.trim().match(/^(http:|https:)/im)[0]+"//"+url.replace(/^(\/{0,2})/img,"") }else if( /^(\/)/.test(url)){ url = location.origin + url } } if(! urls.includes(url.trim())){ urls.push(url.trim()) }else{ return; } switch( location.host ) { case 'x.com': if( /(\/pl\/mp4a\/|\/pl\/avc1)/i.test( url ) ){ return } break; case 'www.iwara.tv': if( !/(_Source\.mp4)/i.test( url ) ){ return } break; default: break; } GM_xhr( url) function GM_xhr( url, i=0){ var head var Headers var Length var Type var origin= (new URL(href)).origin var default_web = false switch( location.host ) { case 'web.telegram.org': head = { Range:"bytes=0-200", "user-agent": "User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0"} default_web = true break; } if (!default_web){ origin= (new URL(href)).origin switch( i ) { case 0: head = {Range:"bytes=0-200", 'Cache-Control':"no-store"} break; case 1: head = {Referer: href, Range:"bytes=0-200", "Cache-Control":"no-store"} break; case 2: head = {Referer: href, Origin: origin ,Range:"bytes=0-200", "Cache-Control":"no-store"} break; case 3: href = (new URL(url)).origin+'/' head = {Referer: href, Origin: origin } break; case 4: origin = location.origin head = {Referer: href, Origin: location.origin ,Range:"bytes=0-200", "Cache-Control":"no-store"} break; case 5: href = url head = {Referer: url, Range:"bytes=0-200"} break; case 6: default: console.log("Url始终HEAD 错误,不添加列表: "+url) return; break; } } var get = GM_xmlhttpRequest({ method: "GET", url: url, fetch: true, headers: head, onerror: function(x) { console.log("Url错误onerror,HEAD出错 : "+url) console.log(x) url_info.push( { url:url, info: "Url错误onerror,HEAD出错 ", response: x} ) GM_xhr( url , i+1 ) get.abort() return; }, onload: function(response) { console.log(get) console.log(response) console.log(url) console.log(head) var x var num if (/https:\/\/web\.telegram\.org\/a\/progressive\/document\d{19}$/i.test( url ) ){ Type = 'normal'; VorA = "MyVideo" x = $("#MyUrls .MyNR>."+VorA) num = x.find('.isUrl').length+1 x.find(".urlnone").remove() x.append("<div class='isUrl' style='height: 31px;'>"+ "<hr > " + "<div class='No-isUrl'> " +num+"、</div>"+ "<input disabled data-type='"+Type+"' class='downUrl"+num+"' title='"+url+"' value='"+url+"'> "+ "<input title='"+ (name=="" ? '自定义保存文件名' : name) +"' class='downName"+num+"' placeholder='文件名' value='"+name+"'>"+ "<div style='display: inline-block;' class='But GoUrl"+num+"' >访问</div>"+ "<div style='display: inline-block;' class='But CopyUrl"+num+"' >复制</div>"+ "<div style='display: inline-block;' data-head_i='"+i+"' data-head_href='"+href+"' data-head_origin='"+origin+"' data-Headers='"+Headers+"' data-Length='"+Length+"' data-Type='"+Type+"' data-head='"+ JSON.stringify(head) + "' class='But noSaveUrl"+num+"' >No</div>"+ "<div style='display: none; ' class='But StopSaveUrl"+num+"'> 0% </div>"+ "<div style='display: inline-block;' class='But playUrl"+num+"' >播放</div> "+ "<div title='删除此条' class='rmUrl"+num+"' > x </div>"+ "</div>") functionAll(num,VorA) if($("#MyUrls").css("display")=="none"){ $("#redPoint").css("display","block") $(".MyBT #"+VorA).click() if(GM_getValue("auto_n", 1) == set['auto_n']){ $("#MyUpDown").click() } } return }else{ if(response.status/100>=3&& response.status!=404 ){ console.log("Url错误onerror,HEAD 403: "+url) url_info.push( { url:url, info: "Url错误onerror,HEAD 403", response: response} ) GM_xhr( url , i+1 ) return; } if(response.status/100>=3){ console.log("Url错误onerror,HEAD出错 不添加列表: "+url) console.log(response) url_info.push( { url:url, info: "Url错误status>400 不添加列表", response: response} ) get.abort() } Headers = response.responseHeaders; if( Headers == undefined || Headers == null || Headers ==""||Headers.length<1 ){ console.log("Url:"+url+",HEAD出错: responseHeaders 为空") url_info.push( { url:url, info: "HEAD出错: responseHeaders 为空", response: response} ) return; } Type = Headers.match(/content-type:\s*[\S]+\s/im) var VorA = "MyVideo" if(Type == undefined || Type == null || Type.length<1){ if( /^#EXTM3U/i.test(response.responseText) ){ Type = 'hls'; VorA = "MyVideo" }else{ console.log("Type为空"+url) console.log(response) url_info.push( { url:url, info: "Type为空", response: response} ) return } }else{ Type = Type[0].replace('content-type:','').trim() if( /.*video\/mp4.*/i.test( Type ) || ( /application\/octet-stream/i.test( Type ) && /mp4\??.*/i.test(url) ) ){ Length = Headers.match(/content-range:\s*bytes\s*0-[\d]+\/[\d]+\s/im)[0].replace(/.*\//img,'').trim() if( Length < 1024*1024){ console.log("嗅探到的视频太小x1:"+Length+"B ,丢弃:"+url) url_info.push( { url:url, info: "嗅探到的视频太小x1:"+Length+"B ,丢弃", response: response} ) return; } Type = 'normal'; VorA = "MyVideo" }else if( /.*\/.*mpegurl.*/i.test( Type )){ Type = 'hls'; VorA = "MyVideo" }else if( /.*audio\/.*/i.test( Type )){ Type = 'auto'; VorA = "MyAudio" }else if( /.*(text\/[\w]*).*/i.test( Type ) || /application\/octet-stream/i.test( Type ) ) { if( /^#EXTM3U/i.test(response.responseText) ){ Type = 'hls'; VorA = "MyVideo" }else{ url_info.push( { url:url, info: "Type:"+Type, response: response} ) console.log(Type, url) return; } }else{ url_info.push( { url:url, info: "Type:"+Type, response: response} ) console.log(Type, url) return; } } } x = $("#MyUrls .MyNR>."+VorA) x.find(".urlnone").remove() num = x.find('.isUrl').length+1 x.append("<div class='isUrl' style='height: 31px;'>"+ "<hr > " + "<div class='No-isUrl'> " +num+"、</div>"+ "<input disabled data-type='"+Type+"' class='downUrl"+num+"' title='"+url+"' value='"+url+"'> "+ "<input title='"+ (name=="" ? '自定义保存文件名' : name) +"' class='downName"+num+"' placeholder='文件名' value='"+name+"'>"+ "<div style='display: inline-block;' class='But GoUrl"+num+"' >访问</div>"+ "<div style='display: inline-block;' class='But CopyUrl"+num+"' >复制</div>"+ "<div style='display: inline-block;' data-head_i='"+i+"' data-head_href='"+href+"' data-head_origin='"+origin+"' data-Headers='"+Headers+"' data-Length='"+Length+"' data-Type='"+Type+"' data-head='"+ JSON.stringify(head) + "' class='But SaveUrl"+num+"' >下载</div>"+ "<div style='display: none; ' class='But StopSaveUrl"+num+"'> 0% </div>"+ "<div style='display: inline-block;' class='But playUrl"+num+"' >播放</div> "+ "<div title='删除此条' class='rmUrl"+num+"' > x </div>"+ "</div>") functionAll(num,VorA) if($("#MyUrls").css("display")=="none"){ $("#redPoint").css("display","block") $(".MyBT #"+VorA).click() if(GM_getValue("auto_n", 1) == set['auto_n']){ $("#MyUpDown").click() } } } }) console.log(get) } } function mkMenu(list){ list.forEach( function(menu){ var No = menu.No var key = menu.key var keyName = menu.keyName var keyVal = GM_getValue( keyName, 1) if( No == 0 ){ menuList[No] = GM_registerMenuCommand( key , function() { eval( keyName ) }) }else{ menuList[No] = GM_registerMenuCommand( key+info[ keyVal == set[keyName] ? 1 : 0 ], function() { keyVal = keyVal == 1 ? 0 : 1 GM_setValue(keyName, keyVal); mkMenu( [menu] ) }, { id: menuList[No] } ); } }) } function rmMenu(id){ GM_unregisterMenuCommand(id); } function dplayerUrl(url,i,type){ var lay_i = unsafeWindow.dpgiegei717index; $('#layui-layer'+lay_i+',#layui-layer-shade'+lay_i).remove() var index = layer.load(2); var conf = { type: 1, title: i+"、"+url, shadeClose: true, offset: offset, fixed: true, maxmin: true, resize: true, airplay: true, chromecast: true, move: '.layui-layer-title', moveOut: false, btn: [], area: weight, content: "<div id='giegei717dplayer' style='width: 100%;height: 100%;display:flex;align-items:center;justify-content:center;'></div>" ,success: function(layero, index){ unsafeWindow.dpgiegei717 = new DPlayer({ element: document.getElementById("giegei717dplayer"), preload: 'auto', hotkey: true, volume: 1, mutex: true, loop: false, airplay: true, playbackSpeed: [0.1,0.5, 1, 1.25, 1.5, 2], screenshot: true, autoplay: true, preventClickToggle: false, contextmenu: [ { text: '刷新视频', click: (player) => { player.switchVideo( { url: url, type: type, }, ); player.play() }, }, { text: '复制链接', click: (player) => { GM_setClipboard(url); var aux = document.createElement("input"); aux.setAttribute("value", url); document.body.appendChild(aux); aux.select(); document.execCommand("copy"); document.body.removeChild(aux); layer.msg("已复制") } } ], video: { url: url, type: type, }, }); dpgiegei717.video.crossOrigin=null; dpgiegei717.on('error', function () { if( firstVideo == 0 ){ console.log('加载video的扩展js') GM_addElement('script', { src: 'https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.min.js',type: 'text/javascript' }); GM_addElement('script', { src: 'https://cdn.bootcdn.net/ajax/libs/shaka-player/4.3.5/shaka-player.compiled.min.js',type: 'text/javascript' }); GM_addElement('script', { src: 'https://cdn.bootcdn.net/ajax/libs/dashjs/4.6.0/dash.all.min.js',type: 'text/javascript' }); firstVideo = 1 dpgiegei717.switchVideo({ url: url, type: type, }); dpgiegei717.play() } }); var set = setInterval(function(){ if($('#giegei717dplayer>.dplayer-video-wrap>video').length>0){ var video = $('#giegei717dplayer>.dplayer-video-wrap> video[class^=dplayer-video]')[0] stopSet() var touchtime = 0; var touchtarget; $('#giegei717dplayer>.dplayer-video-wrap> video[class^=dplayer-video]').on("dblclick",function () { if (document.fullscreenElement == null) { dpgiegei717.fullScreen.request(); } else { dpgiegei717.fullScreen.cancel(); } }).on('touchstart', function(event) { if (touchtime == 0) { touchtime = new Date().getTime(); touchtarget = event.target; } else { if (event.target == touchtarget && new Date().getTime() - touchtime < 300) { if (document.fullscreenElement == null) { dpgiegei717.fullScreen.request(); } else { dpgiegei717.fullScreen.cancel(); } touchtime = 0; } else { touchtime = new Date().getTime(); touchtarget = event.target; } } }); $('#giegei717dplayer .dplayer-icons-right').prepend('<div class="dplayer-icon dplayer-hzh-icon" data-balloon="画中画" data-balloon-pos="up">'+ '<span class="dplayer-icon-content"><svg width="24" height="22" xmlns="http://www.w3.org/2000/svg">'+ '<path d="m19.22801,9.8748l-8.11544,0l0,5.89418l8.11544,0l0,-5.89418zm4.05772,7.85891l0,-13.77273c0,-1.0806 -0.91299,-1.94508 -2.02886,-1.94508l-18.25974,0c-1.11587,0 -2.02886,0.86448 -2.02886,1.94508l0,13.77273c0,1.0806 0.91299,1.96473 2.02886,1.96473l18.25974,0c1.11587,0 2.02886,-0.88413 2.02886,-1.96473zm-2.02886,0.01965l-18.25974,0l0,-13.80221l18.25974,0l0,13.80221z"></path>'+ '</svg></span>'+ '</div>') $('#giegei717dplayer .dplayer-icons-right>.dplayer-hzh-icon').on('click',function(){ var that = this; if(hzh == false && !document.pictureInPictureElement){ video.requestPictureInPicture(); video.addEventListener('enterpictureinpicture', function() { hzh = true; }); }else{ document.exitPictureInPicture(); video.addEventListener('leavepictureinpicture', function() { hzh = false; }); } }) $('#giegei717dplayer .dplayer-icons-right').prepend('<div class="dplayer-icon dplayer-reload-icon" data-balloon="刷新" data-balloon-pos="up">'+ '<span class="dplayer-icon-content"><svg width="24" height="22" xmlns="http://www.w3.org/2000/svg" >'+ '<path stroke="null" d="m3.06995,10.0686a0.7572,0.7696 0 0 1 0.7572,0.7696l0,0.3848c0,4.45446 3.6853,8.08083 8.2482,8.08083c2.08458,0 4.04346,-0.7596 5.54802,-2.10102l0.19384,-0.17778l0.27638,-0.2632a0.7572,0.7696 0 0 1 1.06993,0.03694l0.51717,0.56181a0.7572,0.7696 0 0 1 -0.03559,1.08822l-0.27714,0.26243c-1.94677,1.85012 -4.53791,2.9014 -7.29185,2.9014c-3.33926,0 -6.32036,-1.53844 -8.24896,-3.94037l0,0.86195a0.7572,0.7696 0 0 1 -0.7572,0.7696l-0.7572,0a0.7572,0.7696 0 0 1 -0.7572,-0.7696l0,-7.69603a0.7572,0.7696 0 0 1 0.7572,-0.7696l0.7572,0zm8.54729,-9.23523c3.2802,0 6.2083,1.52381 8.11115,3.90342l0,-0.82501a0.7572,0.7696 0 0 1 0.7572,-0.7696l0.7572,0a0.7572,0.7696 0 0 1 0.7572,0.7696l0,7.69603a0.7572,0.7696 0 0 1 -0.7572,0.7696l-0.7572,0a0.7572,0.7696 0 0 1 -0.7572,-0.7696l0,-0.3848c0,-4.45831 -3.627,-8.08083 -8.11115,-8.08083c-2.15045,0 -4.16385,0.83579 -5.66614,2.29803l-0.17794,0.17855l-0.26502,0.27475a0.7572,0.7696 0 0 1 -1.07144,0.00924l-0.53988,-0.53872a0.7572,0.7696 0 0 1 -0.00909,-1.08899l0.26502,-0.27475a10.43424,10.60512 0 0 1 7.46449,-3.16691z"></path>'+ '</svg></span>'+ '</div>') $('#giegei717dplayer .dplayer-icons-right>.dplayer-reload-icon').on('click',function(){ dpgiegei717.switchVideo({ url: url, type: type, }); dpgiegei717.play() }) } },50); function stopSet(){ clearInterval(set); } window.onresize = function () { w = window.innerWidth; h = window.innerHeight; $("#giegei717dplayer").parents("div[id^=layui-layer]").css({"max-width": w,"max-height": h } ) } } ,end: function(){ $(".But:nth-last-of-type(2)").text('播放') } } layer.close(index); unsafeWindow.dpgiegei717index = layer.open(conf) } function me(){ var conf1 = { formType: 0, title: "支持作者,你的支持就是作者的动力!", move: false, shadeClose: true, offset: '100px', resize: false, btn: ['点击关闭(点此关闭后以后不再自动弹出)'], area: weight1, content: "<h4 style='color:red'>注意:如果下载的视频不完整、缺少片段,可尝试在油猴扩展的脚本菜单中关闭视频下载去广告功能</h4><div id='giegei717dplayer' style='width: 500px;height: 500px;display:flex;align-items:center;justify-content:center;'><img src='https://greasyfork.s3.us-east-2.amazonaws.com/v7apofajl6mc0rte287otz3djpho' border='0' width='100%' height='100%' /></div>" ,success: function(layero, index){ $('layui-layer-btn .layui-layer-btn0').css({'border-color': '#1e9fff !important','background-color': '#1e9fff !important','color': '#fff !important'}) } ,yes: function(index, layero){ GM_setValue("first1",99); layer.close(index) } ,cancel: function(index, layero, that){ GM_setValue("first1",99); layer.close(index) } } layer.open(conf1) return } function FirstOpen(){ var one = GM_getValue("first1", 0) if(one==0){ me(); }; } })();