├── README.md ├── LICENSE ├── YouTube-PiP.js ├── VIP-002.js ├── Ins-download-images.js └── VIP-001.js /README.md: -------------------------------------------------------------------------------- 1 | # ZOE-User-Scripts 2 | User Scripts for ZOE video player pro 3 | 4 | [ZOE - Video Player PRO](https://apps.apple.com/us/app/zoe-video-player-pro/id1505277541) 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 简画大师 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /YouTube-PiP.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Youtube PiP Button 3 | // @author ACTCD 4 | // @version 20220311.3 5 | // @namespace https://t.me/ACTCD 6 | // @description Youtube Enable Picture-in-Picture ,not download 7 | // @match *://*.youtube.com/* 8 | // @grant none 9 | // @run-at document-start 10 | // ==/UserScript== 11 | 12 | (function () { 13 | 'use strict'; 14 | 15 | // Create PiP Button 16 | const i1 = 'url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2221%22%20height%3D%2225%22%3E%3Ctitle%3Epip_reduced%401x%3C%2Ftitle%3E%3Crect%20width%3D%2221%22%20height%3D%2225%22%20fill%3D%22none%22%2F%3E%3Cpath%20d%3D%22M2.5%2C17A1.5%2C1.5%2C0%2C0%2C1%2C1%2C15.5v-9A1.5%2C1.5%2C0%2C0%2C1%2C2.5%2C5h13A1.5%2C1.5%2C0%2C0%2C1%2C17%2C6.5V10h1V6.5A2.5%2C2.5%2C0%2C0%2C0%2C15.5%2C4H2.5A2.5%2C2.5%2C0%2C0%2C0%2C0%2C6.5v9A2.5%2C2.5%2C0%2C0%2C0%2C2.5%2C18H7V17Z%22%20fill%3D%22%23fff%22%2F%3E%3Cpath%20d%3D%22M18.5%2C11h-8A2.5%2C2.5%2C0%2C0%2C0%2C8%2C13.5v5A2.5%2C2.5%2C0%2C0%2C0%2C10.5%2C21h8A2.5%2C2.5%2C0%2C0%2C0%2C21%2C18.5v-5A2.5%2C2.5%2C0%2C0%2C0%2C18.5%2C11Z%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E")'; 17 | const i2 = 'url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2221%22%20height%3D%2225%22%3E%3Ctitle%3Epip.fill_reduced%401x%3C%2Ftitle%3E%3Crect%20width%3D%2221%22%20height%3D%2225%22%20fill%3D%22none%22%2F%3E%3Cpath%20d%3D%22M18.5%2C11H18v1h.5A1.5%2C1.5%2C0%2C0%2C1%2C20%2C13.5v5A1.5%2C1.5%2C0%2C0%2C1%2C18.5%2C20h-8A1.5%2C1.5%2C0%2C0%2C1%2C9%2C18.5V18H8v.5A2.5%2C2.5%2C0%2C0%2C0%2C10.5%2C21h8A2.5%2C2.5%2C0%2C0%2C0%2C21%2C18.5v-5A2.5%2C2.5%2C0%2C0%2C0%2C18.5%2C11Z%22%20fill%3D%22%23fff%22%2F%3E%3Cpath%20d%3D%22M14.5%2C4H2.5A2.5%2C2.5%2C0%2C0%2C0%2C0%2C6.5v8A2.5%2C2.5%2C0%2C0%2C0%2C2.5%2C17h12A2.5%2C2.5%2C0%2C0%2C0%2C17%2C14.5v-8A2.5%2C2.5%2C0%2C0%2C0%2C14.5%2C4Z%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E")'; 18 | const pip_button = document.createElement("button"); 19 | pip_button.title = "Picture-in-Picture"; 20 | pip_button.style.width = "50px"; 21 | pip_button.style.height = "50px"; 22 | if (location.hostname == "m.youtube.com") { 23 | pip_button.style.setProperty("position", "absolute"); 24 | pip_button.style.setProperty("z-index", "100"); 25 | } else { 26 | pip_button.className = "ytp-button"; 27 | } 28 | pip_button.style.setProperty("background-repeat", "no-repeat"); 29 | pip_button.style.setProperty("background-position", "50% 50%"); 30 | pip_button.style.setProperty("background-image", i1); 31 | const onEnterPip = e => pip_button.style.setProperty("background-image", i2); 32 | const onExitPip = e => pip_button.style.setProperty("background-image", i1); 33 | if (document.pictureInPictureEnabled) { 34 | pip_button.addEventListener("click", event => { 35 | if (document.pictureInPictureElement) { 36 | document.exitPictureInPicture(); 37 | } else { 38 | document.querySelector("video[src]")?.requestPictureInPicture(); 39 | } 40 | event.preventDefault(); 41 | event.stopImmediatePropagation(); 42 | }); 43 | } else { 44 | pip_button.style.setProperty("opacity", "0.5"); 45 | console.log('Your browser cannot use picture-in-picture right now'); 46 | } 47 | 48 | // Insert PiP Button (desktop) // Fixed once for Safari 49 | let b = document.querySelector(".ytp-miniplayer-button"); 50 | if (b) b.parentNode.insertBefore(pip_button, b); 51 | 52 | // Video element initialization 53 | const pip_init = video => { 54 | video.addEventListener('webkitpresentationmodechanged', e => e.stopPropagation(), true); // PiP Fix 55 | video.addEventListener("leavepictureinpicture", onExitPip); 56 | video.addEventListener('enterpictureinpicture', onEnterPip); 57 | } 58 | let v = document.querySelector('video[src]'); if (v) pip_init(v); // Fixed once for Safari 59 | 60 | // Dynamic adjustment 61 | new MutationObserver(mutationList => { 62 | mutationList.forEach((mutation) => { 63 | if (mutation.type == 'childList') { 64 | mutation.addedNodes.forEach(node => { 65 | if (node.nodeType != Node.ELEMENT_NODE) return; 66 | if (node.nodeName == 'VIDEO' && node.hasAttribute("src")) pip_init(node); 67 | if (node.id == "player-control-overlay") { // Insert PiP Button (mobile) 68 | new MutationObserver(() => { 69 | if (node.classList.contains("fadein")) { 70 | node.append(pip_button); 71 | } 72 | }).observe(node, { attributes: true }); 73 | } 74 | if (node.classList.contains("ytp-miniplayer-button")) { // Insert PiP Button (desktop) 75 | node.parentNode.insertBefore(pip_button, node); 76 | } 77 | }) 78 | } 79 | if (mutation.type == 'attributes') { // Enter video from the homepage 80 | if (mutation.target.nodeName == 'VIDEO' && mutation.attributeName == 'src' && mutation.target.hasAttribute("src")) { 81 | pip_init(mutation.target); 82 | } 83 | } 84 | }); 85 | }).observe(document, { subtree: true, childList: true, attributes: true }); 86 | 87 | })(); 88 | -------------------------------------------------------------------------------- /VIP-002.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 通用VIP视频解析 3 | // @author 河丶蟹 4 | // @version 2.2.9 5 | // @description 爱奇艺、腾讯视频、优酷、乐视、芒果TV、搜狐、1905、PPTV、B站。 6 | // @include * 7 | // @match * 8 | // @createTime 2021-03-03 12:00:47 9 | // @updateTime 2021-06-28 22:25:16 10 | // ==/UserScript== 11 | (function() { 12 | /* 13 | * 自定义区域 14 | * 变量值可自行更改 15 | */ 16 | // 主颜色(图标整体颜色,如方框颜色) 17 | const mianColor = "#de473c"; 18 | // 副颜色(图标层次颜色,如字体颜色) 19 | const secondColor = "#f3f1e7"; 20 | // 图标右边框距离 21 | const iconMarginRight = 2; 22 | // 图标上边框距离 23 | const iconMarginTop = 100; 24 | // 图标宽(最小30) 25 | var iconWidth = 45; 26 | // 图标高(图标大小) 27 | const iconHeight = 35; 28 | // 图标圆角比例(当高、宽一致时,0.5为圆圈) 29 | const iconFilletPercent = 0.3; 30 | // 解析接口菜单框展开的高度 31 | var developMenuHeight = 315; 32 | // 解析接口菜单框展开的速度(如果展开动画卡顿请设置0,单位是秒) 33 | var developMenuSecond = 0.2; 34 | // 解析接口(可多个) 35 | const parseInterfaces =["https://z1.m1907.cn/?eps=0&jx=","https://vip.parwix.com:4433/player/?url=","https://lecurl.cn/?url=","https://jx.m3u8.tv/jiexi/?url=","https://api.leduotv.com/wp-api/ifr.php?isDp=1&vid=","https://okjx.cc/?url=","https://m2090.com/?url=","http://51wujin.net/?url=","https://vip.2ktvb.com/player/?url=","https://660e.com/?url=","https://api.sigujx.com/?url=","https://jiexi.janan.net/jiexi/?url=","https://jx.618g.com/?url=","https://jx.ergan.top/?url=","https://api.147g.cc/m3u8.php?url=","http://17kyun.com/api.php?url="]; 36 | /* 37 | * 非自定义区域 38 | * 以下代码勿动 39 | * 以下代码勿动 40 | * 以下代码勿动 41 | */ 42 | // 视频网站(规则已定,不可随意更改) 43 | const videoSites = ["v.qq.com","tv.sohu.com","iqiyi.com","youku.com","mgtv.com","m.le.com","www.le.com","1905.com","pptv.com","bilibili.com"]; 44 | const currentUrl = document.location.href; 45 | // 判断是否加载后续代码 46 | if (self != top) { 47 | return; 48 | } 49 | var result = videoSites.some(site=>{ 50 | if (currentUrl.match(site)) { 51 | return true; 52 | } 53 | return false; 54 | }) 55 | if(!result){ 56 | return; 57 | } 58 | // 图标宽度最小值判断(小于30默认30) 59 | if(iconWidth<30){ 60 | iconWidth=30; 61 | } 62 | // 解析接口框高度判断(小于30默认30) 63 | if(developMenuHeight<(iconWidth*2.6)){ 64 | developMenuHeight=iconWidth*2.6; 65 | } 66 | // 判断PC、移动端 67 | var uaLogo="pc"; 68 | if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) { 69 | uaLogo="mobile"; 70 | } 71 | // 图标整体定位样式 72 | const globalStyle = "cursor:pointer;position:fixed;right:"+iconMarginRight+"px;top:"+iconMarginTop+"px;z-index:2147483647;"; 73 | // 主图标(矩形)样式 74 | const mainIconStyle = "height:"+iconHeight+"px;width:"+iconWidth+"px;background:"+mianColor+";border-radius:"+(iconFilletPercent*iconWidth)+"px;box-sizing:border-box;box-shadow:-4px 4px 4px 0px rgba(0,0,0,0.4);"; 75 | // 副图标(三角形)样式 76 | const triangleStyle = "border-left:"+(iconWidth*0.3)+"px solid "+secondColor+";border-top:"+(iconHeight*0.2)+"px solid transparent;border-bottom:"+(iconHeight*0.2)+"px solid transparent;position:absolute;right:31%;top:30%;"; 77 | // 副图标(正方形)样式 78 | const squareStyle = "background:"+secondColor+";width:"+(iconWidth*0.26)+"px;height:"+(iconWidth*0.26)+"px;position:absolute;right:37%;top:37%;"; 79 | // 菜单框外层样式 80 | const inMenuBoxStyle = "width:115%;height:100%;overflow-y:scroll;overflow-x:hidden;"; 81 | // 菜单框里层样式 82 | const outMenuBoxStyle = "background:"+mianColor+";height:0px;overflow:hidden;font-size:"+(iconWidth*0.4)+"px;width:"+(iconWidth*2.4)+"px;position:absolute;right:0px;top:"+iconHeight+"px;box-shadow:-4px 4px 4px 0px rgba(0,0,0,0.4);border-radius:13px 0 1px 13px;transition:height "+developMenuSecond+"s;-moz-transition:height "+developMenuSecond+"s;-webkit-transition:height "+developMenuSecond+"s;-o-transition:height "+developMenuSecond+"s;"; 83 | // 菜单项样式 84 | const MenuItemsStyle = "color:"+secondColor+";display: block;padding:"+(iconWidth*0.12)+"px "+(iconWidth*0.12)+"px "+(iconWidth*0.12)+"px "+(iconWidth*0.2)+"px ;width:"+(iconWidth*3)+"px;"; 85 | // Iframe样式 86 | const IframeStyle = "frameborder='no' width='100%' height='100%' allowfullscreen='true' allowtransparency='true' frameborder='0' scrolling='no';"; 87 | // 视频播放框类ID 88 | var classAndIDMap = {"pc":{"v.qq.com":"mod_player","iqiyi.com":"flashbox","youku.com":"ykPlayer","mgtv.com":"mgtv-player-wrap","sohu.com":"x-player","le.com":"fla_box","1905.com":"player","pptv.com":"pplive-player","bilibili.com":"bilibili-player-video-wrap|player-limit-mask"},"mobile":{"v.qq.com":"mod_player","iqiyi.com":"m-box","youku.com":"h5-detail-player","mgtv.com":"video-area","sohu.com":"player-view","le.com":"playB","1905.com":"player","pptv.com":"pp-details-video","bilibili.com":"bilibiliPlayer|player-wrapper"}}; 89 | // 创建图标 90 | createIcon(); 91 | // 判断页面加载完成以后图标是否存在 92 | document.onreadystatechange = function(){ 93 | if(document.readyState == 'complete'){ 94 | if(!document.getElementById("mainIcon")){ 95 | createIcon(); 96 | } 97 | } 98 | } 99 | function createIcon(){ 100 | try{ 101 | var div = document.createElement("div"); 102 | div.style.cssText = globalStyle; 103 | div.setAttribute("id","mainIcon"); 104 | var html = "
"; 113 | div.innerHTML = html; 114 | document.body.insertBefore(div,document.body.firstChild); 115 | div.onclick = function() { 116 | var dropDownBox = document.getElementById("dropDownBox").style.height; 117 | var mainButton = document.getElementById("mainButton"); 118 | var triangle = document.getElementById("triangle"); 119 | if(dropDownBox == "0px"){ 120 | mainButton.style.borderRadius = (iconFilletPercent*iconWidth)+"px "+(iconFilletPercent*iconWidth)+"px 0 0"; 121 | triangle.removeAttribute("style"); 122 | triangle.setAttribute("style",squareStyle); 123 | document.getElementById("dropDownBox").style.height = developMenuHeight+"px"; 124 | }else{ 125 | document.getElementById("dropDownBox").style.height = "0px"; 126 | triangle.removeAttribute("style"); 127 | triangle.setAttribute("style",triangleStyle); 128 | mainButton.style.borderRadius = (iconFilletPercent*iconWidth)+"px"; 129 | } 130 | } 131 | var elements = document.getElementsByClassName("spanStyle"); 132 | for(var j in elements){ 133 | elements[j].onmouseover = function(){ 134 | this.style.background = secondColor; 135 | this.style.color = mianColor; 136 | } 137 | elements[j].onmouseout = function(){ 138 | this.style.background = mianColor; 139 | this.style.color = secondColor; 140 | } 141 | elements[j].onclick=function(){ 142 | var parseInterface = this.getAttribute("url"); 143 | for(let key in classAndIDMap[uaLogo]){ 144 | if (document.location.href.match(key)) { 145 | var values = classAndIDMap[uaLogo][key].split("|"); 146 | var labelType = ""; 147 | var class_id = ""; 148 | for(let value in values){ 149 | if(document.getElementById(values[value])){ 150 | class_id = values[value]; 151 | labelType = "id"; 152 | break; 153 | } 154 | if(document.getElementsByClassName(values[value]).length>0){ 155 | class_id = values[value]; 156 | labelType = "class"; 157 | break; 158 | } 159 | } 160 | if(labelType!=""&&class_id!=""){ 161 | var iframe = ""; 162 | if(labelType=="id"){ 163 | document.getElementById(class_id).innerHTML=""; 164 | document.getElementById(class_id).innerHTML=iframe; 165 | }else{ 166 | document.getElementsByClassName(class_id)[0].innerHTML=""; 167 | if(uaLogo=="mobile"){ 168 | document.getElementsByClassName(class_id)[0].style.height="225px"; 169 | } 170 | document.getElementsByClassName(class_id)[0].innerHTML=iframe; 171 | } 172 | return; 173 | } 174 | } 175 | } 176 | document.getElementById("dropDownBox").style.display = "none"; 177 | } 178 | } 179 | }catch(error){ 180 | // exception handling 181 | } 182 | } 183 | })(); 184 | -------------------------------------------------------------------------------- /Ins-download-images.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Instagram Download Button 3 | // @name:zh-TW Instagram 下載器 4 | // @name:zh-CN Instagram 下载器 5 | // @name:ja Instagram ダウンローダー 6 | // @name:ko Instagram 다운로더 7 | // @name:es Descargador de Instagram 8 | // @name:fr Téléchargeur Instagram 9 | // @name:hi इंस्टाग्राम डाउनलोडर 10 | // @name:ru Загрузчик Instagram 11 | // @namespace https://github.com/y252328/Instagram_Download_Button 12 | // @version 1.9.7 13 | // @compatible chrome 14 | // @compatible firefox 15 | // @compatible edge 16 | // @description Add the download button and the open button to download or open profile picture and media in the posts, stories, and highlights in Instagram 17 | // @description:zh-TW 在Instagram頁面加入下載按鈕與開啟按鈕,透過這些按鈕可以下載或開啟大頭貼與貼文、限時動態、Highlight中的照片或影片 18 | // @description:zh-CN 在Instagram页面加入下载按钮与开启按钮,透过这些按钮可以下载或开启大头贴与贴文、限时动态、Highlight中的照片或影片 19 | // @description:ja メディアをダウンロードまたは開くためのボタンを追加します 20 | // @description:ko 미디어를 다운로드하거나 여는 버튼을 추가합니다 21 | // @description:es Agregue botones para descargar o abrir medios 22 | // @description:fr Ajoutez des boutons pour télécharger ou ouvrir des médias 23 | // @description:hi मीडिया को डाउनलोड या खोलने के लिए बटन जोड़ें। 24 | // @description:ru Добавьте кнопки для загрузки или открытия медиа 25 | // @author ZhiYu 26 | // @match https://www.instagram.com/* 27 | // @grant none 28 | // @license MIT 29 | // ==/UserScript== 30 | 31 | (function () { 32 | 'use strict'; 33 | // ================= 34 | // = Options = 35 | // ================= 36 | const attachLink = true; // add link into the button elements 37 | const postFilenameTemplate = "%id%-%datetime%-%medianame%.%ext%"; 38 | const storyFilenameTemplate = postFilenameTemplate; 39 | 40 | // ================== 41 | 42 | function yyyymmdd(date) { 43 | // ref: https://stackoverflow.com/questions/3066586/get-string-in-yyyymmdd-format-from-js-date-object?page=1&tab=votes#tab-top 44 | var mm = date.getMonth() + 1; // getMonth() is zero-based 45 | var dd = date.getDate(); 46 | 47 | return [date.getFullYear(), 48 | (mm > 9 ? '' : '0') + mm, 49 | (dd > 9 ? '' : '0') + dd 50 | ].join(''); 51 | } 52 | 53 | var svgDownloadBtn = 54 | ` 56 | 57 | 60 | 61 | 62 | 66 | 67 | `; 68 | 69 | var svgNewtabBtn = 70 | ` 71 | 72 | `; 73 | 74 | document.addEventListener('keydown', keyDownHandler); 75 | 76 | function keyDownHandler(event) { 77 | if (window.location.href === 'https://www.instagram.com/') return; 78 | 79 | if (event.altKey && event.key === 'k') { 80 | let buttons = document.getElementsByClassName('download-btn'); 81 | if (buttons.length > 0) { 82 | let mockEvent = { currentTarget: buttons[buttons.length - 1] }; 83 | if (attachLink) onMouseInHandler(mockEvent); 84 | onClickHandler(mockEvent); 85 | } 86 | } 87 | if (event.altKey && event.key === 'i') { 88 | let buttons = document.getElementsByClassName('newtab-btn'); 89 | if (buttons.length > 0) { 90 | let mockEvent = { currentTarget: buttons[buttons.length - 1] }; 91 | if (attachLink) onMouseInHandler(mockEvent); 92 | onClickHandler(mockEvent); 93 | } 94 | } 95 | 96 | if (event.altKey && event.key === 'l') { 97 | // right arrow 98 | let buttons = document.getElementsByClassName('coreSpriteRightChevron'); 99 | if (buttons.length > 0) { 100 | buttons[0].click(); 101 | } 102 | } 103 | 104 | if (event.altKey && event.key === 'j') { 105 | // left arrow 106 | let buttons = document.getElementsByClassName('coreSpriteLeftChevron'); 107 | if (buttons.length > 0) { 108 | buttons[0].click(); 109 | } 110 | } 111 | } 112 | 113 | var checkExistTimer = setInterval(function () { 114 | let sharePostSelector = "article section span button"; 115 | let storySeletor = "header button > div"; 116 | let profileSelector = "header section svg circle"; 117 | 118 | // check profile 119 | if (document.getElementsByClassName("custom-btn").length === 0) { 120 | if (document.querySelector(profileSelector)) { 121 | addCustomBtn(document.querySelector(profileSelector), "black", append2Header); 122 | } 123 | } 124 | 125 | // check post 126 | let articleList = document.querySelectorAll("article"); 127 | for (let i = 0; i < articleList.length; i++) { 128 | if (articleList[i].querySelector(sharePostSelector) && 129 | articleList[i].getElementsByClassName("custom-btn").length === 0) { 130 | addCustomBtn(articleList[i].querySelector(sharePostSelector), "black", append2Post); 131 | } 132 | } 133 | 134 | // check story 135 | if (document.getElementsByClassName("custom-btn").length === 0) { 136 | if (document.querySelector(storySeletor)) { 137 | addCustomBtn(document.querySelector(storySeletor), "white", append2Post); 138 | } 139 | } 140 | }, 500); 141 | 142 | function append2Header(node, btn) { 143 | node.parentNode.parentNode.parentNode.appendChild(btn, node.parentNode.parentNode); 144 | } 145 | 146 | function append2Post(node, btn) { 147 | node.parentNode.parentNode.appendChild(btn); 148 | } 149 | 150 | function addCustomBtn(node, iconColor, appendNode) { 151 | // add download button and set onclick handler 152 | // add newtab button 153 | let newtabBtn = createCustomBtn(svgNewtabBtn, iconColor, "newtab-btn", "16px"); 154 | appendNode(node, newtabBtn); 155 | 156 | // add download button 157 | let downloadBtn = createCustomBtn(svgDownloadBtn, iconColor, "download-btn", "14px"); 158 | appendNode(node, downloadBtn); 159 | } 160 | 161 | function createCustomBtn(svg, iconColor, className, marginLeft) { 162 | let newBtn = document.createElement("a"); 163 | newBtn.innerHTML = svg.replace('%color', iconColor); 164 | newBtn.setAttribute("class", "custom-btn " + className); 165 | newBtn.setAttribute("target", "_blank"); 166 | newBtn.setAttribute("style", "cursor: pointer;margin-left: " + marginLeft + ";margin-top: 8px;"); 167 | newBtn.onclick = onClickHandler; 168 | if (attachLink) newBtn.onmouseenter = onMouseInHandler; 169 | if (className.includes("newtab")) { 170 | newBtn.setAttribute("title", "Open in new tab"); 171 | } else { 172 | newBtn.setAttribute("title", "Download"); 173 | } 174 | return newBtn; 175 | } 176 | 177 | function onClickHandler(e) { 178 | // handle button click 179 | let target = e.currentTarget; 180 | e.stopPropagation(); 181 | e.preventDefault(); 182 | if (window.location.pathname.includes('stories')) { 183 | storyOnClicked(target); 184 | } else if (document.querySelector('header') && 185 | document.querySelector('header').contains(target)) { 186 | profileOnClicked(target); 187 | } else { 188 | postOnClicked(target); 189 | } 190 | } 191 | 192 | function onMouseInHandler(e) { 193 | if (!attachLink) return; 194 | let target = e.currentTarget; 195 | if (window.location.pathname.includes('stories')) { 196 | storyOnMouseIn(target); 197 | } else if (document.querySelector('header') && 198 | document.querySelector('header').contains(target)) { 199 | profileOnMouseIn(target); 200 | } else { 201 | postOnMouseIn(target); 202 | } 203 | } 204 | 205 | function profileOnMouseIn(target) { 206 | let url = profileGetUrl(target); 207 | target.setAttribute("href", url); 208 | } 209 | 210 | function profileOnClicked(target) { 211 | // extract profile picture url and download or open it 212 | let url = profileGetUrl(target); 213 | let filename = '.png'; 214 | 215 | if (url.length > 0) { 216 | // check url 217 | if (target.getAttribute("class").includes("download-btn")) { 218 | // generate filename 219 | let posterName = document.querySelector('header h2').textContent; 220 | filename = posterName + filename; 221 | downloadResource(url, filename); 222 | } else { 223 | // open url in new tab 224 | openResource(url); 225 | } 226 | } 227 | } 228 | 229 | function profileGetUrl(target) { 230 | let img = document.querySelector('header img'); 231 | let url = img.getAttribute('src'); 232 | return url; 233 | } 234 | 235 | async function postOnMouseIn(target) { 236 | let articleNode = postGetArticleNode(target); 237 | let url = await postGetUrl(target, articleNode); 238 | target.setAttribute("href", url); 239 | } 240 | 241 | async function postOnClicked(target) { 242 | // extract url from target post and download or open it 243 | let articleNode = postGetArticleNode(target); 244 | let url = await postGetUrl(target, articleNode); 245 | 246 | // ============================== 247 | // = download or open media url = 248 | // ============================== 249 | if (url.length > 0) { 250 | // check url 251 | if (target.getAttribute("class").includes("download-btn")) { 252 | let mediaName = url.split('?')[0].split('\\').pop().split('/').pop(); 253 | let ext = mediaName.substr(mediaName.lastIndexOf('.') + 1); 254 | mediaName = mediaName.substring(0, mediaName.lastIndexOf('.')); 255 | let datetime = new Date(articleNode.querySelector('time').getAttribute('datetime')); 256 | datetime = yyyymmdd(datetime) + '_' + datetime.toTimeString().split(' ')[0].replace(/:/g, ''); 257 | let posterName = articleNode.querySelector('header a').getAttribute('href').replace(/\//g, ''); 258 | let filename = filenameFormat(postFilenameTemplate, posterName, datetime, mediaName, ext); 259 | downloadResource(url, filename); 260 | } else { 261 | // open url in new tab 262 | openResource(url); 263 | } 264 | } 265 | } 266 | 267 | function postGetArticleNode(target) { 268 | let articleNode = target; 269 | while (articleNode && articleNode.tagName !== "ARTICLE") { 270 | articleNode = articleNode.parentNode; 271 | } 272 | return articleNode; 273 | } 274 | 275 | async function postGetUrl(target, articleNode) { 276 | // meta[property="og:video"] 277 | let list = articleNode.querySelectorAll('li[style][class]'); 278 | let url = ""; 279 | if (list.length === 0) { 280 | // single img or video 281 | if (articleNode.querySelector('article div > video')) { 282 | let videoElem = articleNode.querySelector('article div > video'); 283 | url = videoElem.getAttribute('src'); 284 | if (videoElem.hasAttribute('videoURL')) { 285 | url = videoElem.getAttribute('videoURL'); 286 | } else if (url === null || url.includes('blob')) { 287 | url = await fetchVideoURL(articleNode, videoElem); 288 | } 289 | } else if (articleNode.querySelector('article div[role] div > img')) { 290 | url = articleNode.querySelector('article div[role] div > img').getAttribute('src'); 291 | } else { 292 | console.log("Err: not find media at handle post single"); 293 | } 294 | } else { 295 | // multiple imgs or videos 296 | let idx = 0; 297 | // check current index 298 | if (!articleNode.querySelector('.coreSpriteLeftChevron')) { 299 | idx = 0; 300 | } else if (!articleNode.querySelector('.coreSpriteRightChevron')) { 301 | idx = list.length - 1; 302 | } else idx = 1; 303 | 304 | let node = list[idx]; 305 | if (node.querySelector('video')) { 306 | let videoElem = node.querySelector('video'); 307 | url = videoElem.getAttribute('src'); 308 | if (videoElem.hasAttribute('videoURL')) { 309 | url = videoElem.getAttribute('videoURL'); 310 | } else if (url === null || url.includes('blob')) { 311 | url = await fetchVideoURL(articleNode, videoElem); 312 | } 313 | } else if (node.querySelector('img')) { 314 | url = node.querySelector('img').getAttribute('src'); 315 | } 316 | } 317 | return url 318 | } 319 | 320 | async function fetchVideoURL(articleNode, videoElem) { 321 | let poster = videoElem.getAttribute('poster'); 322 | let timeNodes = articleNode.querySelectorAll('time'); 323 | // special thanks 孙年忠 (https://greasyfork.org/en/scripts/406535-instagram-download-button/discussions/120159) 324 | let posterUrl = timeNodes[timeNodes.length - 1].parentNode.parentNode.href; 325 | let posterPattern = /\/([^\/?]*)\?/; 326 | let posterMatch = poster.match(posterPattern); 327 | let postFileName = posterMatch[1]; 328 | // special thanks to 孙年忠 for the pattern (https://greasyfork.org/zh-TW/scripts/406535-instagram-download-button/discussions/116675) 329 | let pattern = new RegExp(`${postFileName}.*?video_versions.*?url":("[^"]*")`, 's'); 330 | let resp = await fetch(posterUrl); 331 | let content = await resp.text(); 332 | let match = content.match(pattern); 333 | let videoUrl = JSON.parse(match[1]); 334 | videoUrl = videoUrl.replace(/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/?\n]+)/g, 'https://scontent.cdninstagram.com'); 335 | videoElem.setAttribute('videoURL', videoUrl); 336 | return videoUrl; 337 | } 338 | 339 | function storyOnMouseIn(target) { 340 | let sectionNode = storyGetSectionNode(target); 341 | let url = storyGetUrl(target, sectionNode); 342 | target.setAttribute('href', url); 343 | } 344 | 345 | function storyOnClicked(target) { 346 | // extract url from target story and download or open it 347 | let sectionNode = storyGetSectionNode(target); 348 | let url = storyGetUrl(target, sectionNode); 349 | 350 | // ============================== 351 | // = download or open media url = 352 | // ============================== 353 | if (target.getAttribute("class").includes("download-btn")) { 354 | let mediaName = url.split('?')[0].split('\\').pop().split('/').pop(); 355 | let ext = mediaName.substr(mediaName.lastIndexOf('.') + 1); 356 | mediaName = mediaName.substring(0, mediaName.lastIndexOf('.')); 357 | let datetime = new Date(sectionNode.querySelector('time').getAttribute('datetime')); 358 | datetime = yyyymmdd(datetime) + '_' + datetime.toTimeString().split(' ')[0].replace(/:/g, ''); 359 | let posterName = sectionNode.querySelector('header a').getAttribute('href').replace(/\//g, ''); 360 | 361 | let filename = filenameFormat(storyFilenameTemplate, posterName, datetime, mediaName, ext); 362 | downloadResource(url, filename); 363 | } else { 364 | // open url in new tab 365 | openResource(url); 366 | } 367 | } 368 | 369 | function storyGetSectionNode(target) { 370 | let sectionNode = target; 371 | while (sectionNode && sectionNode.tagName !== "SECTION") { 372 | sectionNode = sectionNode.parentNode; 373 | } 374 | return sectionNode; 375 | } 376 | 377 | function storyGetUrl(target, sectionNode) { 378 | let url = ""; 379 | if (sectionNode.querySelector('video > source')) { 380 | url = sectionNode.querySelector('video > source').getAttribute('src'); 381 | } else if (sectionNode.querySelector('img[decoding="sync"]')) { 382 | let img = sectionNode.querySelector('img[decoding="sync"]'); 383 | url = img.srcset.split(/ \d+w/g)[0].trim(); // extract first src from srcset attr. of img 384 | if (url.length > 0) { 385 | return url; 386 | } 387 | url = sectionNode.querySelector('img[decoding="sync"]').getAttribute('src'); 388 | } 389 | return url; 390 | } 391 | 392 | function filenameFormat(template, id, datetime, medianame, ext) { 393 | let filename = template; 394 | filename = filename.replaceAll("%id%", id); 395 | filename = filename.replaceAll("%datetime%", datetime); 396 | filename = filename.replaceAll("%medianame%", medianame); 397 | filename = filename.replaceAll("%ext%", ext); 398 | return filename; 399 | } 400 | 401 | function openResource(url) { 402 | // open url in new tab 403 | var a = document.createElement('a'); 404 | a.href = url; 405 | a.setAttribute("target", "_blank"); 406 | document.body.appendChild(a); 407 | a.click(); 408 | a.remove(); 409 | } 410 | 411 | function forceDownload(blob, filename) { 412 | // ref: https://stackoverflow.com/questions/49474775/chrome-65-blocks-cross-origin-a-download-client-side-workaround-to-force-down 413 | var a = document.createElement('a'); 414 | a.download = filename; 415 | a.href = blob; 416 | // For Firefox https://stackoverflow.com/a/32226068 417 | document.body.appendChild(a); 418 | a.click(); 419 | a.remove(); 420 | } 421 | 422 | // Current blob size limit is around 500MB for browsers 423 | function downloadResource(url, filename) { 424 | // ref: https://stackoverflow.com/questions/49474775/chrome-65-blocks-cross-origin-a-download-client-side-workaround-to-force-down 425 | if (!filename) filename = url.split('\\').pop().split('/').pop(); 426 | fetch(url, { 427 | headers: new Headers({ 428 | 'Origin': location.origin 429 | }), 430 | mode: 'cors' 431 | }) 432 | .then(response => response.blob()) 433 | .then(blob => { 434 | let blobUrl = window.URL.createObjectURL(blob); 435 | forceDownload(blobUrl, filename); 436 | }) 437 | .catch(e => console.error(e)); 438 | } 439 | })(); 440 | -------------------------------------------------------------------------------- /VIP-001.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 全网VIP视频自动解析蓝光播放器(已适配苹果,安卓,PC端) 3 | // @namespace https://www.tampermonkey.net/ 4 | // @version 1.1.8.8 5 | // @license AGPL-3.0 6 | // @description 无需跳转新网址,打开官网直接看,蓝光 4k 无广告 随机去水印。支持:腾讯,爱奇艺,优酷,哔哩哔哩,咪咕,乐视,搜狐,芒果,西瓜,PPTV,1905电影网,华数。支持解析失败自动切换推荐解析源。适配各种浏览器。 7 | // @description 新增加视频嗅探,m3u8视频下载 视频下载转mp4(该功能目前只试配PC端) 8 | // @author Tenfond 9 | // @match *://v.qq.com/* 10 | // @match *://m.v.qq.com/* 11 | // @match *://www.iqiyi.com/* 12 | // @match *://m.iqiyi.com/* 13 | // @match *://*.youku.com/* 14 | // @match *://*.bilibili.com/* 15 | // @match *://*.miguvideo.com/* 16 | // @match *://*.le.com/* 17 | // @match *://tv.sohu.com/* 18 | // @match *://film.sohu.com/* 19 | // @match *://m.tv.sohu.com/* 20 | // @match *://*.mgtv.com/* 21 | // @match *://*.ixigua.com/* 22 | // @match *://*.pptv.com/* 23 | // @match *://vip.1905.com/* 24 | // @match *://www.wasu.cn/* 25 | // @include *://*.*/*url=http*://*.*.*/* 26 | // @include *://*.*:*/*url=http*://*.*.*/* 27 | // @include *://*.*/*v=http*://*.*.*/* 28 | // @include *://*.*:*/*v=http*://*.*.*/* 29 | // @match *://api.leduotv.com/*?vid=* 30 | // @grant GM_getValue 31 | // @grant GM_setValue 32 | // @run-at document-body 33 | // ==/UserScript== 34 | /** 35 | * 任务清单: 36 | */ 37 | 38 | // 读取配置后执行 39 | function readSettings() { 40 | // 获取框架循环时间,CPU性能好的可以设置为100,CPU性能不好的可以设置为1000 41 | settings.getElementTimes = 500; 42 | // log输出字体布局 43 | settings.fontStyle = { 44 | error: "font-family: 微软雅黑,黑体,Droid Serif,Arial,sans-serif; color: #f00;", 45 | warn: "font-family: 微软雅黑,黑体,Droid Serif,Arial,sans-serif; color: #ff0;", 46 | ok: "font-family: 微软雅黑,黑体,Droid Serif,Arial,sans-serif; color: #0f0;", 47 | maxTip: "font-family: 微软雅黑,黑体,Droid Serif,Arial,sans-serif; font-size: 30px; background-color: #222; text-shadow: 0px 0px 12px #fff; color: #fff;" 48 | }; 49 | 50 | if (window === top) { 51 | /* 52 | * (): 小括号括住的表示推荐解析 画质高 速度快 53 | * : 无括号的表示视频带水印 或 原页面画质 54 | * []: 方括号表示标清画质 不推荐 55 | */ 56 | settings.NoAD解析 = { // TODO by 17kyun.com/api.php?url= // TODO by tv.hzwdd.cn 57 | // 你可以在这里定义自己的解析接口,脚本会自动适配。格式如下: 58 | // "解析名称": "解析接口的链接", // TODO 注意 : 和 " 以及 , 都是英文的符号。 59 | "PPJ蓝光解析": "https://bf.ppjbk.cn/?url=", // TODO 腾讯 (芒果) 60 | "PPJ解析": "https://jx.ppjbk.cn/?url=", // TODO 腾讯 (芒果) (B站) 61 | "PPJ弹幕解析2": "https://bf.ppjbk.cn/bf/?url=", // TODO 腾讯 (芒果) 62 | "OK解析": "https://api.okjx.cc:3389/jx.php?url=" || "https://okjx.cc/?url=" || "https://m2090.com/?url=", // TODO 优质: 腾讯 (爱奇艺) 优酷 乐视 芒果 PPTV (华数) 63 | "全民解析": "https://jx.quanmingjiexi.com/?url=" || "https://chaxun.truechat365.com/?url=", // TODO (腾讯) 64 | "云解析": "https://jx.aidouer.net/?url=" || "https://jx.ppflv.com/?url=", // TODO 腾讯 [爱奇艺] 优酷 (乐视) 芒果 (1905电影网) [华数] 65 | "天翼解析": "https://jsap.attakids.com/?url=" || "https://www.qianyicp.com/vip/vip_g.php?url=", // _4K解析: "", // TODO 腾讯 爱奇艺 (优酷) 咪咕 乐视 (芒果) 西瓜 PPTV 66 | "虾米解析": "https://jx.xmflv.com/?url=", // TODO (土豆) (咪咕) 搜狐 (芒果) 67 | "九八看解析": "https://jx.ap2p.cn/?url=", // (Parwix解析: "https://jx.parwix.com:4433/player/analysis.php?v=" || "https://vip.parwix.com:4433/player/?url=" || ) // TODO (西瓜) (B站) (搜狐) (芒果) 68 | "夜幕解析": "https://www.yemu.xyz/?url=", // TODO 土豆 华数 芒果:可能有广告 // by www.yunboys.cn 69 | "new1": "https://jx.xl6.top/cache.php?url=", 70 | "new2": "https://jx.xl6.top/fp/?url=", 71 | "new3": "https://jx.xl6.top/dp/?url=", 72 | "new4": "https://dm.xl6.top/?url=", 73 | "new5": "https://vip.parwix.com:4433/player/analysis.php?v=", 74 | "new6": "https://jx.fulitang365.com/?url=", 75 | "new7": "https://www.nxflv.com/?url=", 76 | "new8": "https://jsap.attakids.com/?url=", 77 | "new9": "https://jx.xiaoxiong.me/?url=" 78 | }; 79 | settings.AD解析 = { // TODO (有赌博广告,请勿相信,这么简单的骗术不会有人上当吧) 80 | "z1解析": "https://z1.m1907.cn?jx=", 81 | "乐多解析": "https://api.leduotv.com/wp-api/ifr.php?isDp=1&vid=", // TODO (B站) 82 | "Parwix解析": "https://jx.parwix.com:4433/player/?url=" // TODO 无水印(但不稳定): 腾讯 爱奇艺 优酷 乐视 [芒果] (PPTV) (华数) 83 | }; 84 | start(); 85 | } else if (settings.isParse) { 86 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00给予\x000\x00" + location.href, settings.k1, settings.k2), "*"); 87 | Object.defineProperty(console, "clear", { 88 | value: () => console.log("%c禁止清除控制台", settings.fontStyle.error), writable: false 89 | }); 90 | settings.parseDB = new Promise(resolve => { 91 | window.addEventListener("message", event => { 92 | if (event.source !== window) { 93 | try { 94 | let sql = key.DECRYPT(event.data, settings.k1, settings.k2).split("\x00"); 95 | if (sql[0] === "天王盖地虎") { 96 | if (sql[1] === "给予") { 97 | if (sql[2] === "用户数据库") { 98 | resolve(JSON.parse(sql[3])); 99 | } 100 | } 101 | } 102 | } catch (e) { 103 | // 排除 下标越界错误 及 指令处理错误 104 | } 105 | } 106 | }); 107 | }); 108 | // 需要先监听再发送数据 109 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00请求\x00用户数据库", settings.k1, settings.k2), "*"); 110 | start(); 111 | } 112 | } 113 | 114 | // 未经许可禁止抄袭算法,可以私用。 115 | const key = (() => { 116 | // 新方案定义私有变量。修复部分浏览器不支持 # 定义private私有变量 117 | const password = Symbol(); 118 | const randomkey = Symbol(); 119 | 120 | // 自定义加密算法,以防数据包被破解。 121 | class key { 122 | // _pwd; // 火狐v68版本貌似不支持这种方式声明变量。 123 | 124 | constructor(pwd = null) { 125 | // num,密码偏移量 126 | // key,排列长度偏移量 127 | // charCode,防止内存频繁运动,定义在外部 128 | let num = 7, charCode, key = 7; 129 | if (pwd) { 130 | if (typeof pwd === "string") { 131 | for (let i = 0; i < pwd.length; i++) { 132 | // 将pwd中 每个字 转换成 十进制ASCII值 133 | charCode = pwd[i].charCodeAt(); 134 | // 将每个 ASCII值 中 第一个值加入到 排列长度偏移量 135 | key += parseInt(charCode.toString()[0]); 136 | // 用 hash算法 将 ASCII值 减去 31 作为新的值加入到num中 137 | // 以下方法是为了防止出现负数,ASCII字符集一共有65536个字符 138 | // num += charCode - 31 => (charCode + 65505) % 65536 139 | num = 31 * num + (charCode + 65505) % 65536; 140 | } 141 | } else if (typeof pwd === "number") { 142 | // 如果密码是数值型就使用此方法作为 密码偏移量 和 排列长度偏移量 143 | num = key = 7 + parseInt(Math.abs(pwd)); 144 | } else { 145 | // 如果类型不匹配就直接提出错误 146 | console.error("Unsupported type '" + (typeof pwd) + "'. It only supports 'string' or 'number'.") 147 | } 148 | } 149 | // 让排列长度偏移量的转换成8进制,取第一个数字。加上密码转换成字符字符串的方式。数值+字符串 会将数值自动转换为字符串 150 | this[password] = key.toString(8)[0] + (num % 65536).toString(); 151 | } 152 | 153 | encrypt(string) { 154 | if (string) { 155 | // subStart 排列长度的起始位置。subIndex 排列长度。 encryptPool 加密池,即去除的排列长度存放在这里。result 加密后的结果。 156 | let subStart = string.length, subIndex = parseInt(this[password][0]) + 3, encryptPool = [], result = ""; 157 | // stringKey 加密字符偏移量的散列值的的个数。 158 | let stringKey = subStart + parseInt(this[password].substring(1)); 159 | // stringKeyFloat 加密字符偏移量的偏移单位。stringKeyIndex 加密字符偏移量的位置 160 | let stringKeyFloat = 65536 / stringKey, stringKeyIndex = stringKey - 1; 161 | // 获取加密池。 162 | while (subStart > subIndex) { 163 | subStart -= subIndex; 164 | encryptPool.push(string.substr(subStart, subIndex)); 165 | } 166 | encryptPool.push(string.substring(0, subStart)); 167 | // 对加密池进行加密,并将加密的字符的结果放入 result 中。 168 | for (let i = 0, j; i < subIndex; i++) { 169 | for (j = 0; j < encryptPool.length; j++) { 170 | let char = encryptPool[j][i]; 171 | if (char) { 172 | // 将字符的 ASCII值 偏移 指定量 173 | result += String.fromCharCode((char.charCodeAt() + parseInt(stringKeyFloat * (stringKeyIndex % 2 === 0 ? stringKeyIndex : stringKey - stringKeyIndex))) % 65536); 174 | stringKeyIndex = stringKeyIndex === 0 ? stringKey - 1 : stringKeyIndex - 1; 175 | } else { 176 | break; 177 | } 178 | } 179 | } 180 | // 返回加密结果 181 | return result; 182 | } else { 183 | // 如果加密字符串不存在就返回空字符串 184 | return ""; 185 | } 186 | } 187 | 188 | /* 假设有7个字符 189 | 190 | 加密前 - 排列 191 | ( 1 ) ( 2 3 ) ( 4 5 ) ( 6 7 ) 192 | 193 | 加密中 - 排列 194 | ︵ ︵ ︵ ︵ 195 | 6 4 2 1 196 | 7 5 3 ︶ 197 | ︶ ︶ ︶ 198 | 加密后 - 排列 199 | ( 6 4 2 1 ) ( 7 5 3 ) 200 | 201 | 解密中 - 排列 202 | ︵ ︵ 203 | 6 7 204 | 4 5 205 | 2 3 206 | 1 ︶ 207 | ︶ 208 | 解密后 - 排列 209 | 1 2 3 4 5 6 7 8 210 | */ 211 | 212 | decrypt(string) { 213 | if (string) { 214 | // subStart 排列长度的起始位置。desubIndex 反向取加密池的长度。 decryptPool 解密池。 215 | let subStart = 0, desubIndex = Math.ceil(string.length / (parseInt(this[password][0]) + 3)), 216 | //NullCount 加密池中最后一个元素的元素空位。 desubIndex 反向取加密池的长度。 decryptPool 解密池,result 解密后的结果。 217 | NullCount = string.length % (parseInt(this[password][0]) + 3), decryptPool = [], result = ""; 218 | // stringKey 加密字符偏移量的散列值的的个数。 219 | let stringKey = string.length + parseInt(this[password].substring(1)), // stringKeyFloat 加密字符偏移量的偏移单位。stringKeyIndex 加密字符偏移量的位置 220 | stringKeyFloat = 65536 / stringKey, stringKeyIndex; 221 | // 获取解密池 222 | while (string.length - subStart > desubIndex) { 223 | decryptPool.push(string.substr(subStart, desubIndex)); 224 | subStart += desubIndex; 225 | if (decryptPool.length === NullCount) { 226 | desubIndex--; 227 | } 228 | } 229 | decryptPool.push(string.substring(subStart)); 230 | // 对解密池进行解密 并将解密结果 加入到 result(结果) 中 231 | for (let j = decryptPool[0].length - 1, i; j > -1; j--) { 232 | // 为节省NullCount的空间利用,使用NullCount用来辅助计算 stringKeyIndex(加密字符偏移量的位置) 的位置 233 | // 画图排列就知道为什么要这样做了,上面做了一个加密到解密的排列的草图 234 | NullCount = 0; 235 | for (i = 0; i < decryptPool.length; i++) { 236 | let char = decryptPool[i][j]; 237 | if (char) { 238 | NullCount += decryptPool[i].length; 239 | // 计算得到当前字符的位置 240 | stringKeyIndex = NullCount - decryptPool[i].length + j + 1; 241 | // 计算得到 stringKeyIndex(加密字符偏移量的位置) 的位置 242 | stringKeyIndex = (stringKey - stringKeyIndex % stringKey) % stringKey; 243 | // 让加密后的偏移量,偏移回去,得到原先的字符串 244 | result += String.fromCharCode((char.charCodeAt() - parseInt(stringKeyFloat * (stringKeyIndex % 2 === 0 ? stringKeyIndex : stringKey - stringKeyIndex)) + 65536) % 65536); 245 | } 246 | } 247 | } 248 | // 返回解密结果 249 | return result; 250 | } else { 251 | // 如果解密字符串不存在就返回空字符串 252 | return ""; 253 | } 254 | } 255 | 256 | // encrypt 既可以用作加密 也可以用作解密,decrypt 既可以用作解密 也可以用作加密。 257 | 258 | static ENCRYPT() { 259 | if (arguments) { 260 | let strings = [], keys = []; 261 | for (let i = 0; i < arguments.length; i++) { 262 | // JavaScript如何用最简单的方法获取任意对象的类名?(包括自定义类) 判断对象类型? 263 | // 欢迎支持我的原创文档 https://blog.csdn.net/qq_37759464/article/details/121764755 264 | if (arguments[i].constructor.name === "key") { 265 | keys.push(arguments[i]); 266 | } else if (arguments[i].constructor.name === "String") { 267 | strings.push(arguments[i]); 268 | } 269 | } 270 | if (strings) { 271 | if (keys) { 272 | for (let i = 0, j; i < strings.length; i++) { 273 | for (j = 0; j < keys.length; j++) { 274 | strings[i] = i % 2 === 0 ? keys[j].encrypt(strings[i]) : keys[j].decrypt(strings[i]); 275 | } 276 | } 277 | return strings.length === 1 ? strings[0] : strings; 278 | } else { 279 | if (!this[randomkey]) { 280 | this[randomkey] = new key(parseInt(Math.random() * 1024) + 3); 281 | } 282 | // 为了使加密方法不一样,这里反过来 283 | strings[i] = this[randomkey].decrypt(this[randomkey].decrypt(strings[i])); 284 | return strings.length === 1 ? strings[0] : strings; 285 | } 286 | } 287 | } 288 | } 289 | 290 | static DECRYPT() { 291 | if (arguments) { 292 | let strings = [], keys = []; 293 | for (let i = 0; i < arguments.length; i++) { 294 | if (arguments[i].constructor.name === "key") { 295 | keys.push(arguments[i]); 296 | } else if (arguments[i].constructor.name === "String") { 297 | strings.push(arguments[i]); 298 | } 299 | } 300 | if (strings) { 301 | if (keys) { 302 | for (let i = 0, j; i < strings.length; i++) { 303 | for (j = keys.length - 1; j > -1; j--) { 304 | strings[i] = i % 2 === 0 ? keys[j].decrypt(strings[i]) : keys[j].encrypt(strings[i]); 305 | } 306 | } 307 | return strings.length === 1 ? strings[0] : strings; 308 | } else { 309 | if (!this[randomkey]) { 310 | this[randomkey] = new key(parseInt(Math.random() * 1024) + 3); 311 | } 312 | strings[i] = this[randomkey].encrypt(this[randomkey].encrypt(strings[i])); 313 | return strings.length === 1 ? strings[0] : strings; 314 | } 315 | } 316 | } 317 | } 318 | } 319 | 320 | return key; 321 | })(); 322 | 323 | // 有人反馈苹果端不能看,尝试修改UA解决 324 | if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i)) { 325 | // 修改手机端UA,似乎改完这个UA还是没有效果。说明苹果端页面从数据请求就开始检测UA了。请手动修改浏览器UA。 326 | Object.defineProperty(navigator, 'userAgent', { 327 | // 这个UA会屏蔽百度搜索的广告? 328 | value: "Mozilla/5.0 (Linux; Android 8.0; MI 6 Build/OPR1.170623.027; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/48.0.2564.116 Mobile Safari/537.36 T7/10.3 SearchCraft/2.6.3 (Baidu; P1 8.0.0)", 329 | writable: false 330 | }); 331 | } 332 | 333 | let settings = {}; 334 | const root = document.querySelector(":root"); 335 | // 核心驱动代码 336 | (() => { 337 | if (location.search.match(/[?&]url=https?:\/\/.+\..+\..+\/.+/i) || 338 | location.search.match(/[?&]v=https?:\/\/.+\..+\..+\/.+/i) || 339 | location.href.match(/https?:\/\/api\.leduotv\.com\/.+?vid=/i)) { 340 | settings.isParse = true; 341 | } 342 | if (settings.isParse || location.host.indexOf("v.qq.com") !== -1 || location.host.indexOf("iqiyi.com") !== -1 || location.host.indexOf("youku.com") !== -1 || location.host.indexOf("bilibili.com") !== -1 || location.host.indexOf("miguvideo.com") !== -1 || location.host.indexOf("le.com") !== -1 || location.host.indexOf("tv.sohu.com") !== -1 || location.host.indexOf("film.sohu.com") !== -1 || location.host.indexOf("mgtv.com") !== -1 || location.host.indexOf("ixigua.com") !== -1 || location.host.indexOf("pptv.com") !== -1 || location.host.indexOf("vip.1905.com") !== -1 || location.host.indexOf("www.wasu.com") !== -1) { 343 | // 对符合条件的域名执行脚本 344 | // 调用自写加密算法,生成实例类 345 | settings.k1 = new key("Tenfond"); 346 | settings.k2 = new key(" 腾 风 "); 347 | if (window === top) { 348 | settings.parseDB = { 349 | 解析开关: "\x01", 弹幕开关: "\x01", DIY解析栏: "\x01" 350 | }; 351 | for (let name in settings.parseDB) { 352 | let data = localStorage.getItem("解析数据库." + name); 353 | if (data !== null) { 354 | settings.parseDB[name] = data; 355 | } 356 | } 357 | // 油猴可以实现跨域存储 358 | try { 359 | let data = GM_getValue("弹幕开关"); 360 | if (data !== null) settings.parseDB.弹幕开关 = data; 361 | } catch (e) { 362 | // 排除无效函数异常 363 | } 364 | 365 | if (settings.parseDB.解析开关) { 366 | if (!sessionStorage.getItem("tip设置")) { 367 | showTip("右下角可以编辑 设置"); 368 | sessionStorage.setItem("tip设置", "\x01"); 369 | } 370 | readSettings(); 371 | } 372 | settings.parseDBFuntions = { 373 | 解析开关: () => { 374 | if (!settings.parseDB.解析开关) { 375 | location.reload(); 376 | // window 刷新时会自动清除缓存 377 | } else { 378 | readSettings(); 379 | settings.parseDB.解析开关 = "\x01"; 380 | } 381 | }, 382 | 弹幕开关: () => { 383 | try { 384 | GM_setValue("弹幕开关", settings.parseDB.弹幕开关) 385 | } catch (error) { 386 | // 排除无效函数异常 387 | } 388 | showTip("刷新页面即可生效"); 389 | }, 390 | DIY解析栏: () => { 391 | if (typeof settings.DIY_iframeFunction === "function") { 392 | settings.DIY_iframeFunction(); 393 | } else { 394 | showTip("设置已生效"); 395 | } 396 | } 397 | }; 398 | let toolsBar = document.createElement("toolsbar"); 399 | toolsBar.style = "display: block !important; visibility: visible !important; position: fixed; z-index: 2147483647 !important; left:0; bottom: 0; width: 100%; height: 0; font-family: 微软雅黑,黑体,Droid Serif,Arial,sans-serif; font-size: 15px; color: #000;"; 400 | toolsBar.innerHTML = "\n" + "" + 410 | " \n" + 413 | " \n" + 415 | ""; 416 | let SettingsBlock = toolsBar.querySelector("settings>button+ul"); 417 | let parseDBKeys = Object.keys(settings.parseDB); 418 | for (let i = 0; i < parseDBKeys.length; i++) { 419 | SettingsBlock.innerHTML += "
  • " + parseDBKeys[i] + "
  • \n"; 420 | } 421 | let SettingBlockSwitchs = SettingsBlock.querySelectorAll("li>label.parse-switch"); 422 | for (let i = 0; i < SettingBlockSwitchs.length; i++) { 423 | let checkBox = SettingBlockSwitchs[i].querySelector("input[type=checkbox]"); 424 | checkBox.checked = Boolean(settings.parseDB[parseDBKeys[i]]); 425 | SettingBlockSwitchs[i].querySelector("bg").addEventListener("transitionend", () => { 426 | if (checkBox.checked !== Boolean(settings.parseDB[parseDBKeys[i]])) { 427 | // 如果有变化才会执行,否则会重复执行,因为动画会有延迟,刚打开网页时也会触发此监听事件 428 | if (checkBox.checked) { 429 | settings.parseDB[parseDBKeys[i]] = "\x01"; 430 | } else { 431 | settings.parseDB[parseDBKeys[i]] = ""; 432 | } 433 | localStorage.setItem("解析数据库." + parseDBKeys[i], settings.parseDB[parseDBKeys[i]]); 434 | settings.parseDBFuntions[parseDBKeys[i]](); 435 | } 436 | }, false); 437 | } 438 | let SettingsBtn = toolsBar.querySelector("settings>button"); 439 | SettingsBtn.onclick = () => { 440 | if (SettingsBlock.style.opacity === "0") { 441 | SettingsBtn.innerText = "关闭"; 442 | SettingsBlock.style.opacity = "1"; 443 | SettingsBlock.style.width = "200px"; 444 | } else { 445 | SettingsBtn.innerText = "设置"; 446 | SettingsBlock.style.opacity = "0"; 447 | SettingsBlock.style.width = "0"; 448 | } 449 | } 450 | root.append(toolsBar); 451 | } else { 452 | readSettings(); 453 | } 454 | } 455 | })(); 456 | 457 | // 启动解析代码 458 | function start() { 459 | console.log("脚本运行在 " + location.href); 460 | 461 | function detectMobile() { 462 | return (navigator.userAgent.match(/Android/i) || 463 | navigator.userAgent.match(/webOS/i) || 464 | navigator.userAgent.match(/Windows Phone/i) || 465 | navigator.userAgent.match(/Symbian/i) || 466 | navigator.userAgent.match(/BlackBerry/i) || 467 | navigator.userAgent.match(/hpwOS/i)); 468 | } 469 | 470 | function doElement(cssString, doFunction, waitMS = 0) { 471 | let Element = document.querySelector(cssString); 472 | if (Element && Element.nodeType === 1) { 473 | doFunction(Element); 474 | console.log("%c已为 " + cssString + " 进行了操作", settings.fontStyle.ok); 475 | } else if (document.readyState !== "complete" || waitMS > 0) { 476 | console.log("正在查找 " + cssString); // TODO 10毫秒约函数执行时间 477 | setTimeout(() => doElement(cssString, doFunction, document.readyState !== "complete" ? waitMS : waitMS - 10 - settings.getElementTimes), settings.getElementTimes); 478 | } else { 479 | console.log("%c未找到 " + cssString, settings.fontStyle.error); 480 | } 481 | } 482 | 483 | function doElements(cssString, doFunction, waitMS = 0, index = 0) { 484 | let Elements = document.querySelectorAll(cssString); 485 | if (Elements[index] && Elements[index].nodeType === 1) { 486 | doFunction(Elements); 487 | console.log("%c已为 All[" + index + "] " + cssString + " 进行了操作", settings.fontStyle.ok); 488 | } else if (document.readyState !== "complete" || waitMS > 0) { 489 | console.log("正在查找 All[" + index + "] " + cssString); // TODO 10毫秒约函数执行时间 490 | setTimeout(() => doElements(cssString, doFunction, document.readyState !== "complete" ? waitMS : waitMS - 10 - settings.getElementTimes, index), settings.getElementTimes); 491 | } else { 492 | console.log("%c未找到 All[" + index + "] " + cssString, settings.fontStyle.error); 493 | } 494 | } 495 | 496 | function forElements(cssString, doFunction, waitMS = 0, failFunction = null) { 497 | let forElementInterval = setInterval(() => { 498 | if (document.readyState !== "complete" || waitMS > 0) { 499 | let Elements = document.querySelectorAll(cssString); 500 | if (Elements && Elements.length > 0 && Elements[0].nodeType === 1) { 501 | doFunction(Elements, forElementInterval); 502 | console.log("%cforElements已为 " + cssString + " 进行了操作", settings.fontStyle.ok); 503 | } 504 | if (document.readyState === "complete") { 505 | waitMS = waitMS - 10 - settings.getElementTimes; 506 | } 507 | } else { 508 | if (failFunction) { 509 | failFunction(); 510 | } 511 | console.log("已清除 forElements Interval计时器") 512 | clearInterval(forElementInterval); 513 | } 514 | }, settings.getElementTimes); 515 | } 516 | 517 | function removeElements(ElementsStrings) { 518 | console.log("正在检测并移除 " + ElementsStrings); 519 | let removeElementsInterval = setInterval(() => { 520 | if (ElementsStrings.length > 0) { 521 | for (let i in ElementsStrings) { 522 | try { 523 | let Elements = eval(ElementsStrings[i]); 524 | console.log(Elements); 525 | if (Elements && Elements.nodeType === 1) { 526 | console.log("%cremoveElemets 执行了移除 " + ElementsStrings[i], settings.fontStyle.ok); 527 | Elements.parentNode.removeChild(Elements); 528 | ElementsStrings.splice(i, 1); 529 | } else if (Elements[0] && Elements[0].nodeType === 1) { 530 | console.log("%cremoveElemets 执行了移除 " + ElementsStrings[i], settings.fontStyle.ok); 531 | for (let Element of Elements) { 532 | Element.parentNode.removeChild(Element); 533 | } 534 | ElementsStrings.splice(i, 1); 535 | } 536 | } catch (e) { 537 | // 排除 null值未找到方法 错误 538 | } 539 | } 540 | if (document.readyState === "complete") { 541 | console.log("%cremoveElemets 移除失败 " + ElementsStrings, settings.fontStyle.error); 542 | clearInterval(removeElementsInterval); 543 | } 544 | } else { 545 | clearInterval(removeElementsInterval); 546 | console.log("Elements 移除完毕"); 547 | } 548 | }, 200); 549 | } 550 | 551 | if (window === top) { 552 | // 自定义remove方法,暂时用不着了,新方案代替了 553 | // Array.prototype.remove = value => { 554 | // for (let i = 0; i < this.length; i++) { 555 | // if (this[i] === value) { 556 | // this.splice(i, 1); 557 | // return i; 558 | // } 559 | // } 560 | // return -1; 561 | // } 562 | top.addEventListener("message", event => { 563 | if (event.source !== window) { 564 | try { 565 | let sql = key.DECRYPT(event.data, settings.k1, settings.k2).split("\x00"); 566 | if (sql[0] === "宝塔镇河妖") { 567 | if (sql[1] === "函数") { 568 | console.log("top执行了函数: " + sql[2]); 569 | eval(sql[2]); 570 | } else if (sql[1] === "请求") { 571 | if (sql[2] === "用户数据库") { 572 | event.source.postMessage(key.ENCRYPT("天王盖地虎\x00给予\x00用户数据库\x00" + JSON.stringify(settings.parseDB), settings.k1, settings.k2), "*"); 573 | } 574 | } else if (sql[1] === "给予") { 575 | if (sql[2] === "0") { 576 | if (settings.address !== null) { 577 | settings.address = sql[3]; 578 | } 579 | console.log("%c" + settings.address, settings.fontStyle.warn); 580 | } else if (sql[2] === "-1") { 581 | if (settings.address === sql[3]) { 582 | showTip("解析失败,正在更换解析源"); 583 | settings.randomSeleceParse(); 584 | } 585 | } 586 | } else if (sql[1] === "按下Enter获取焦点") { 587 | onkeydown = e => { 588 | if (e.key === 'Enter') { 589 | event.source.focus(); 590 | } 591 | } 592 | } 593 | } 594 | } catch (e) { 595 | console.log("%c" + e, settings.fontStyle.error); 596 | } 597 | } 598 | }); 599 | 600 | if (!detectMobile()) { 601 | if (location.host.indexOf("v.qq.com") !== -1) { 602 | readyPlayerBox("已进入腾讯视频", ["#mask_layer", ".mod_vip_popup", "#mask_layer"], [settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["OK解析"], settings.NoAD解析["天翼解析"], settings.NoAD解析["夜幕解析"]], "div#mod_player", null); 603 | } else if (location.host.indexOf("iqiyi.com") !== -1) { 604 | readyPlayerBox("已进入爱奇艺", ["#playerPopup", "div[class^=qy-header-login-pop]"], [settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["OK解析"]], "iqpdiv.iqp-player[data-player-hook$=er]", null); 605 | } else if (location.host.indexOf("youku.com") !== -1) { 606 | readyPlayerBox("已进入优酷视频", ["#iframaWrapper"], [settings.NoAD解析["PPJ蓝光解析"]], "div#player", null); 607 | } else if (location.host.indexOf("bilibili.com") !== -1) { 608 | doElements("div[role=tooltip]:not([class*=popover-])", loginTip => displayNone(["#" + loginTip[6].id]), 1000, 6); 609 | doElement("svg[aria-hidden=true]", () => readyPlayerBox("已进入哔哩哔哩", null, [settings.NoAD解析["夜幕解析"], settings.NoAD解析["PPJ蓝光解析"]], "div.bpx-player-video-area,div.mask-container", null)); // TODO || document.getElementById("bilibiliPlayer") || document.getElementById("live-player-ctnr") 610 | } else if (location.host.indexOf("miguvideo.com") !== -1) { 611 | readyPlayerBox("已进入咪咕视频", null, [], "section#mod-player", null); 612 | } else if (location.host.indexOf("le.com") !== -1) { 613 | readyPlayerBox("已进入乐视TV", null, [settings.NoAD解析["PPJ蓝光解析"]], "#le_playbox", null); 614 | } else if (location.host.match(/(tv|film).sohu.com/)) { 615 | readyPlayerBox("已进入搜狐视频", null, [settings.NoAD解析["夜幕解析"]], "#player,#sohuplayer,.player-view", null); 616 | } else if (location.host.indexOf("mgtv.com") !== -1) { 617 | readyPlayerBox("已进入芒果TV", null, [settings.NoAD解析["PPJ解析"], settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["OK解析"], settings.NoAD解析["虾米解析"], settings.NoAD解析["夜幕解析"]], "#mgtv-player-wrap", null); 618 | } else if (location.host.indexOf("ixigua.com") !== -1) { 619 | readyPlayerBox("已进入西瓜视频", null, [settings.NoAD解析["夜幕解析"]], "div.teleplayPage__playerSection", null); 620 | } else if (location.host.indexOf("pptv.com") !== -1) { 621 | readyPlayerBox("已进入PPTV", null, [settings.NoAD解析["PPJ蓝光解析"]], "div.w-video", null); 622 | } else if (location.host.indexOf("vip.1905.com") !== -1) { 623 | readyPlayerBox("已进入1905电影网", null, [settings.NoAD解析["云解析"]], "div#playBox", null); 624 | } else if (location.host.indexOf("www.wasu.cn") !== -1) { 625 | readyPlayerBox("已进入华数TV", null, [settings.NoAD解析["PPJ蓝光解析"]], "div#pcplayer", null); 626 | } 627 | } else { 628 | if (location.host.indexOf("v.qq.com") !== -1) { 629 | readyPlayerBox("已进入腾讯视频", [".mod_vip_popup", "[class^=app_],[class^=app-],[class*=_app_],[class*=-app-],[class$=_app],[class$=-app]", "div[dt-eid=open_app_bottom]", "div.video_function.video_function_new", "a[open-app]", "section.mod_source", "section.mod_box.mod_sideslip_h.mod_multi_figures_h,section.mod_sideslip_privileges,section.mod_game_rec"], [settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["OK解析"]], "div.mod_play:not([style*='display: none;']) section.mod_player", null, href => { 630 | let location = hrefToLocation(href); 631 | href = searchToJSON(location.search); 632 | if (href) { 633 | if (href["cid"]) { 634 | if (href["id"]) { 635 | return location.protocol + '//v.qq.com/detail/' + href["cid"][0] + '/' + href["cid"] + '.html'; 636 | } else if (href["vid"]) { 637 | return location.protocol + '//v.qq.com/x/cover/' + href["cid"] + '/' + href["vid"] + '.html'; 638 | } else { 639 | return location.protocol + '//v.qq.com/x/cover/' + href["cid"] + '.html'; 640 | } 641 | } else if (href["vid"]) { 642 | return location.protocol + '//v.qq.com/x/page/' + href["vid"] + '.html'; 643 | } else if (href["lid"]) { 644 | return location.protocol + '//v.qq.com/detail/' + href["lid"][0] + '/' + href["lid"] + '.html'; 645 | } else { 646 | return null; 647 | } 648 | } else { 649 | return null; 650 | } 651 | }); 652 | } else if (location.host.indexOf("iqiyi.com") !== -1) { 653 | readyPlayerBox("已进入爱奇艺", ["div.m-iqyGuide-layer", "a[down-app-android-url]", "[name=m-extendBar]", "[class*=ChannelHomeBanner]", "section.m-hotWords-bottom"], [settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["OK解析"]], "section.m-video-player", null); 654 | } else if (location.host.indexOf("youku.com") !== -1) { 655 | readyPlayerBox("已进入优酷视频", ["#iframaWrapper", ".ad-banner-wrapper", ".h5-detail-guide,.h5-detail-vip-guide", ".brief-btm"], [], "#player", null); 656 | } else if (location.host.indexOf("bilibili.com") !== -1) { 657 | readyPlayerBox("已进入哔哩哔哩", ["div.fe-ui-open-app-btn,div.recom-wrapper,open-app-btn", "[class*=openapp]"], [settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["夜幕解析"]], "div#app.main-container div.player-wrapper", null, href => href.replace("m.bilibili.com", "www.bilibili.com")); 658 | } else if (location.host.indexOf("miguvideo.com") !== -1) { 659 | readyPlayerBox("已进入咪咕视频", ["[class^=app_],[class^=app-],[class*=_app_],[class*=-app-],[class$=_app],[class$=-app]", ".openClient", "div.group-item.programgroup .data-rate-01,div.group-item.programgroup .max-rate-01,div.group-item.programgroup .p-common"], [], "section#mod-player", null, href => href.replace("m.miguvideo.com", "www.miguvideo.com").replace("msite", "website")); 660 | } else if (location.host.indexOf("le.com") !== -1) { 661 | (block_show => { 662 | block_show.innerHTML = "div.layout{visibility: visible !important; display:block !important;}div.layout>*:not(style,script,#j-vote,#j-follow){visibility: visible !important; display: block !important;}"; 663 | document.head.insertBefore(block_show, document.head.firstChild); 664 | })(document.createElement("style")); 665 | doElement("a.j-close-gdt", jump_over => { 666 | jump_over.click(); 667 | return false; 668 | }); 669 | readyPlayerBox("已进入乐视TV", ["a.leapp_btn", "div.full_gdt_bits[id^=full][data-url]", "[class*=Daoliu],[class*=daoliu],[class*=game]", "div.m-start", "[class*=icon_user]"], [settings.NoAD解析["云解析"]], "div.column.play", null); 670 | } else if (location.host.indexOf("m.tv.sohu.com") !== -1) { 671 | readyPlayerBox("已进入搜狐视频", ["div[class^=banner]", "div.js-oper-pos", "div[id^=ad],div[id^=ad] *", "[id*=login],[class*=login]", "[class$=-app]", "div.app-vbox.ph-vbox,div.app-vbox.app-guess-vbox", "div.twinfo_iconwrap", "div[class$=banner],div[id$=banner]"], [settings.NoAD解析["夜幕解析"]], "#player,#sohuplayer,.player-view", null, async href => { 672 | return new Promise(resolve => { 673 | xmlHttpRequest({ 674 | url: href, success: data => { 675 | let result = data.responseText.match(/var videoData = \{[^\x00]+tvUrl:"(http.+)",[\r\n]/)[1]; 676 | resolve(result); 677 | }, error: () => resolve(href) 678 | }); 679 | }); 680 | }); 681 | } else if (location.host.indexOf("mgtv.com") !== -1) { 682 | readyPlayerBox("已进入芒果TV", ["div.adFixedContain,div.ad-banner,div.m-list-graphicxcy.fstp-mark", "div[class^=mg-app],div#comment-id.video-comment div.ft,div.bd.clearfix,div.v-follower-info", "div.ht.mgui-btn.mgui-btn-nowelt", "div.personal", "div[data-v-41c9a64e]"], [settings.NoAD解析["PPJ解析"], settings.NoAD解析["PPJ蓝光解析"], settings.NoAD解析["云解析"], settings.NoAD解析["虾米解析"], settings.NoAD解析["夜幕解析"]], "div.video-poster,div.video-area", null); 683 | } else if (location.host.indexOf("ixigua.com") !== -1) { 684 | readyPlayerBox("已进入西瓜视频", ["div.xigua-download", "div.xigua-guide-button", "div.c-long-video-recommend.c-long-video-recommend-unfold"], [settings.NoAD解析["夜幕解析"]], "div.xigua-detailvideo-video", null); 685 | } else if (location.host.indexOf("pptv.com") !== -1) { 686 | readyPlayerBox("已进入PPTV", ["[data-darkreader-inline-bgimage][data-darkreader-inline-bgcolor]", "div[class^=pp-m-diversion]", "section#ppmob-detail-picswiper", "section.layout.layout_ads", "div.foot_app", "div[modulename=导流位]", "a[class*=user]", "div.mod_video_info div.video_func"], [settings.NoAD解析["PPJ蓝光解析"]], "section.pp-details-video", null, href => href.replace("m.pptv.com", "v.pptv.com")); 687 | } else if (location.host.indexOf("vip.1905.com") !== -1) { 688 | (movie_info => { 689 | movie_info.innerHTML = "section#movie_info{padding-top: 20px !important;}"; 690 | document.head.appendChild(movie_info); 691 | })(document.createElement("style")); 692 | readyPlayerBox("已进入1905电影网", ["a.new_downLoad[target=_blank]", "iframe[srcdoc^='" + "" + ""; 811 | let DIY_iframe_text = DIY_iframe.querySelector("input[type=text]"); 812 | 813 | async function DIY_iframe_src() { 814 | let newiframe = document.querySelector("iframe[id*=player]"); 815 | if (newiframe) { 816 | iframe = newiframe; 817 | } 818 | settings.src.set(DIY_iframe_select.options[DIY_iframe_select.selectedIndex].value, DIY_iframe_text.value ? DIY_iframe_text.value : location.href); 819 | // 预先设置历史解析源(用于适配不支持iframe执行脚本的浏览器) 820 | localStorage.setItem('historyParse', settings.src.get()); 821 | } 822 | 823 | let DIY_iframe_select = DIY_iframe.querySelector("select"); 824 | for (let name in settings.NoAD解析) { 825 | DIY_iframe_select.innerHTML += ""; 826 | } 827 | for (let name in settings.AD解析) { 828 | DIY_iframe_select.innerHTML += ""; 829 | } 830 | DIY_iframe.querySelector("option[value='" + settings.src.get() + "']").selected = true; 831 | settings.randomSeleceParse = async () => { 832 | // arguments 代表输入的所有参数,看不懂可以百度搜索 “js 参数 arguments” 833 | // return arguments ? arguments[Math.floor(Math.random() * arguments.length)] : null; 834 | if (srcs.length > 0) { 835 | let random = Math.floor(Math.random() * srcs.length); 836 | settings.src.set(srcs[random]); 837 | srcs.splice(random, 1); 838 | DIY_iframe.querySelector("option[value='" + settings.src.get() + "']").selected = true; 839 | } else { 840 | if (tested) { 841 | showTip("该视频可能无法解析\n请尝试使用z1解析\n如有疑问请反馈"); 842 | return false; 843 | } else { 844 | showTip("解析失败,正在尝试其他解析源"); 845 | srcs = others; 846 | others = null; 847 | tested = true; 848 | let random = Math.floor(Math.random() * srcs.length); 849 | settings.src.set(srcs[random]); 850 | srcs.splice(random, 1); 851 | } 852 | } 853 | settings.address = {"0": 0, "-1": 1}; 854 | } 855 | DIY_iframe.querySelector("button").onclick = () => DIY_iframe_src(); 856 | DIY_iframe_text.onkeydown = DIY_iframe_select.onkeydown = event => { 857 | if (event.key === "Enter") { 858 | DIY_iframe_src(); 859 | } 860 | } 861 | doElement("toolsbar", toolsBar => { 862 | toolsBar.appendChild(DIY_iframe); 863 | }); 864 | } else if (DIY_iframe.style.visibility === "hidden") { 865 | DIY_iframe.style.display = "flex"; 866 | DIY_iframe.style.visibility = ""; 867 | } 868 | } else if (DIY_iframe && DIY_iframe.constructor.name === "HTMLDivElement" && DIY_iframe.style.visibility === "") { 869 | DIY_iframe.style.display = "none"; 870 | DIY_iframe.style.visibility = "hidden"; 871 | } 872 | } 873 | settings.DIY_iframeFunction(); 874 | 875 | (waiter => { 876 | waiter /= settings.getElementTimes; 877 | let resetPlayerBoxInterval = setInterval(() => { 878 | let newPlayerBox = document.querySelector(cssString); 879 | if (newPlayerBox !== playerBox && newPlayerBox !== null || newPlayerBox !== null && newPlayerBox.querySelector("iframe[src='" + iframe.src + "']") === null) { 880 | console.log("playerBox重新建立连接"); 881 | let src = iframe.src; 882 | iframe.src = ""; 883 | iframe = iframe.cloneNode(true); 884 | iframe.src = src; 885 | newPlayerBox.style.zIndex = "1"; 886 | newPlayerBox.appendChild(iframe); 887 | clearInterval(resetPlayerBoxInterval); 888 | } else if (document.readyState === "complete" && waiter-- <= 0) { 889 | clearInterval(resetPlayerBoxInterval); 890 | } 891 | }, settings.getElementTimes) 892 | })(0); 893 | 894 | if (doFunction) { 895 | doFunction(playerBox, iframe); 896 | } 897 | setInterval(() => { 898 | for (let video of document.getElementsByTagName("video")) { 899 | if (video.src) { 900 | video.removeAttribute("src"); 901 | video.load(); 902 | video.muted = true; 903 | } 904 | } 905 | }, settings.getElementTimes); 906 | 907 | ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange'].forEach(item => { 908 | window.addEventListener(item, () => { 909 | let toolsBar = document.querySelector("toolsbar"); 910 | if (document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen) { 911 | toolsBar.style.display = 'none'; 912 | } else { 913 | toolsBar.style.display = 'block'; 914 | } 915 | }, true); 916 | }); 917 | }); 918 | } 919 | 920 | function hrefToLocation(href) { 921 | let location = {href: href}, c = 0, start = 0, search; 922 | for (let i = 0, port; i < href.length; i++) { 923 | if (href[i] === "/") { 924 | if (++c === 1) { 925 | location.protocol = href.substring(start, i); 926 | } else if (c === 3) { 927 | location.host = href.substring(start + 1, i); 928 | if (port) { 929 | location.port = href.substring(port + 1, i); 930 | } else { 931 | location.hostname = location.host; 932 | location.port = ""; 933 | } 934 | } 935 | if (c <= 3) { 936 | start = i; 937 | } 938 | } else if (href[i] === ":" && c === 2) { 939 | location.hostname = href.substring(start + 1, i); 940 | port = i; 941 | } else if (href[i] === "?" && !search) { 942 | location.pathname = href.substring(start, i); 943 | search = i; 944 | } else if (href[i] === "#" && !location.hash) { 945 | location.hash = href.substr(i); 946 | if (location.pathname === undefined) { 947 | location.pathname = href.substring(c, i); 948 | } else if (search) { 949 | location.search = href.substring(search, i); 950 | } 951 | break; 952 | } 953 | } 954 | if (location.pathname === undefined) { 955 | location.pathname = c === 3 ? href.substr(start) : ""; 956 | location.search = location.hash = ""; 957 | } 958 | if (location.search === undefined) { 959 | if (search) { 960 | location.search = href.substr(search); 961 | } else { 962 | location.search = ""; 963 | } 964 | } 965 | if (location.hash === undefined) { 966 | location.hash = ""; 967 | } 968 | return location; 969 | } 970 | } else { 971 | function setParseVideo() { 972 | forElements("video", async (videos, thisInterval) => { 973 | for (const video of videos) { 974 | if (video.poster) video.removeAttribute("poster"); 975 | if (video.src) { 976 | // 解析成功,清空解析列表缓存 977 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00函数\x00settings.address = null", settings.k1, settings.k2), "*"); 978 | // 设置历史解析 979 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00函数\x00localStorage.setItem('historyParse', settings.src.get())", settings.k1, settings.k2), "*"); 980 | 981 | // 移除广告模块 982 | removeElements(['document.getElementById("ADplayer")', 'document.getElementById("ADtip")']); 983 | // 等待数据得到响应,移除弹幕模块 984 | await settings.parseDB; 985 | if (!settings.parseDB.弹幕开关) { 986 | console.log("正在移除弹幕功能"); 987 | removeElements(['document.querySelector("div[class$=player-video-wrap]").getElementsByTagName("div")', 'document.querySelector("div[class$=player-danmu]")', 'document.querySelector("div[class$=player-danmaku]")', 'document.querySelector("div[class*=player-comment-box]")', 'document.querySelector("div[class*=player-controller-mask]")', 'document.querySelector("[class*=player-list-icon]")', 'document.querySelector("div[class$=player-menu]")']); 988 | } 989 | 990 | // 判断是否移动端 991 | if (!detectMobile()) { 992 | let fullscreen_btn = document.querySelector("[class*=fullscreen],[class$=player-full] button[class$=full-icon]"); 993 | if (fullscreen_btn && fullscreen_btn.nodeType === 1) { 994 | // 阻止事件冒泡 995 | fullscreen_btn.parentNode.parentNode.onkeyup = event => event.stopPropagation(); 996 | } 997 | video.onkeyup = event => event.stopPropagation(); 998 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00按下Enter获取焦点", settings.k1, settings.k2), "*") 999 | onkeyup = video.onkeyup = event => { 1000 | if (event.key === "Enter") { 1001 | if (video.paused) { 1002 | video.play(); 1003 | } 1004 | if (fullscreen_btn && fullscreen_btn.nodeType === 1) { 1005 | fullscreen_btn.click(); 1006 | return false; 1007 | } else if (video.webkitDisplayingFullscreen) { 1008 | if (video.webkitExitFullScreen) { 1009 | video.webkitExitFullScreen(); 1010 | } else if (video.webkitExitFullscreen) { 1011 | video.webkitExitFullscreen(); 1012 | } 1013 | } else { 1014 | if (video.webkitEnterFullScreen) { 1015 | video.webkitEnterFullScreen(); 1016 | } else if (video.webkitEnterFullscreen) { 1017 | video.webkitEnterFullscreen(); 1018 | } 1019 | } 1020 | } 1021 | } 1022 | focus(); 1023 | showTip("按下Enter回车键,进入全屏 并 自动播放"); 1024 | video.addEventListener("pause", () => { 1025 | if ((video.currentTime - video.duration) > -5) { 1026 | console.log("视频播放结束了"); 1027 | if (fullscreen_btn && fullscreen_btn.nodeType === 1 && ((video.clientWidth || video.scrollWidth) === screen.width) || ((video.clientHeight || video.scrollHeight) === screen.height)) { 1028 | fullscreen_btn.click(); 1029 | return false; 1030 | } else if (video.webkitExitFullScreen) { 1031 | video.webkitExitFullScreen(); 1032 | } else if (video.webkitExitFullscreen) { 1033 | video.webkitExitFullscreen(); 1034 | } else { 1035 | console.log("不支持退出全屏"); 1036 | } 1037 | } 1038 | }, false); 1039 | } else { 1040 | // showTip("解析成功"); 1041 | } 1042 | 1043 | // 清除监听video计时器 1044 | clearInterval(thisInterval); 1045 | } 1046 | } 1047 | }, 3000, function () { 1048 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00给予\x00-1\x00" + location.href, settings.k1, settings.k2), "*"); 1049 | }); 1050 | } 1051 | 1052 | if (location.host.indexOf("jiexi.t7g.cn") !== -1) { 1053 | // 移除PPJ解析p2p提示 1054 | displayNone(["body>div#stats"]); 1055 | setParseVideo(); 1056 | } else if (location.host.indexOf("api.okjx.cc:3389") !== -1) { 1057 | // 删除OK解析线路选择功能 1058 | (style => { 1059 | style.innerHTML = ".slide,.panel,.slide *,.panel *{width: 0 !important; max-width: 0 !important; opacity: 0 !important;}"; 1060 | document.head.appendChild(style); 1061 | })(document.createElement("style")); 1062 | setParseVideo(); 1063 | } else if (location.host.indexOf("api.jiubojx.com") !== -1) { 1064 | displayNone("div.adv_wrap_hh"); 1065 | setParseVideo(); 1066 | } else if (location.host.indexOf("yemu.xyz") !== -1) { 1067 | if (location.pathname.indexOf("jx.php") === -1) { 1068 | if (location.host.indexOf("www.yemu.xyz") !== -1) { 1069 | // 删除夜幕解析线路选择功能 1070 | (style => { 1071 | style.innerHTML = ".slide,.panel,.slide *,.panel *{width: 0 !important; max-width: 0 !important; opacity: 0 !important;}"; 1072 | document.head.appendChild(style); 1073 | })(document.createElement("style")); 1074 | } else if (location.host.indexOf("jx.yemu.xyz") !== -1) { 1075 | // 移除视频分类提示 及 解析框架处理 1076 | displayNone(["div.advisory"]); 1077 | setParseVideo(); 1078 | } 1079 | } else { 1080 | // 移除背景图片 1081 | doElement("div[style*='width:100%;height:100%;'][style*='.jpg']", background => { 1082 | background.style = "width:100%;height:100%;position:relative;z-index:2147483647987;"; 1083 | }, 5000); 1084 | } 1085 | } else if (location.host.indexOf('www.mtosz.com') !== -1) { 1086 | displayNone([".video-panel-blur-image"]); // 似乎不管用? 1087 | doElement(".video-panel-blur-image", element => { 1088 | element.style = "display: none; height: 0; width: 0;"; 1089 | }); 1090 | setParseVideo(); 1091 | } else if (location.host.indexOf('v.superchen.top:3389') !== -1) { 1092 | setParseVideo(); 1093 | } else if (location.host.indexOf('jx.parwix.com:4433') !== -1) { 1094 | setParseVideo(); 1095 | } else if (location.pathname) { 1096 | setParseVideo(); 1097 | } 1098 | } 1099 | 1100 | 1101 | function displayNone(Tags) { 1102 | let style = document.createElement("style"); 1103 | style.innerHTML = "\n"; 1104 | for (let i = 0; i < Tags.length; i++) { 1105 | style.innerHTML += Tags[i] + "{display: none !important; height: 0 !important; width: 0 !important; visibility: hidden !important; max-height: 0 !important; max-width: 0 !important; opacity: 0 !important;}\n"; 1106 | } 1107 | document.head.insertBefore(style, document.head.firstChild); 1108 | } 1109 | 1110 | function onLocationChange(handler) { 1111 | let url = top.location.pathname; 1112 | let onLocationChangeInterval = setInterval(() => { 1113 | let href = top.location.pathname; 1114 | if (href.indexOf(url) === -1) { 1115 | handler(); 1116 | clearInterval(onLocationChangeInterval); 1117 | } else { 1118 | url = href; 1119 | } 1120 | }, settings.getElementTimes); 1121 | } 1122 | 1123 | function onFirstLoad(doFunction) { 1124 | if (document.readyState === "complete") { 1125 | if (doFunction) { 1126 | doFunction(); 1127 | } 1128 | } else { 1129 | setTimeout(() => { 1130 | onFirstLoad(doFunction); 1131 | }, settings.getElementTimes); 1132 | } 1133 | } 1134 | 1135 | function searchToJSON(search) { 1136 | if (search) { 1137 | return JSON.parse("{\"" + decodeURIComponent(search.substring(1) 1138 | .replace(/"/g, '\\"') 1139 | .replace(/&/g, '","') 1140 | .replace(/=/g, '":"')) + "\"}"); 1141 | } else { 1142 | return null; 1143 | } 1144 | } 1145 | } 1146 | 1147 | function showTip(msg, style = "") { 1148 | // 该函数需要在top内运行,否则可能显示异常 1149 | if (window === top) { 1150 | let tip = document.querySelector(":root>tip"); 1151 | if (tip && tip.nodeType === 1) { 1152 | // 防止中途新的showTip事件创建多个tip造成卡顿 1153 | root.removeChild(tip); 1154 | } 1155 | tip = document.createElement("tip"); 1156 | // pointer-events: none; 禁用鼠标事件,input标签使用 disabled='disabled' 禁用input标签 1157 | tip.style = style + "pointer-events: none; opacity: 0; background-color: #222a; color: #fff; font-family: 微软雅黑,黑体,Droid Serif,Arial,sans-serif; font-size: 20px; text-align: center; padding: 6px; border-radius: 16px; position: fixed; transform: translate(-50%, -50%); left: 50%; bottom: 15%; z-index: 2147483647;"; 1158 | tip.innerHTML = "\n" + msg; 1159 | let time = msg.replace(/\s/, "").length / 2; // TODO 2个字/秒 1160 | // cubic-bezier(起始点, 起始点偏移量, 结束点偏移量, 结束点),这里的 cubic-bezier函数 表示动画速度的变化规律 1161 | tip.style.animation = "showTip " + (time > 2 ? time : 2) + "s cubic-bezier(0," + ((time - 1) > 0 ? (time - 1) / time : 0) + "," + (1 - ((time - 1) > 0 ? (time - 1) / time : 0)) + ",1) 1 normal"; 1162 | root.appendChild(tip); 1163 | setTimeout(() => { 1164 | try { 1165 | root.removeChild(tip); 1166 | } catch (e) { 1167 | // 排除root没有找到tip 1168 | } 1169 | }, time * 1000); 1170 | } else { 1171 | top.postMessage(key.ENCRYPT("宝塔镇河妖\x00函数\x00showTip('" + msg + "')", settings.k1, settings.k2), "*"); 1172 | } 1173 | } 1174 | 1175 | function xmlHttpRequest(settings) { 1176 | let request = new XMLHttpRequest(); 1177 | if (settings.success) { 1178 | request.onload = event => { 1179 | // 加载成功 1180 | settings.success(request, event); 1181 | } 1182 | } 1183 | if (settings.error) { 1184 | request.onerror = event => { 1185 | // 加载失败 1186 | settings.error(request, event); 1187 | } 1188 | } 1189 | if (settings.loadend) { 1190 | request.onloadend = event => { 1191 | // 加载结束 1192 | settings.loadend(request, event); 1193 | } 1194 | } 1195 | if (settings.timeout) { 1196 | request.ontimeout = event => { 1197 | // 加载超时 1198 | settings.timeout(request, event); 1199 | } 1200 | } 1201 | request.open(settings.method ? settings.method : "GET", settings.url ? settings.url : location.href, settings.async ? settings.async : true, settings.username ? settings.username : null, settings.password ? settings.password : null); 1202 | if (settings.headers) { 1203 | for (let header in settings.headers) { 1204 | request.setRequestHeader(header, settings[header]); 1205 | } 1206 | } 1207 | if (settings.dataType) { 1208 | request.responseType = settings.dataType; 1209 | } 1210 | if (settings.data) { 1211 | let data = ""; 1212 | for (let key in settings.data) { 1213 | data += key + "=" + settings.data[key] + "&"; 1214 | } 1215 | data = data.substr(0, data.length - 1); 1216 | request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 1217 | request.send(data); 1218 | } else { 1219 | request.send(); 1220 | } 1221 | return request; 1222 | } 1223 | ////m3u8视频下载 1224 | ////********************************************** 1225 | (function() { 1226 | 'use strict'; 1227 | var m3u8Target = '' 1228 | var originXHR = window.XMLHttpRequest 1229 | 1230 | function ajax(options) { 1231 | options = options || {}; 1232 | let xhr = new originXHR(); 1233 | if (options.type === 'file') { 1234 | xhr.responseType = 'arraybuffer'; 1235 | } 1236 | 1237 | xhr.onreadystatechange = function() { 1238 | if (xhr.readyState === 4) { 1239 | let status = xhr.status; 1240 | if (status >= 200 && status < 300) { 1241 | options.success && options.success(xhr.response); 1242 | } else { 1243 | options.fail && options.fail(status); 1244 | } 1245 | } 1246 | }; 1247 | 1248 | xhr.open("GET", options.url, true); 1249 | xhr.send(null); 1250 | } 1251 | 1252 | // 检测 m3u8 链接的有效性 1253 | function checkM3u8Url(url) { 1254 | ajax({ 1255 | url, 1256 | success: (fileStr) => { 1257 | if (fileStr.indexOf('.ts') > -1) { 1258 | appendDom() 1259 | m3u8Target = url 1260 | console.log('【m3u8】----------------------------------------') 1261 | console.log(url) 1262 | console.log('http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html?source=' + url) 1263 | } 1264 | } 1265 | }) 1266 | } 1267 | 1268 | function resetAjax() { 1269 | if (window._hadResetAjax) { // 如果已经重置过,则不再进入。解决开发时局部刷新导致重新加载问题 1270 | return 1271 | } 1272 | window._hadResetAjax = true 1273 | 1274 | var originOpen = originXHR.prototype.open 1275 | window.XMLHttpRequest = function() { 1276 | var realXHR = new originXHR() 1277 | realXHR.open = function(method, url) { 1278 | url.indexOf('.m3u8') > 0 && checkM3u8Url(url) 1279 | originOpen.call(realXHR, method, url) 1280 | } 1281 | return realXHR 1282 | } 1283 | } 1284 | 1285 | function appendDom() { 1286 | if (document.getElementById('m3u8-download-dom')) { 1287 | return 1288 | } 1289 | var domStr = ` 1290 |
    跳转下载
    1300 |
    注入下载
    1310 |
    1319 | 1324 |
    1325 | ` 1326 | var $section = document.createElement('section') 1327 | $section.id = 'm3u8-download-dom' 1328 | $section.style.position = 'fixed' 1329 | $section.style.zIndex = '9999' 1330 | $section.style.bottom = '20px' 1331 | $section.style.right = '20px' 1332 | $section.style.textAlign = 'center' 1333 | $section.innerHTML = domStr 1334 | document.body.appendChild($section); 1335 | 1336 | var m3u8Jump = document.getElementById('m3u8-jump') 1337 | var m3u8Close = document.getElementById('m3u8-close') 1338 | var m3u8Append = document.getElementById('m3u8-append') 1339 | 1340 | m3u8Close.addEventListener('click', function() { 1341 | $section.remove() 1342 | }) 1343 | 1344 | m3u8Jump.addEventListener('click', function() { 1345 | window.open('http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html?source=' + m3u8Target) 1346 | }) 1347 | 1348 | m3u8Append.addEventListener('click', function() { 1349 | var _hmt = _hmt || []; 1350 | (function() { 1351 | var hm = document.createElement("script"); 1352 | hm.src = "https://hm.baidu.com/hm.js?1f12b0865d866ae1b93514870d93ce89"; 1353 | var s = document.getElementsByTagName("script")[0]; 1354 | s.parentNode.insertBefore(hm, s); 1355 | })(); 1356 | ajax({ 1357 | url: 'https://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html', 1358 | success: (fileStr) => { 1359 | let fileList = fileStr.split(`