/* globals jQuery, $, Vue */ // ==UserScript== // @name 窗口解析VIP视频集合 // @namespace https://greasyfork.org/zh-CN/users/104201 // @version 6.0.6 // @description 破解VIP或会员视频,原作者:黄盐 // @author xinggsf // @noframes // @match https://www.iqiyi.com/* // @match https://v.youku.com/v_show/id_* // @match http://www.le.com/ptv/vplay/* // @match https://www.le.com/ptv/vplay/* // @match https://v.qq.com/* // @match https://m.mgtv.com/b/* // @match https://www.mgtv.com/b/* // @match https://film.sohu.com/album/* // @match https://tv.sohu.com/v/* // @match https://www.acfun.cn/bangumi/* // @match https://www.bilibili.com/* // @match https://vip.1905.com/play/* // @match http://v.pptv.com/show/* // @match https://v.pptv.com/show/* // @match https://m.fun.tv/vplay/* // @match https://www.fun.tv/vplay/* // @exclude https://*.bilibili.com/blackboard/* // @grant window.onurlchange // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @grant GM_openInTab // @run-at document-body // @require https://cdn.staticfile.org/vue/2.6.11/vue.min.js // @require https://cdn.staticfile.org/jquery/3.6.0/jquery.min.js // ==/UserScript== // 加上广告过滤规则~白名单: #@##intabPlayer > iframe 'use strict'; const sleep = ms => new Promise(resolve => { setTimeout(resolve, ms) }); if (window.onurlchange === void 0) { history.pushState = ( f => function pushState(){ const ret = f.apply(this, arguments); window.dispatchEvent(new Event('pushstate')); window.dispatchEvent(new Event('urlchange')); return ret; })(history.pushState); history.replaceState = ( f => function replaceState(){ const ret = f.apply(this, arguments); window.dispatchEvent(new Event('replacestate')); window.dispatchEvent(new Event('urlchange')); return ret; })(history.replaceState); window.addEventListener('popstate',()=>{ window.dispatchEvent(new Event('urlchange')) }); }; const site = location.hostname.replace(/\W/g, ''); //[^_\W]数字字母集 // 把不同的集数据,以站点名为键,分开存储 function saveSet(name, value) { const thisSet = GM_getValue(name, {}); thisSet[site] = value; GM_setValue(name, thisSet); } function getSet(name, defaultValue) { const thisSet = GM_getValue(name, {}); return thisSet[site] || defaultValue; } // 解析引擎。 去除原bad字符,以适应git const APIS = [ {name: "parwix", url: "https://jx.bozrc.com:4433/player/?url=", title: "全网解析"}, // 88看 必须修改请求头referer为 https://www.mgtv1.tv/ 示例网址:https://vip.shankuwang.com:8443/?url=https://v.youku.com/v_show/id_XNTg2NDQ0NDg0NA==.html {name: "88看", url: "https://vip.shankuwang.com:8443/?url=", title: "全网解析"}, // 88TV 必须修改请求头referer为 https://www.agemys.cc/ {name: "88TV", url: "https://vip.jsjinfu.com:8443/?url=", title: "全网解析"}, {name:"高速接口",url: "https://jsap.attakids.com/?url="}, {name: "虾米", url: "https://jx.xmflv.com/?url="}, {name: "M1907", url: "https://z1.m1907.cn/?jx=", title: "全网VIP接口"}, {name:"夜幕",url: "https://www.yemu.xyz/?url="}, {name:"乐多",url: "https://api.leduotv.com/wp-api/ifr.php?isDp=1&vid="}, {name: "诺讯", url: "https://www.nxflv.com/?url="}, {name:"m3u8.tv",url: "https://jx.m3u8.tv/jiexi/?url="}, {name:"OK云",url: "https://api.okjx.cc:3389/m33/?url="}, {name:"猪蹄",url: "https://jx.iztyy.com/svip/?url="}, {name:"盘古",url: "https://www.pangujiexi.cc/jiexi.php?url="}, {name:"黑云",url: "https://jiexi.380k.com/?url="}, {name:"爱豆",url: "https://jx.aidouer.net/?url="}, {name:"sugan",url: "https://api.suganjx.com/index/?url="}, // Youku {name:"ergan",url: "https://jx.ergan.top/?url="}, {name:"代代",url: "https://api.daidaitv.com/index/?url="} ]; const siteCfg = { 'wwwbilibilicom': { VIPFlag: '.player-limit-mask.pay, .ep-item.cursor.badge', // nextFlag: '' }, 'wwwmgtvcom': { VIPFlag: '.episode-item.focus > .vip, .vip-button-box > .vip-button' }, 'vpptvcom': { VIPFlag: '.pay-btn' }, 'wwwwasucn': { VIPFlag: '#vip_information' }, 'wwwacfuncn': { // '.single-p.active > .needpay-sign' VIPFlag: _ => !!unsafeWindow.player.videoInfo }, 'vip1905com': { VIPFlag: _ => 1 }, 'vqqcom': { // VIPFlag: '.list_item.current i.mark_v>img[alt^=VIP], .mod_vip_sidebar' VIPFlag: _ => unsafeWindow.VIDEO_INFO?.drm }, 'wwwiqiyicom': { VIPFlag: '[data-player-hook=videoLoadingVip]:visible' // .iqp-stream-switch > a[data-event=recharge]:visible', .play-list-item.selected .icon-tr > img[src$="VIP.png"], .select-item.selected .icon-tr > img[src*="/vip_1000"] }, 'vyoukucom': { // VIPFlag: _ => 'drmType' in videoPlayer.context.drm VIPFlag() { const s = `a[href^="https://v.youku.com${location.pathname}"]:first span.mark-text`; return $(s).text() === 'VIP'; } } }; // 通讯总线 const bus = new Vue(); // 页内播放器 intabPlayer.vue const comIntabPlayer = { template: `
`, data() { return { src: '', isShow: 0, position: { left: 100, top: 100 }, sizeCode: 'medium', size: {small:40, medium:65, large:90, fill:100} } }, methods: { move(e) { const disX = e.clientX - this.$el.offsetLeft; const disY = e.clientY - this.$el.offsetTop; document.onmousemove = (e) => { this.position.left = Math.max(e.clientX - disX, -150); this.position.top = Math.max(e.clientY - disY, 0); }; document.onmouseup = (e) => { saveSet('intabPosition', this.position); document.onmousemove = null; document.onmouseup = null; }; }, closePlayer() { this.src = ''; this.isShow = 0; } }, computed: { intabPlayerStyle() { const override = this.sizeCode == 'fill' ? "left:0;top:0;" : ''; const per = this.size[this.sizeCode]; return `left:${this.position.left}px;top:${this.position.top}px;width:${per}vw;height:${per}vh;${override}`; } }, mounted() { bus.$on('updateSrc', async src => { // && $(this.$el).find('.wrap>iframe:visible').length == 0 if (this.src && !this.$refs.ifr.offsetWidth) { this.isShow = 0; // this.$forceUpdate() await sleep(99); } this.src = src; this.isShow = 1; }); this.position = getSet('intabPosition', { left: 100, top: 100 }); } }; // intabPlayer CSS GM_addStyle(` button{cursor:pointer} #intabPlayer{z-index:999999;position:fixed;display:block;overflow:hidden; resize:both!important;box-shadow:0 0 2px 2px #f3c;color:#333!important;} #intabPlayer #bar{visibility:hidden;position:absolute;width:366px;top:0;left:calc(50% - 180px);} #intabPlayer:hover #bar{visibility:visible;z-index:999999;cursor:move} #intabPlayer #bar button{background:yellow;padding:0px 10px;font-size:20px;line-height:30px;border:1px solid #3a3a3a} #intabPlayer #bar button:hover{background:red} #intabPlayer > .wrap, #intabPlayer iframe{padding:0;width:100%;height:100%;border:0} `); // 编辑API组件 editApis.vue const comEditApis = { template: `

  • `, data() { return { isShow: 0, isChanged: 0, defaultApis: { apis: [] }, myApis: { apis: [] } } }, methods: { async saveApis() { const defaultApis = this.defaultApis.apis.filter(item => item.url); const myApis = this.myApis.apis.filter(item => item.url); // console.log(defaultApis,myApis); GM_setValue("defaultApis", defaultApis); GM_setValue("myApis", myApis); bus.$emit("updateApis"); await sleep(500); this.isShow = 0; this.isChanged = 0; }, closeEdit() { if (this.isChanged && !confirm("有改动,未保存就关闭吗?")) return !1; this.isShow = 0; this.isChanged = 0; }, testApi(index, isDefault) { const api = isDefault ? this.defaultApis.apis[index].url : this.myApis.apis[index].url; GM_openInTab(api + location.href, !1); }, addApi(index, isDefault) { const blankItem = {name: '', url: '', title: ''}; if (isDefault) { this.defaultApis.apis.splice(index + 1, 0, blankItem); } else { this.myApis.apis.splice(index + 1, 0, blankItem) } }, deleteApi(index, isDefault) { if (isDefault) { this.defaultApis.apis.splice(index, 1) } else { this.myApis.apis.splice(index, 1) } } }, mounted() { bus.$on("editApis", (defaultApis) => { this.defaultApis.apis = GM_getValue('defaultApis', defaultApis); const myApis = GM_getValue('myApis', []); this.myApis.apis = myApis.length ? myApis : [{ name: '', url: '', title: ''}]; this.isShow = 1; }) } }; // editApis.vue CSS GM_addStyle(` #editApis{z-index:999998;position:fixed;top:0;width:100%;height:100%;background:#3a3a3acc; color:white;text-align:center;overflow:auto} #editApis li{list-style-type:none;display:block;margin-bottom:3px} #editApis input{border:1px solid #999;padding:3px;margin-right:5px;border-radius:3px} #editApis .short{width:100px} #editApis .long{width:250px} #editApis button{display:inline-block;padding:3px;margin:2px;color:#3a3a3a;background:#ff0;border:0} #editApis .bigger{font-size:20px;padding:5px 10px} `); // 主界面 组件 const comMain = { template: `
    {{api.name||'未命名'}}
    `, data() { return { apis: [], defaultApis: [], myApis: [], settings: { openIntab: { value: 1, name: "页内播放" }, autoEpisodeIntab: { value: 1, name: "选集自动解析" }, myApisFirst: { value: 1, name: "我的API优先" }, editApis: { value: 0, name: "管理API" }, }, nav: 'apis', topOffset: 50, selAPIName: '' } }, components: { 'edit-apis': comEditApis }, methods: { moveY(e) { const disY = e.clientY - this.$el.offsetTop; document.onmousemove = (e) => { this.topOffset = Math.max(e.clientY - disY, 0); }; document.onmouseup = (e) => { saveSet("topSet", this.topOffset); document.onmousemove = null; document.onmouseup = null; }; }, quickJump() { let i = this.apis.findIndex(k => k.name === this.selAPIName); if (i == -1) ++i; this.jump(i); }, jump(index) { this.selAPIName = this.apis[index].name; saveSet("selAPIName", this.selAPIName); const link = this.apis[index].url + location.href; if (this.settings.openIntab.value) { bus.$emit('updateSrc', link); } else { GM_openInTab(link, !1); } }, changeSetting(name) { GM_setValue("Settings", this.settings); if (name == 'editApis') { bus.$emit('editApis', this.defaultApis) } else if (name == 'myApisFirst') { this.updateApis(); } }, updateApis() { this.defaultApis = GM_getValue('defaultApis', APIS); this.myApis = GM_getValue("myApis", []); const settings = GM_getValue("Settings", {}); if (this.settings.myApisFirst.value) { this.apis = this.myApis.concat(this.defaultApis); } else { this.apis = this.defaultApis.concat(this.myApis); } }, testVIP() { let isVIP = siteCfg[site]?.VIPFlag; if (!isVIP) return !1; if (typeof isVIP == 'function') isVIP = isVIP(); else isVIP = $(isVIP)[0]; isVIP && this.quickJump(); return isVIP; } }, computed: { styleTop() { return `top:${this.topOffset}px;`; } }, mounted() { bus.$on('updateApis', () => { this.updateApis() }); window.addEventListener('urlchange', async (info) => { await sleep(330); if (this.testVIP()) return; if (this.settings.openIntab.value && this.settings.autoEpisodeIntab.value && $('#intabPlayer:visible')[0]) this.quickJump(); }); $(async () => { await sleep(550); this.testVIP(); }); this.$nextTick(() => { this.topOffset = getSet('topSet', 50); this.selAPIName = getSet('selAPIName', ''); Object.assign(this.settings, GM_getValue("Settings", {})); this.updateApis(); }); } }; // 主界面 CSS GM_addStyle(` body{padding:0;margin:0} #crackVIPSet input[type=checkbox],#editApis input[type=checkbox]{display:none} #crackVIPSet input[type=checkbox] + span:before,#editApis input[type=checkbox] + span:before{content:'☒';margin-right:5px} #crackVIPSet input[type=checkbox]:checked + span:before,#editApis input[type=checkbox]:checked + span:before{content:'☑';margin-right:5px} #crackVIPSet,#editApis,#intabPlayer{user-select:none;font-family:"微软雅黑"} #crackVIPSet{z-index:999998;position:fixed;display:grid;grid-template-columns:30px 150px;width:30px;height:50px;overflow:hidden;padding:5px 0 5px 0;opacity:0.4;font-size:12px} #crackVIPSet button{cursor:pointer} #crackVIPSet:hover{width:180px;height:450px;padding:5px 5px 5px 0;opacity:1} #crackVIPSet #nav{display:grid;grid-auto-rows:50px 50px 200px;grid-row-gap:5px} #crackVIPSet #nav [name=quickJump]:active{cursor:move} #crackVIPSet #nav button{background:yellow;color:red;font-size:20px;padding:0;border:0;cursor:pointer;border-radius:0 5px 5px 0} #crackVIPSet #list{overflow:auto;margin-left:2px} #crackVIPSet #list b{display:block;cursor:pointer;color:#3a3a3a;font-weight:normal;font-size:14px;padding:5px;background-color:#ffff00cc;border-bottom:1px dashed #3a3a3a} #crackVIPSet #list b:before{content:attr(data-icon);padding-right:5px} #crackVIPSet #list b:first-child{border-radius:5px 5px 0 0} #crackVIPSet #list b:last-child{border-radius:0 0 5px 5px} #crackVIPSet #list b:hover{background-color:#3a3a3a;color:white} `); // 在文档之外渲染并且随后挂载 const player = new Vue({ render: h => h(comIntabPlayer) }).$mount(); document.body.appendChild(player.$el); const vm = new Vue({ render: h => h(comMain) }).$mount(); document.body.appendChild(vm.$el);