含羞草

含羞草-解析脚本,永久导航http://www.Fi11.app 中转地址:http://www.pmeaqve.cn 遇到播放地址为旧播放地址或者无反应,请自行多刷新几次当前页面,重新播放即可

  1. // ==UserScript==
  2. // @name 含羞草
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.3.0
  5. // @description 含羞草-解析脚本,永久导航http://www.Fi11.app 中转地址:http://www.pmeaqve.cn 遇到播放地址为旧播放地址或者无反应,请自行多刷新几次当前页面,重新播放即可
  6. // @author 院长
  7. // @match *://*/play/video/*
  8. // @match *://*/live/*
  9. // @match *://h5.*.com/home
  10. // @match *://h5.*.cn/home
  11. // @match *://www.*.com/home
  12. // @match *://www.*.cn/home
  13. // @match *://h5.*.com/play/video/*
  14. // @match *://h5.*.cn/play/video/*
  15. // @match *://www.*.com/play/video/*
  16. // @match *://www.*.cn/play/video/*
  17. // @include /^.*?://.*?\.fi.*?\.com.*?$/
  18. // @include /^.*?://.*?\.hx.*?\.com.*?$/
  19. // @include /^.*?://.*?/play/video.*?$/
  20. // @include /^.*?://(www|h5)\..*?\.com/play/video/.*?$/
  21. // @include /^.*?://(www|h5)\..*?\.cn/play/video/.*?$/
  22. // @icon https://www.google.com/s2/favicons?sz=64&domain=3kjs.com
  23. // @grant none
  24. // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
  25. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js
  26. // @require https://cdnjs.cloudflare.com/ajax/libs/dplayer/1.26.0/DPlayer.min.js
  27. // @require https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.1.5/hls.min.js
  28. // @run-at document-end
  29. // ==/UserScript==
  30.  
  31. //中转地址:http://www.zhongyouchuanmei.xyz
  32. //含羞草永久导航:http://www.Fi11.tv http://fi11.com http://fi11.cn http://www.Fi11.live http://www.fi11av.com
  33. //打开永久导航中的最新网址即可,若是脚本框架需要匹配域名,自行将导航中的最新网址填上即可
  34. //遇到播放地址为旧播放地址或者无反应,请自行刷新当前页面,重新播放即可
  35.  
  36.  
  37. /**********************************/
  38.  
  39. /*
  40. 含羞草-解析脚本
  41. 参考来源https://yaohuo.me/bbs-1210512.html
  42.  
  43. 实现游客无限试用,无限获取真实播放地址
  44.  
  45. 已兼容手机和电脑
  46.  
  47. */
  48. /**********************************/
  49.  
  50.  
  51.  
  52.  
  53. // 权限认证标识
  54. const TOKEN = 'hxc_1.0.0_token';
  55. // 服务地址
  56. //let baseUrl = location.origin;
  57. let baseUrl = "https://ap988.hydzswyxgs.com";
  58. // 视频试看地址
  59. //const PRE_URL = baseUrl + '/api/videos/getPreUrl';
  60. const PRE_URL = baseUrl + '/videos/getPreUrl';
  61. // 手机免费视频地址
  62. const PRE_URL_V2 = baseUrl + '/videos/v2/getUrl';
  63. // 用户注册地址
  64. //const REG_URL = baseUrl + '/api/login/userReg';
  65. const REG_URL = baseUrl + '/login/userReg';
  66. //获取cid地址
  67. //const DETAIL_URL = baseUrl + '/api/gather/getDetail';
  68. const DETAIL_URL = baseUrl + '/gather/getDetail';
  69. var videoUrl = "";
  70.  
  71.  
  72.  
  73.  
  74. // 参数加密
  75. function Encrypt(word) {
  76. let keyStr = 'B77A9FF7F323B5404902102257503C2F';
  77. const key = CryptoJS.enc.Utf8.parse(keyStr);
  78. const iv = CryptoJS.enc.Utf8.parse(keyStr);
  79. const srcs = CryptoJS.enc.Utf8.parse(word);
  80. const encrypted = CryptoJS.AES.encrypt(srcs, key, {
  81. iv: iv,
  82. mode: CryptoJS.mode.CBC,
  83. padding: CryptoJS.pad.Pkcs7
  84. });
  85. return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
  86. }
  87.  
  88. // 请求封装
  89. const fetchData = async (url, body) => {
  90. const Z = new Date;
  91. //console.log("服务器系统时间戳",parseInt(Z.getTime() / 1e3) + Z.getTimezoneOffset() * 60)
  92. return fetch(url, {
  93. method: 'post',
  94. body: JSON.stringify({
  95. endata: Encrypt(JSON.stringify(body)),
  96. ents:Encrypt(parseInt(Z.getTime() / 1e3) + Z.getTimezoneOffset() * 60),
  97. }),
  98. headers: {
  99. // 携带认证头
  100. auth: localStorage.getItem(TOKEN)?.replace(/"/g, ''),
  101. 'Content-Type': 'application/json'
  102. }
  103. });
  104. };
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111. // 去除限制
  112. const setValue = async () => {
  113. let isDetail = location.href.includes('play/video');
  114. if (isDetail) {
  115. //判断是h5还是电脑,或者是合集视频
  116. let videoId = location.href.match(/.+\/h5\..+\/play\/video\/(\d+)\/.+/)||location.href.match(/.+\/www\..+\/play\/video\/(\d+)\/.+/);
  117. if(!videoId){
  118. videoId = location.href.match(/.+\/play\/video\/(\d+)/)[1];
  119. //电脑
  120. //console.log("电脑")
  121. var preInfo = localStorage.getItem("preInfo");
  122. if(preInfo){
  123. preInfo = JSON.parse(preInfo)
  124. preInfo.count = 0;
  125. preInfo = JSON.stringify(preInfo)
  126. localStorage.setItem("preInfo", preInfo);
  127. }
  128.  
  129. //await setElement("pc",videoId);
  130. //console.log("最后的视频url:" + videoUrl)
  131.  
  132. videoId = getVideoId()
  133. //用于判定当前页面的videoId是否变化
  134. if (window.videoId == videoId) {
  135. return
  136. }
  137. await pc()
  138. }else{
  139. //手机
  140. //console.log(`-----------判断是手机:${videoId}`);
  141. let isCid = location.href.match(/.+\/h5\..+\/play\/video\/(\d+)\/1?videoId=.+/)||location.href.match(/.+\/www\..+\/play\/video\/(\d+)\/1?videoId=.+/);
  142. videoId = videoId[1];
  143. //合集视频
  144. if(isCid){
  145. //console.log(`-----------判断是isCid:${isCid}`);
  146. let url_list = isCid[0].split('1?videoId=');
  147. //带了videoId=后缀
  148. if(url_list.length>1){
  149. videoId = url_list[1];
  150. //console.log(`-----------videoId:${videoId}`);
  151. }else{
  152. //console.log(`-----------isCid:${videoId}`);
  153. videoId = await isListId(isCid[1]);
  154. }
  155. }
  156. //console.log(videoId)
  157. var tryPlayNum = localStorage.getItem("tryPlayNum");
  158. if(tryPlayNum){
  159. tryPlayNum = JSON.parse(tryPlayNum)
  160. tryPlayNum.num = 0;
  161. tryPlayNum = JSON.stringify(tryPlayNum)
  162. localStorage.setItem("tryPlayNum", tryPlayNum);
  163. }
  164. //await setElement("mobile",videoId);
  165. //新增判断合集
  166. if (!(window.location.href.endsWith("0") || window.location.href.endsWith("1")|| location.href.match(/.+1?videoId=/))) {
  167. return
  168. }
  169. //console.log("执行到这来了========================")
  170. videoId = await getVideoId();
  171. if (window.videoId == videoId) {
  172. return
  173. }
  174. //console.log("执行手机操作========================")
  175. await mobile()
  176. }
  177.  
  178. //console.log("最后的视频ID:" + videoId);
  179. var videoId_File = localStorage.getItem("videoId");
  180. //console.log("===========================")
  181. if(videoId_File && videoId_File === videoId){
  182. //console.log("----------------------------")
  183. return
  184. }
  185. localStorage.setItem("videoId", videoId);
  186. }
  187.  
  188.  
  189. }
  190.  
  191.  
  192. function importJS(src) {
  193. let script = document.createElement('script');
  194. script.src = src;
  195. document.head.appendChild(script);
  196. }
  197.  
  198. //导包
  199. function importLib() {
  200. importJS("https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js")
  201. importJS("https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js")
  202. importJS("https://cdn.bootcdn.net/ajax/libs/dplayer/1.26.0/DPlayer.min.js")
  203. importJS("https://cdn.bootcdn.net/ajax/libs/hls.js/1.1.5/hls.min.js")
  204. }
  205.  
  206. //判断是否为合集,返回第一集
  207. async function isListId(cid){
  208. let json = await fetchData(DETAIL_URL, {
  209. gatherId: Number(cid)
  210. }).then(response => {
  211. return response.json();
  212. });
  213. return json.data.info.videos[0].id;
  214. }
  215.  
  216.  
  217. //获取视频id
  218. async function getVideoId() {
  219. //console.log("匹配视频id")
  220. let url = window.location.href;
  221. let url_list = url.split('0?cid=');
  222. let videoId = 0;
  223. if(url_list.length<2){
  224. //手机模式,普通视频
  225. if (url.endsWith("0")) {
  226. let urlSplited = url.split("play/video")
  227. urlSplited = urlSplited[1].split("/")
  228. videoId = urlSplited[1]
  229. //console.log("匹配普通视频id:"+videoId)
  230. return parseInt(videoId);
  231. }
  232. //匹配手机模式合集
  233. if (url.endsWith("/1")) {
  234. let urlSplited = url.split("play/video")
  235. urlSplited = urlSplited[1].split("/")
  236. //console.log("匹配手机模式合集cid:"+urlSplited[1])
  237. videoId = await isListId(urlSplited[1])
  238. //console.log("videoId:"+videoId)
  239. return parseInt(videoId);
  240. }
  241. if(url.match(/.+1?videoId=/)){
  242. videoId = url.split('1?videoId=')[1];
  243. return parseInt(videoId);
  244. }
  245. //通用视频
  246. let urlSplited = url.split("/");
  247. videoId = urlSplited[urlSplited.length - 1];
  248. }else{
  249. //电脑模式合集
  250. videoId = await isListId(url_list[1])
  251. //console.log("电脑模式合集cid:"+videoId)
  252. }
  253.  
  254. return parseInt(videoId);
  255. }
  256.  
  257.  
  258. //获取视频链接(区分手机和电脑)
  259. async function getVideoUrl(type,videoId){
  260. //很重要,区分是否当前页的id
  261. window.videoId = videoId
  262. //删除参数
  263. var waibubofan = "#waibubofan";
  264. var shipindizhi = "#shipindizhi";
  265. var delete_waibubofan = document.querySelectorAll(waibubofan);
  266. var delete_shipindizhi = document.querySelectorAll(shipindizhi);
  267. //先删除按键
  268. if(delete_waibubofan){
  269. for(let i=0;i<delete_waibubofan.length;i++){
  270. //console.log(`删除外部播放按键:${i}`)
  271. delete_waibubofan[i].remove()
  272. }
  273. }
  274. if(delete_shipindizhi){
  275. for(let i=0;i<delete_shipindizhi.length;i++){
  276. //console.log(`删除视频地址按键:${i}`)
  277. delete_shipindizhi[i].remove()
  278. }
  279. }
  280.  
  281. //设置按钮
  282. let selectorParam = ".el-divider.el-divider--horizontal";
  283. if(type == "mobile"){
  284. selectorParam = ".tendency-row";
  285.  
  286. }
  287. let json =await fetchData(PRE_URL, {
  288. videoId: Number(videoId)
  289. }).then(response => {
  290. return response.json();
  291. });
  292. const isSuccess = !!json.data.url;
  293. let el = document.querySelector(selectorParam);
  294. let a = document.createElement('a');
  295. a.style =
  296. 'display:block;font-size:18px;padding:12px;color:#1890ff;';
  297. a.text = isSuccess ? '视频地址' : '获取失败';
  298. a.target = "_blank";
  299. a.id = "shipindizhi";
  300. if (isSuccess) {
  301. let parseUrl = json.data.url.replace(/start=\d+&end=\d+/, '').replace("?&sign", '?sign');
  302. a.href = parseUrl;
  303. // 获取ts切片
  304. let m3u8Str = await fetch(parseUrl).then(async res => {
  305. let m3u8Str = await res.text();
  306. return m3u8Str
  307. });
  308. // 提取第一条记录
  309. let tsUrl = m3u8Str.split('\n').find(item => {
  310. return /^[^#]/.test(item);
  311. });
  312. // 拼接
  313. //const linkUrl =
  314. 'https://m3u8play.com/?play=' +
  315. new URL(parseUrl).origin +
  316. tsUrl;
  317. //新增地址
  318. const linkUrl = 'https://m3u8play.com/?play=' + encodeURI(parseUrl);
  319. //videoUrl = new URL(parseUrl).origin + tsUrl;
  320. //新增地址
  321. videoUrl = parseUrl;
  322. let external = document.createElement('a');
  323. external.style =
  324. 'display:block;font-size:18px;padding:12px;color:#1890ff;';
  325. external.text = '外部播放';
  326. external.href = linkUrl;
  327. external.target = "_blank";
  328. external.id = "waibubofan";
  329. if(el){
  330. el.parentNode.insertBefore(external, el);
  331. }
  332. }else{
  333. //获取失败直接返回
  334. return;
  335. }
  336. if(el){
  337. el.parentNode.insertBefore(a, el);
  338. }
  339.  
  340. return videoUrl;
  341. }
  342.  
  343.  
  344. //电脑播放
  345. function play(playerUrl, pic, container, playType) {
  346. container.style.zIndex = 99999
  347. var videoObject = {
  348. container: '#v_prism', //容器的ID或className
  349. // live: true,//指定为直播
  350. //seek: 'cookie',//指定跳转到cookie记录的时间,使用该属性必需配置属性cookie
  351. cookie: 'abcdefg',//cookie名称,请在同一域中保持唯一
  352. plug: 'hls.js',//使用hls.js插件播放m3u8
  353. video: playerUrl//视频地址
  354. }
  355. window.ck = new ckplayer(videoObject);
  356. //window.ck.volume(0.5);//修改音量为0.5
  357. window.ck.volume(1);
  358. window.ck.play()
  359. }
  360.  
  361. //手机播放
  362. function mobilePlay(playerUrl, pic, container, playType) {
  363. container.style.zIndex = 99999
  364. window.dp = new DPlayer({
  365. container: container, // 可选,player元素
  366. autoplay: false, // 可选,自动播放视频,不支持移动浏览器
  367. theme: '#FADFA3', // 可选,主题颜色,默认: #b7daff
  368. loop: true, // 可选,循环播放音乐,默认:true
  369. lang: 'zh', // 可选,语言,`zh'用于中文,`en'用于英语,默认:Navigator language
  370. screenshot: true, // 可选,启用截图功能,默认值:false,注意:如果设置为true,视频和视频截图必须启用跨域
  371. hotkey: true, // 可选,绑定热键,包括左右键和空格,默认值:true
  372. preload: 'auto', // 可选,预加载的方式可以是'none''metadata''auto',默认值:'auto'
  373. video: { // 必需,视频信息
  374. url: playerUrl, // 必填,视频网址
  375. pic: pic, // 可选,视频截图
  376. thumbnails: pic
  377. }
  378. });
  379. }
  380.  
  381.  
  382. async function pc() {
  383. if (window.location.href.endsWith("home")) {
  384. return
  385. }
  386. let videoId = await getVideoId();
  387. //let videoUrl = await getVideoUrl(videoId)
  388. let videoUrl = await getVideoUrl("pc",videoId)
  389. if (videoUrl == null) {
  390. return
  391. }
  392. let pic = document.querySelector(".el-image.overflow-hidden > img")
  393. if (pic) {
  394. pic = pic.getAttribute("src")
  395. }
  396. let container = document.querySelector("#v_prism")
  397. let playType = 'live'
  398. let elem = document.querySelector(".vip-mask")
  399. if (elem) {
  400. elem.remove()
  401. }
  402. elem = document.querySelector(".el-image.overflow-hidden")
  403. if (elem) {
  404. elem.remove()
  405. }
  406. elem = document.querySelector(".top-0.left-0.w-full.h-full.overflow-hidden")
  407. if (elem) {
  408. elem.remove()
  409. }
  410. elem = document.querySelector(".vip-mask > div")
  411. if (elem) {
  412. elem.remove()
  413. }
  414.  
  415. elem = document.querySelector(".absolute.bg-overlay")
  416. if (elem) {
  417. elem.remove()
  418. }
  419. //console.log(`-----------执行播放电脑视频事件-------------`);
  420. //console.log(`-----------视频地址:${videoUrl}`);
  421. play(videoUrl, pic, container, playType)
  422. //await setElement("pc",videoId);
  423. }
  424.  
  425. async function mobile() {
  426. if (!(window.location.href.endsWith("0") || window.location.href.endsWith("1")|| location.href.match(/.+1?videoId=/))) {
  427. return
  428. }
  429. let videoId = await getVideoId()
  430. //let videoUrl = await getVideoUrl(videoId)
  431. let videoUrl = await getVideoUrl("mobile",videoId)
  432. console.log(`-----------视频地址:${videoUrl}`);
  433. if (videoUrl == null) {
  434. return
  435. }
  436.  
  437. let pic = document.querySelector(".pub-video-poster")
  438. if (pic) {
  439. pic = pic.getAttribute("src")
  440. }
  441. //container = document.querySelector(".van-sticky")
  442. let container = document.querySelector("#video1")
  443. let playType = 'live'
  444. //document.querySelector(".try-detail-video").remove()
  445. mobilePlay(videoUrl, pic, container, playType)
  446. //await setElement("mobile",videoId);
  447. }
  448.  
  449.  
  450. async function main() {
  451. //console.log(`-----------启动-------------`);
  452. /**********************************/
  453. // hook: 拦截路由地址变化
  454. const _historyWrap = function (type) {
  455. const orig = history[type];
  456. const e = new Event(type);
  457. return function () {
  458. const rv = orig.apply(this, arguments);
  459. e.arguments = arguments;
  460. window.dispatchEvent(e);
  461. return rv;
  462. };
  463. };
  464. // 监听路由操作
  465. ['pushState', 'replaceState'].forEach(method => {
  466. history[method] = _historyWrap(method);
  467. window.addEventListener(method, () => {
  468. //console.log('当前URL为:', document.location.href);
  469. setValue();
  470. });
  471. });
  472.  
  473. window.addEventListener('popstate', function(event) {
  474. //console.log('当前URL为:', document.location.href);
  475. //setValue();
  476. });
  477. /**********************************/
  478. importLib()
  479. }
  480.  
  481.  
  482. main()
  483.  
  484. window.onload = function() {
  485. let elem = document.querySelector(".vip-mask")
  486. if (elem) {
  487. elem.remove()
  488. }
  489. };