您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
破解vip视频免费观看
// ==UserScript== // @name 猫咪av // @namespace http://tampermonkey.net/ // @version 1.4 // @description 破解vip视频免费观看 // @author thunder-sword // @match *://*/home // @match *://*/page/vip/* // @match *://*/page/remen/* // @require https://cdn.staticfile.net/crypto-js/4.2.0/crypto-js.min.js#sha256=dppVXeVTurw1ozOPNE3XqhYmDJPOosfbKQcHyQSE58w= // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=f2c013d5bbbb.com // @grant none // @connect mjson.szaction.cc // ==/UserScript== //变量作用:负责一些配置 var settings = { m3u8Prefix: "https://tma.qianchengwandian.top", //setSource(config?.m3u8_host_encrypt ?? data?.source?.m3u8_host)(video.tsx) apiPrefix: "https://mjson.szaction.cc", //_domain = _domain.endsWith('/') ? _domain : `${_domain}/`;(useAxios.ts) } //变量作用:管理当前pageIndex var pageIndex=1; //变量作用:管理当前mediaType var mediaType=1; //常量作用:页面端type和mediaType不是一一对应的,需要转换一下(/data/category/base-2.js) const mediaTypes={ 58: "base-vip-mmtj-", 59: "base-vip-ycgc-", 62: "base-vip-zfyx-", 60: "base-vip-hlaiq-", 61: "base-vip-sjzy-", 63: "base-vip-cydm-", 64: "base-vip-omdp-", 65: "base-vip-txzq-", 150: "base-remen-xpsd-", 151: "base-remen-djjx-", 152: "base-remen-gccm-", 153: "base-remen-jpgq-", 154: "base-remen-zmcs-", 155: "base-remen-thss-", 156: "base-remen-spxm-", 157: "base-remen-avjs-", } //常量作用:加解密所需常量 const key = CryptoJS.enc.Utf8.parse("IdTJq0HklpuI6mu8iB%OO@!vd^4K&uXW"); const iv = "$0v@krH7V2"; const mode = CryptoJS.mode.CBC; const padding = CryptoJS.pad.Pkcs7; const formatter = CryptoJS.format.OpenSSL; const secretKey = "D7hGKHnWThaECaQ3ji4XyAF3MfYKJ53M"; //来自util.js // this.key = "SWRUSnEwSGtscHVJNm11OGlCJU9PQCF2ZF40SyZ1WFc="; // this.iv = "JDB2QGtySDdWMg=="; // this.sign_key = "JkI2OG1AJXpnMzJfJXUqdkhVbEU0V2tTJjFKNiUleG1VQGZO"; // this.suffix = 123456; // this.statDomain = process.env.REACT_APP_STATIC_STAT_DOMAIN; // this.secretKey = "D7hGKHnWThaECaQ3ji4XyAF3MfYKJ53M"; //判断第三方库是否导入成功 if('undefined'===typeof CryptoJS || undefined===CryptoJS.AES){ showStackToast("导入第三方库crypto-js失败","red"); throw Error("导入第三方库crypto-js失败,请尝试更换cdn或更改网络环境"); } function addVidKeyParam2(url) { let secret_key = secretKey; let currentTime = Math.floor(Date.now() / 1000); // Current time in seconds let storedTime = sessionStorage.getItem('timestamp'); // Get the stored timestamp from sessionStorage let time; // Declare the time variable // If there is a stored time and 5 minutes haven't passed, reuse the stored time if (storedTime && currentTime - parseInt(storedTime) < 300) { time = parseInt(storedTime) + 300; // Use the stored timestamp and add 300 seconds } else { // If no stored time or more than 5 minutes have passed, generate a new timestamp time = currentTime + 300; // Add 300 seconds to the current time sessionStorage.setItem('timestamp', currentTime.toString()); // Store the new timestamp in sessionStorage } // Convert the time to a hexadecimal string let hexTime = time.toString(16); console.log('Hex time:', hexTime); // The URI for which we're generating the key let uri = url; console.log('URI:', uri); // Concatenate secret_key, uri, and time (decimal) for the MD5 hash let paramToAppend = secret_key + uri + time; // Time in decimal console.log('Param to append for MD5:', paramToAppend); // Calculate the MD5 hash using CryptoJS let key = CryptoJS.MD5(paramToAppend).toString(); console.log('Generated key (MD5):', key); // Return the URL with wsSecret (the MD5 hash) and wsTime (in decimal) return '?wsSecret=' + key + "&wsTime=" + time; // wsTime is the time in seconds (decimal) } function encrypt(plaintext, suffix = "123456") { var tmp=CryptoJS.enc.Utf8.parse(plaintext); let new_iv = CryptoJS.enc.Utf8.parse(iv + suffix); var enc=CryptoJS.AES.encrypt(tmp, key, { iv: new_iv, mode: mode, padding: padding, formatter: formatter }); return enc.toString(); } //let __data = u.decrypt(response.data.data, response.data.suffix);(useAxios.ts) function decrypt(ciphertext, suffix = "123456") { let new_iv = CryptoJS.enc.Utf8.parse(iv + suffix); var dec=CryptoJS.AES.decrypt(ciphertext, key, { iv: new_iv, mode: mode, padding: padding, formatter: formatter }); var s=dec.toString(CryptoJS.enc.Utf8); return JSON.parse(s); } function getSignature(data) { function objKeySort(arys) { let newObj = {}; let newkey = Object.keys(arys).sort(); for (var i = 0; i < newkey.length; i++) { newObj[newkey[i]] = arys[newkey[i]]; } return newObj; } data = objKeySort(data); let pre_sign = ""; for (let i in data) { pre_sign += i + "=" + data[i] + "&"; } let key = '&B68m@%zg32_%u*vHUlE4WkS&1J6%%xmU@fN'; pre_sign += key; return CryptoJS.MD5(pre_sign).toString(); } //作用:生成toast,让其在toast_container中,显示在页面中上部,会永久性向页面添加一个id为ths_toast_container的div标签 function showStackToast(message, backcolor='rgb(76, 175, 80)', timeout=3000){ //没有容器则生成容器 let box=document.querySelector("body > div#ths_toast_container"); if(!box){ box=document.createElement('div'); box.id="ths_toast_container"; box.style.cssText = ` position: fixed; top: 10px; left: 50%; transform: translateX(-50%); right: 10px; width: 300px; height: auto; display: flex; z-index: 9999; flex-direction: column-reverse;`; document.body.appendChild(box); } //创建toast const toast = document.createElement('div'); toast.innerText = message; toast.style.cssText = ` padding: 10px; background-color: ${backcolor}; color: rgb(255, 255, 255); border-radius: 10px; font-size: 24px; font-weight: bold; text-align: center; box-shadow: rgb(0 0 0 / 30%) 0px 5px 10px; opacity: 1; transition: opacity 0.3s ease-in-out 0s; z-index: 9999; margin: 5px; `; box.appendChild(toast); toast.style.opacity = 1; if(timeout > 0){ setTimeout(() => { toast.style.opacity = 0; setTimeout(() => { box.removeChild(toast); }, 300); }, timeout); } return toast; } class NetworkError extends Error { constructor(message) { super(message); this.name = "NetworkError"; } } //api='https://mmnew.tlxxw.cc/api/list/base'; async function query(url, obj={}){ let data=''; try{ //data=encrypt(JSON.stringify(obj)); //data=JSON.stringify(obj); }catch(e){ console.log("发送包aes加密失败"); console.log(obj); console.log(key); console.log(gzip); throw e; } const ret = await fetch(url, { method: 'GET', headers: { //'Content-Type': 'application/json' }}) .then(function(response) { if(!response.ok) { throw new NetworkError(`HTTP error! status: ${response.status}`); } return response.text(); }).catch(error => { if (error instanceof NetworkError) { console.error("Network error: ", error.message); throw error; } else { console.error("Other error: ", error); //alert("发生其他错误"); throw error; } }); const tmp=JSON.parse(ret); if(!tmp || 0!==tmp.code){ showStackToast("解析返回包失败!","red"); console.log(tmp); throw Error("解析返回包失败!"); } //解密返回包 try{ data=decrypt(tmp.data, tmp.suffix); }catch(e){ console.log("返回包aes解密失败"); console.log(tmp); console.log(key); throw e; } return data; } //作用:弹出新窗口播放指定m3u8视频 function playMedia(mediaUrl, width=800, height=600) { /* 第三个参数规定了新窗口的大小,不加则会以新窗口的形式出现 */ var windowHandle = window.open("", "_blank", `width=${width}, height=${height}`); windowHandle.document.write(` <html> <head> <script src="https://cdn.staticfile.net/dplayer/1.27.1/DPlayer.min.js"></script> <script src="https://cdn.staticfile.net/hls.js/1.5.1/hls.min.js"></script> </head> <body> <div id="dplayer"></div> <script> //var url = prompt("请输入要播放的视频url"); var dp = new DPlayer({ container: document.getElementById('dplayer'), autoplay: true, theme: '#FADFA3', loop: true, lang: 'zh', screenshot: true, hotkey: true, preload: 'auto', video: { url: "${mediaUrl}", type: 'hls' } }); </script> </body> </html> `); } //await query("https://utt.51jiajiao.top/data/index/home.js?1718510400000"); //插入视频条目执行函数 async function insertList(box, videoList){ showStackToast("正在破解中..."); //修改第一个容器内的标识 box.firstElementChild.firstElementChild.innerText="已破解VIP视频"; let list=box.querySelector("div:nth-child(2) > div"); //循环添加事件 for(let i=0; i < videoList.length && i < list.childNodes.length; i++){ //先去除绑定 list.childNodes[i].onclick= () => { if(!videoList[i].video_url){ alert("未找到该视频地址"); throw Error("未找到该视频地址"); } let video_url=videoList[i].video_url.replaceAll('//', '/') let m3u8url=settings['m3u8Prefix']+video_url; m3u8url=m3u8url+addVidKeyParam2(video_url); showStackToast("视频地址获取成功,将弹窗播放"); showStackToast(videoList[i].title); console.log(m3u8url); console.log(videoList[i]); playMedia(m3u8url); }; } showStackToast("破解完成!"); } //获取当前时间戳 function getTime(){ var time = new Date(); if (time.getHours() < 4){ time.setHours(0, 0, 0, 0) } else if (time.getHours() < 8){ time.setHours(4, 0, 0, 0) } else if (time.getHours() < 12){ time.setHours(8, 0, 0, 0) } else if (time.getHours() < 16){ time.setHours(12, 0, 0, 0) } else if (time.getHours() < 20){ time.setHours(16, 0, 0, 0) } else if (time.getHours() < 24){ time.setHours(20, 0, 0, 0) } else{ time.setHours(24, 0, 0, 0) } let ts = time.getTime(); return ts; } //main要执行的内容 async function main_func(){ //let apiUrl=settings["apiPrefix"]+"/data/index/home.js?"+getTime(); let apiUrl=settings["apiPrefix"]+"/data/index/home.js?"; //showStackToast(apiUrl); const ret = await query(apiUrl); if(!ret || !ret.vip_list || !ret.vip_list.data){ alert("api访问异常"); throw Error("api访问异常"); } showStackToast(`成功找到【${ret.vip_list.data.length}】个vip视频`); //查找box let box = document.querySelector("div.mw1100 > div:nth-child(1)"); if(!box){ showStackToast("未找到box!", "red"); throw Error("未找到box!"); } showStackToast("成功找到box!"); insertList(box, ret.vip_list.data); } ///page/vip/和/page/remen/的执行内容 async function func_list(user_id=0){ let urlType=mediaTypes[mediaType]; if(undefined === urlType){ alert("脚本异常,urlType为空"); throw Error("脚本异常,urlType为空"); } //let apiUrl=settings["apiPrefix"]+"/data/list/"+urlType+pageIndex+".js?"+getTime(); let apiUrl=settings["apiPrefix"]+"/data/list/"+urlType+pageIndex+".js?"; //showStackToast(apiUrl); const ret = await query(apiUrl); if(!ret || !ret.list || !ret.list.data){ alert("api访问异常"); throw Error("api访问异常"); } showStackToast(`成功找到【${ret.list.data.length}】个vip视频`); //查找box let box = document.querySelector("div.mw1100"); if(!box){ showStackToast("未找到box!", "red"); throw Error("未找到box!"); } showStackToast("成功找到box!"); insertList(box, ret.list.data); //找到上一页、下一页按钮容器 let pagination=document.querySelector("div.fl.align_center.justify_center.gap20.mb20"); //清空原有按钮 //pagination.innerHTML=''; pagination.removeChild(pagination.lastChild); pagination.removeChild(pagination.firstChild); pagination.removeChild(pagination.childNodes[1]); //找到上一页按钮 var prePage=pagination.firstChild; prePage.textContent="上一页"; prePage.setAttribute("style", "padding: 5px .6rem;border: 1px solid #bebebd;text-align: center;border-radius: 7px;cursor: pointer;background: #fff;"); //pagination.appendChild(prePage); //绑定事件 prePage.addEventListener("click", async () => { if(pageIndex<=1){ showStackToast(`当前page为${pageIndex},不能再向上一页`); throw Error(`当前page为${pageIndex},不能再向上一页`); } pageIndex-=1; //apiUrl=settings["apiPrefix"]+"/data/list/"+urlType+pageIndex+".js?"+getTime(); apiUrl=settings["apiPrefix"]+"/data/list/"+urlType+pageIndex+".js?"; //showStackToast(apiUrl); const ret = await query(apiUrl); if(!ret || !ret.list || !ret.list.data){ alert("api访问异常"); throw Error("api访问异常"); } showStackToast(`成功找到【${ret.list.data.length}】个vip视频`); insertList(box, ret.list.data); }); //找到下一页按钮 var nextPage=pagination.lastChild; nextPage.textContent="下一页"; nextPage.setAttribute("style", "padding: 5px .6rem;border: 1px solid #bebebd;text-align: center;border-radius: 7px;cursor: pointer;background: #fff;"); //pagination.appendChild(nextPage); //绑定事件 nextPage.addEventListener("click", async () => { pageIndex+=1; //apiUrl=settings["apiPrefix"]+"/data/list/"+urlType+pageIndex+".js?"+getTime(); apiUrl=settings["apiPrefix"]+"/data/list/"+urlType+pageIndex+".js?"; //showStackToast(apiUrl); const ret = await query(apiUrl); if(!ret || !ret.list || !ret.list.data){ alert("api访问异常"); throw Error("api访问异常"); } showStackToast(`成功找到【${ret.list.data.length}】个vip视频`); insertList(box, ret.list.data); }); } // 主函数:检验是否在可执行域,不是则不管 async function mainFunction(){ //每次执行都重置pageIndex pageIndex=1; if('/home'===window.location.pathname){ //执行main相关内容 showStackToast("当前位于main页面"); setTimeout(async () => { await main_func(); }, 2000); } else if(-1!==window.location.pathname.search("/page/vip/") || -1!==window.location.pathname.search("/page/remen/")){ //执行video_list相关内容 showStackToast("当前位于list页面"); //修改mediaType const e=window.location.pathname.match(/(\d+)$/); if(!e || e.length < 2){ alert(`没有找到type,当前url为${window.location}`); throw Error(`没有找到type,当前url为${window.location}`); } if(!e[1] in mediaTypes){ showStackToast("未找到vip视频标识,将忽略"); throw Error("未找到vip视频标识,将忽略"); } mediaType=e[1]; setTimeout(async () => { await func_list(); }, 300); } //否则什么也不执行 } setTimeout(async () => { 'use strict'; //alert("测试"); // console.log(encrypt); // console.log(decrypt);//decrypt用于方便调试 // console.log(query); // console.log(getSignature); // console.log(addVidKeyParam2); let previousUrl = ''; const observer = new MutationObserver(async function(mutations) { let nowUrl=window.location.href; if (nowUrl !== previousUrl) { console.log(`URL changed from ${previousUrl} to ${window.location.href}`); previousUrl = nowUrl; await mainFunction(); } }); const config = {subtree: true, childList: true}; observer.observe(document, config); }, 500);