找回密码
 立即注册
查看: 4|回复: 1

m3u8视频提取 抓取影视站真实播放链接

[复制链接]
发表于 昨天 23:57 | 显示全部楼层 |阅读模式
很多影视聚合站都在 m3u8 里面直接加入广告,并且切片 url 都用 md5 混淆,想通过特征来去除基本上不太可能了,于是找了个无广告的视频站,试着直接抓一下播放链接。

首先打开站点 https://www.keke1.app/
f12 无效,通过浏览器菜单打开开发者工具
开启了防 debugger

点击确定,重新加载,在弹窗重新打开时不要点确定,查看接口请求,发现 vf.mgdnka.cn/vod_pc_static_kkdy/frameworks/disable-devtool/latest/index.min.js?ver=ffffeee,直接添加到 Network request blocking,刷新后可以正常 debugger



首先检查一下播放页html,代码很多,那基本上就排除了通过 js 来加载播放链接的逻辑,大概率是在 html 页里面,翻一下代码,看到有个显眼的 gogogo 函数:

  1. ...
  2. const parameterName = "role";
  3.             const paramValue = getURLParameter(window.location.search, parameterName);
  4.                             if (paramValue !== null && md5(paramValue) == 'b18c4beb8b0b9077b37af22a01324c23') {
  5.                     gogogo()
  6.                 } else {
  7.                     fetchWithTimeout(window.whatTMDwhatTMDApiDomain + '/app/userArea', 5000)
  8.                         .then(async data => {
  9.                             if (data.country == 'China' && data.countryCode == 'CN') {
  10.                                 gogogo()
  11.                             } else {
  12.                                 OFFICIALPOPUP.show(await getAlertDLPopupConfiguration("安装APP,免费观看4K超清影片", "对不起,您所在的地区可以使用APP观看。"));
  13.                             }
  14.                         })
  15.                         .catch(error => {
  16.                             console.error('Error occurred:', error);
  17.                             gogogo()
  18.                             OFFICIALPOPUP.hide();
  19.                         });
  20.                 }
  21.                         let clickTimer = null;
  22. ...
复制代码


找到 gogogo 函数,发现做了混淆,丢个 chatgpt 看看,不得不说有了 AI 之后这个效率杠杠的

  1. gogogo() {
  2.                 var _0xee81bd=(711499^711490)+(862694^862691);const playSource={'\u0073\u0072\u0063':"\u0068\u0074\u0074\u0070\u0073\u003A\u002F\u002F\u0073\u0076\u0069\u0070\u0073\u0076\u0069\u0070\u002E\u0066\u0066\u007A\u0079\u0072\u0065\u0061\u0064\u0031\u002E\u0063\u006F\u006D\u002F\u0032\u0030\u0032\u0035\u0030\u0031\u0032\u0033\u002F\u0033\u0035\u0033\u0030\u0034\u005F\u0036\u0032\u0034\u0034\u0032\u0061\u0061\u0061\u002F\u0069\u006E\u0064\u0065\u0078\u002E\u006D\u0033\u0075\u0038",'\u0074\u0079\u0070\u0065':"\u0061\u0070\u0070\u006C\u0069\u0063\u0061\u0074\u0069\u006F\u006E\u002F\u0078\u002D\u006D\u0070\u0065\u0067\u0055\u0052\u004C"};_0xee81bd=(795600^795609)+(424590^424591);let _0x8b5gb;const config={"lang":'zh',"id":"\u006D\u0079\u002D\u0076\u0069\u0064\u0065\u006F",'\u0061\u0075\u0074\u006F\u0070\u006C\u0061\u0079':!![],'\u0075\u0072\u006C':KKYS['\u0073\u0061\u0066\u0065\u0050\u006C\u0061\u0079']()['\u0075\u0072\u006C']("\u0049\u0073\u0075\u0037\u0066\u004F\u0041\u0076\u0049\u0036\u0021\u0026\u0049\u004B\u0070\u0041\u0062\u0056\u0064\u0068\u0066\u0026\u005E\u0046"),"playsinline":!![],'\u0070\u0069\u0070':!![],"keyShortcut":'on','\u0068\u0065\u0069\u0067\u0068\u0074':"\u0031\u0030\u0030\u0025",'\u0077\u0069\u0064\u0074\u0068':"\u0031\u0030\u0030\u0025","plugins":[],'x5-video-player-type':'h5',"\u0078\u0035\u002D\u0076\u0069\u0064\u0065\u006F\u002D\u0070\u006C\u0061\u0079\u0065\u0072\u002D\u0066\u0075\u006C\u006C\u0073\u0063\u0072\u0065\u0065\u006E":!![],"\u0078\u0035\u002D\u0076\u0069\u0064\u0065\u006F\u002D\u006F\u0072\u0069\u0065\u006E\u0074\u0061\u0074\u0069\u006F\u006E":"\u006C\u0061\u006E\u0064\u0073\u0063\u0061\u0070\u0065",'\u0063\u006F\u006D\u006D\u006F\u006E\u0053\u0074\u0079\u006C\u0065':{"playedColor":'var(--fs-primary-color)','\u0076\u006F\u006C\u0075\u006D\u0065\u0043\u006F\u006C\u006F\u0072':'var(--fs-primary-color)'},"playbackRate":{'\u006C\u0069\u0073\u0074':[{"text":"\u0032\u002E\u0030\u0058",'\u0072\u0061\u0074\u0065':2.0},{"text":"\u0031\u002E\u0035\u0058",'\u0072\u0061\u0074\u0065':1.5},{"text":"\u0031\u002E\u0032\u0035\u0058",'\u0072\u0061\u0074\u0065':1.25},{"text":'1X',"iconText":'倍速','\u0072\u0061\u0074\u0065':1},{"text":'0.75X','\u0072\u0061\u0074\u0065':0.75},{'\u0074\u0065\u0078\u0074':"\u0030\u002E\u0035\u0058",'\u0072\u0061\u0074\u0065':0.5}]}};_0x8b5gb='\u0068\u006C\u0062\u0068\u0068\u0069';if(playSource['\u0074\u0079\u0070\u0065']=="\u0061\u0070\u0070\u006C\u0069\u0063\u0061\u0074\u0069\u006F\u006E\u002F\u0078\u002D\u006D\u0070\u0065\u0067\u0055\u0052\u004C"&&HlsPlayer['\u0069\u0073\u0053\u0075\u0070\u0070\u006F\u0072\u0074\u0065\u0064']()){config['\u0070\u006C\u0075\u0067\u0069\u006E\u0073']['\u0070\u0075\u0073\u0068'](window['\u0048\u006C\u0073\u0050\u006C\u0061\u0079\u0065\u0072']);config['\u0068\u006C\u0073']={"retryCount":30,'\u0072\u0065\u0074\u0072\u0079\u0044\u0065\u006C\u0061\u0079':1000,'\u006C\u006F\u0061\u0064\u0054\u0069\u006D\u0065\u006F\u0075\u0074':10000,"fetchOptions":{"mode":"\u0063\u006F\u0072\u0073","headers":{'\u004F\u0072\u0069\u0067\u0069\u006E':''},'\u0072\u0065\u0066\u0065\u0072\u0072\u0065\u0072':"\u006E\u006F\u002D\u0072\u0065\u0066\u0065\u0072\u0072\u0065\u0072"}};}else if(playSource['\u0074\u0079\u0070\u0065']=="\u0076\u0069\u0064\u0065\u006F\u002F\u006D\u0070\u0034"){config['\u0070\u006C\u0075\u0067\u0069\u006E\u0073']['\u0070\u0075\u0073\u0068'](window['\u004D\u0070\u0034\u0050\u006C\u0075\u0067\u0069\u006E']);config['\u006D\u0070\u0034\u0070\u006C\u0075\u0067\u0069\u006E']={'\u006D\u0061\u0078\u0042\u0075\u0066\u0066\u0065\u0072\u004C\u0065\u006E\u0067\u0074\u0068':50,'\u006D\u0069\u006E\u0042\u0075\u0066\u0066\u0065\u0072\u004C\u0065\u006E\u0067\u0074\u0068':10};}else{}xgplayer=new window['\u0050\u006C\u0061\u0079\u0065\u0072'](config);var _0x351b1d=(482744^482748)+(448319^448319);const playProgress=window['\u006C\u006F\u0063\u0061\u006C\u0053\u0074\u006F\u0072\u0061\u0067\u0065']['\u0067\u0065\u0074\u0049\u0074\u0065\u006D'](config['\u0075\u0072\u006C']);_0x351b1d='\u0064\u0071\u0064\u0064\u0064\u006E';if(playProgress){xgplayer['\u0063\u0075\u0072\u0072\u0065\u006E\u0074\u0054\u0069\u006D\u0065']=parseFloat(playProgress);}const Events=window['\u0050\u006C\u0061\u0079\u0065\u0072']['\u0045\u0076\u0065\u006E\u0074\u0073'];xgplayer['\u006F\u006E'](Events['\u004C\u004F\u0041\u0044\u005F\u0053\u0054\u0041\u0052\u0054'],onPlayerLoadStartHandler);xgplayer['\u006F\u006E'](Events['\u004C\u004F\u0041\u0044\u0045\u0044\u005F\u0044\u0041\u0054\u0041'],onPlayerLoadedDataHandler);xgplayer['\u006F\u006E'](Events['\u0050\u004C\u0041\u0059'],onPlayerPlayHandler);xgplayer['\u006F\u006E'](Events['\u0050\u0041\u0055\u0053\u0045'],onPlayerPauseHandler);xgplayer['\u006F\u006E'](Events['\u0045\u004E\u0044\u0045\u0044'],onPlayerEndedHandler);xgplayer['\u006F\u006E'](Events['\u0045\u0052\u0052\u004F\u0052'],onPlayerErrorHandler);xgplayer['\u006F\u006E'](Events['\u0054\u0049\u004D\u0045\u005F\u0055\u0050\u0044\u0041\u0054\u0045'],onPlayerTimeUpdateHandler);xgplayer['\u006F\u006E'](Events['\u0057\u0041\u0049\u0054\u0049\u004E\u0047'],onPlayerWaitingHandler);xgplayer['\u006F\u006E'](Events['\u0053\u0045\u0045\u004B\u0049\u004E\u0047'],onPlayerSeekingHandler);xgplayer['\u006F\u006E'](Events['\u0053\u0045\u0045\u004B\u0045\u0044'],onPlayerSeekedHandler);updatePlayBoxSize();
  3.             }

  4. // 转换后
  5. function gogogo() {
  6.     var _0xee81bd = (711499 ^ 711490) + (862694 ^ 862691);

  7.     const playSource = {
  8.         src: "https://svipsvip.ffzyread1.com/20250123/35304_62442aaa/index.m3u8",
  9.         type: "application/x-mpegURL"
  10.     };

  11.     _0xee81bd = (795600 ^ 795609) + (424590 ^ 424591);
  12.     let _0x8b5gb;

  13.     const config = {
  14.         lang: 'zh',
  15.         id: "my-video",
  16.         autoplay: true,
  17.         url: KKYS.safePlay().url("Isu7fOAvI6!&IKpAbVdhf&^F"),
  18.         playsinline: true,
  19.         pip: true,
  20.         keyShortcut: 'on',
  21.         height: "100%",
  22.         width: "100%",
  23.         plugins: [],
  24.         'x5-video-player-type': 'h5',
  25.         'x5-video-player-fullscreen': true,
  26.         'x5-video-orientation': "landscape",
  27.         commonStyle: {
  28.             playedColor: 'var(--fs-primary-color)',
  29.             volumeColor: 'var(--fs-primary-color)'
  30.         },
  31.         playbackRate: {
  32.             list: [
  33.                 { text: "2.0X", rate: 2.0 },
  34.                 { text: "1.5X", rate: 1.5 },
  35.                 { text: "1.25X", rate: 1.25 },
  36.                 { text: "1X", iconText: '倍速', rate: 1 },
  37.                 { text: '0.75X', rate: 0.75 },
  38.                 { text: "0.5X", rate: 0.5 }
  39.             ]
  40.         }
  41.     };

  42.     _0x8b5gb = 'hlbhhi';

  43.     if (playSource.type === "application/x-mpegURL" && HlsPlayer.isSupported()) {
  44.         config.plugins.push(window.HlsPlayer);
  45.         config.hls = {
  46.             retryCount: 30,
  47.             retryDelay: 1000,
  48.             loadTimeout: 10000,
  49.             fetchOptions: {
  50.                 mode: "cors",
  51.                 headers: { Origin: '' },
  52.                 referrer: "no-referrer"
  53.             }
  54.         };
  55.     } else if (playSource.type === "video/mp4") {
  56.         config.plugins.push(window.Mp4Plugin);
  57.         config.mp4plugin = {
  58.             maxBufferLength: 50,
  59.             minBufferLength: 10
  60.         };
  61.     }

  62.     const xgplayer = new window.Player(config);

  63.     var _0x351b1d = (482744 ^ 482748) + (448319 ^ 448319);
  64.     const playProgress = window.localStorage.getItem(config.url);
  65.     _0x351b1d = 'qdddn';

  66.     if (playProgress) {
  67.         xgplayer.currentTime = parseFloat(playProgress);
  68.     }

  69.     const Events = window.Player.Events;
  70.     xgplayer.on(Events.LOAD_START, onPlayerLoadStartHandler);
  71.     xgplayer.on(Events.LOADED_DATA, onPlayerLoadedDataHandler);
  72.     xgplayer.on(Events.PLAY, onPlayerPlayHandler);
  73.     xgplayer.on(Events.PAUSE, onPlayerPauseHandler);
  74.     xgplayer.on(Events.ENDED, onPlayerEndedHandler);
  75.     xgplayer.on(Events.ERROR, onPlayerErrorHandler);
  76.     xgplayer.on(Events.TIME_UPDATE, onPlayerTimeUpdateHandler);
  77.     xgplayer.on(Events.WAITING, onPlayerWaitingHandler);
  78.     xgplayer.on(Events.SEEKING, onPlayerSeekingHandler);
  79.     xgplayer.on(Events.SEEKED, onPlayerSeekedHandler);

  80.     updatePlayBoxSize();
  81. }
复制代码


KKYS.safePlay().url(“Isu7fOAvI6!&IKpAbVdhf&^F”) 这一行就是获取实际代码的位置,打个断点,找到源码,丢给 chatgpt,让他写个解析的函数来:

  1. 'url': function(_0x568646=_0x3e87b3) {
  2.             function _0x2c39a9(_0x4a7539, _0x34f7c7, _0x1a2124, _0x3e7506) {
  3.                 return _0x391b7f(_0x4a7539 - -0x31, _0x34f7c7 - 0x188, _0x34f7c7, _0x3e7506 - 0xe9);
  4.             }
  5.             function _0xa69db3(_0x2bed71, _0x19d5be, _0x4387b3, _0x163261) {
  6.                 return _0x18be3a(_0x2bed71 - 0x68, _0x19d5be - 0x79, _0x4387b3 - -0x187, _0x19d5be);
  7.             }
  8.             if (_0x19b3dd[_0x2c39a9(-0x1ca, -0x218, -0x199, -0x225)] !== _0x19b3dd[_0xa69db3(-0x117, 0x4e, -0x7e, 0x2e)])
  9.                 try {
  10.                     var _0x527427 = CryptoJS[_0xa69db3(-0x188, -0xb6, -0xf5, -0x96)][_0x2c39a9(-0x167, -0x118, -0x117, -0x13e)]['parse'](_0x568646);
  11.                     let _0x264b22 = window[_0x2c39a9(-0x178, -0x11e, -0x148, -0xea) + _0xa69db3(-0xe8, -0x13f, -0xe3, -0x82)];
  12.                     var _0x33e517 = CryptoJS[_0x2c39a9(-0x1e3, -0x229, -0x12c, -0x297)]['Base64'][_0x2c39a9(-0xcf, -0xb2, -0x31, -0x150)](_0x264b22);
  13.                     const _0x240c87 = {};
  14.                     _0x240c87[_0xa69db3(-0xf4, -0xa8, -0x7f, -0x8a)] = _0x33e517;
  15.                     var _0x358b25 = CryptoJS[_0xa69db3(-0x14, -0xb2, -0x4d, 0x5c)][_0x2c39a9(-0xc1, -0x11, -0x11e, -0x1b)](_0x240c87, _0x527427, {
  16.                         'mode': CryptoJS[_0xa69db3(0x33, -0xa7, -0x30, 0x24)][_0x2c39a9(-0x8b, -0x6c, 0x2e, -0xd8)],
  17.                         'padding': CryptoJS['pad'][_0xa69db3(-0x11b, -0xce, -0xbe, -0xe5)]
  18.                     })
  19.                       , _0x4f3e21 = _0x358b25[_0x2c39a9(-0xa5, 0x22, -0xbf, -0x88)](CryptoJS[_0x2c39a9(-0x1e3, -0x11f, -0x157, -0x204)][_0x2c39a9(-0x167, -0xcc, -0x146, -0x1f9)]);
  20.                     return _0x4f3e21;
  21.                 } catch (_0x38162c) {
  22.                     return _0x2c39a9(-0x13f, -0x71, -0x17e, -0xc2);
  23.                 }
  24.             else {
  25.                 const _0xffa502 = _0x10f4b1['apply'](_0x5324aa, arguments);
  26.                 return _0x2f1b95 = null,
  27.                 _0xffa502;
  28.             }
  29.         }

  30. function getUrl(secret = 'Isu7fOAvI6!&IKpAbVdhf&^F', key = 's9Wqfwm5nA1uGOqZZ1k6NdRIXtRQHPs3qQLkAGEx5/kD+ggNX1NPf8o1jI9HpV8s4h9pt7JnJRADFmhc+uKtuKxaiT6gC9OlJHDd2nyNwgzkN/+FlGw/F7X2/gicqjf20vWUoeORf6DEXkF/AXxGPeXm6E3yuiJkBUSmZWKNKqtXrSn7E+DHvs9k6rrnlJmOAF52z2/C2axzbhhfXQd9ghfPEjCs8JOh4kvoQ4ThFTk=') {
  31.     const secretData = CryptoJS.enc.Utf8.parse(secret);
  32.     const keyData = CryptoJS.enc.Base64.parse(key);

  33.     const payload = {
  34.         ciphertext: keyData,
  35.     }
  36.     const data = CryptoJS.AES.decrypt(payload, secretData, {
  37.         mode: CryptoJS.mode.ECB,
  38.         padding: CryptoJS.pad.Pkcs7
  39.     });
  40.     return data.toString(CryptoJS.enc.Utf8)
  41. }
复制代码


secret 值来源于 gogogo 里面的调用参数,而 key 的值来源于 window.whatTMDwhatTMDPPPP

回复

使用道具 举报

 楼主| 发表于 昨天 23:59 | 显示全部楼层
接下来就是使用脚本来爬,访问时使用了反爬 cdndefend,原理是在 js 里面计算一个 cookie,请求的时候需要带上 cookie 来访问才行,再次丢给 ai:



  1. function computeCookie(prefix) {
  2.   let i = 0
  3.   while (true) {
  4.     const s = prefix + i
  5.     const digest = crypto.createHash('sha1').update(s).digest()

  6.     if (digest[0] === 0xB0 && digest[1] === 0x0B) {
  7.       return s
  8.     }
  9.     i++
  10.   }
  11. }

  12. async function parseCookie(html) {
  13.   const match = html.match(/([A-F0-9]{30,40})/)
  14.   if (!match) {
  15.     throw new Error('Hash Error')
  16.   }

  17.   return computeCookie(match[1])
  18. }
复制代码


不太完整的 nodejs 脚本:

  1. #!/usr/bin/env node
  2. const crypto = require('crypto')
  3. const cheerio = require('cheerio')
  4. const pLimit = require('p-limit').default

  5. let cookie = ''

  6. async function get(url) {
  7.   const headers = new Headers({
  8.     'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36'
  9.   })

  10.   if (cookie) {
  11.     headers.append('Cookie', `cdndefend_js_cookie=${cookie}`)
  12.   }

  13.   const response = await fetch(url, {
  14.     headers,
  15.     'method': 'GET',
  16.   })
  17.   return await response.text()
  18. }

  19. function computeCookie(prefix) {
  20.   let i = 0
  21.   while (true) {
  22.     const s = prefix + i
  23.     const digest = crypto.createHash('sha1').update(s).digest()

  24.     if (digest[0] === 0xB0 && digest[1] === 0x0B) {
  25.       return s
  26.     }
  27.     i++
  28.   }
  29. }

  30. async function parseCookie(html) {
  31.   const match = html.match(/([A-F0-9]{30,40})/)
  32.   if (!match) {
  33.     throw new Error('Hash Error')
  34.   }

  35.   return computeCookie(match[1])
  36. }

  37. function parseSources(content) {
  38.   const $ = cheerio.load(content)
  39.   const sources = $('#detail-source-swiper .swiper-slide')

  40.   const result = sources.map((i, el) => {
  41.     const sourceName = $(el).find('.source-item-label').text().trim()

  42.     const episodeList = $('.episode-box-main .episode-list').eq(i)

  43.     const episodes = episodeList.find('a.episode-item').map((j, ep) => ({
  44.       name: $(ep).text().trim(),
  45.       url: $(ep).attr('href')
  46.     })).get()

  47.     return {
  48.       name: sourceName,
  49.       episodes
  50.     }
  51.   }).get()

  52.   return [result[0]]
  53. }

  54. const limit = pLimit(2)

  55. async function updateSourcesPlayUrl(sources) {
  56.   // 先平铺所有 episode,附带 source index 和 episode index
  57.   const tasks = []
  58.   sources.forEach((source, si) => {
  59.     source.episodes.forEach((ep, ei) => {
  60.       tasks.push(
  61.         limit(async () => {
  62.           const playUrl = await fetchPlayUrl(ep.url)
  63.           sources[si].episodes[ei].playUrl = playUrl
  64.         })
  65.       )
  66.     })
  67.   })

  68.   await Promise.all(tasks)
  69.   return sources
  70. }

  71. function getUrl(secret = 'Isu7fOAvI6!&IKpAbVdhf&^F', base64Ciphertext = 's9Wqfwm5nA1uGOqZZ1k6NdRIXtRQHPs3qQLkAGEx5/kD+ggNX1NPf8o1jI9HpV8s4h9pt7JnJRADFmhc+uKtuKxaiT6gC9OlJHDd2nyNwgzkN/+FlGw/F7X2/gicqjf20vWUoeORf6DEXkF/AXxGPeXm6E3yuiJkBUSmZWKNKqtXrSn7E+DHvs9k6rrnlJmOAF52z2/C2axzbhhfXQd9ghfPEjCs8JOh4kvoQ4ThFTk=') {
  72.   // 1. 確定加密演算法
  73.   // 原始金鑰 'Isu7fOAvI6!&IKpAbVdhf&^F' 的長度是 24 位元組 (bytes)
  74.   // 24 * 8 = 192 位 (bits),所以我們使用 'aes-192-ecb'
  75.   const algorithm = 'aes-192-ecb';

  76.   // 2. 準備金鑰
  77.   // crypto 模組需要 Buffer 格式的金鑰
  78.   const key = Buffer.from(secret, 'utf8');

  79.   // 3. 創建解密器
  80.   // ECB 模式不需要初始向量 (IV),所以第三個參數為 null
  81.   const decipher = crypto.createDecipheriv(algorithm, key, null);

  82.   // 4. 關閉自動填充
  83.   // CryptoJS 預設使用 Pkcs7 填充,Node.js crypto 也能處理。
  84.   // 預設 decipher.setAutoPadding(true) 是開啟的,所以我們不需要手動設定。

  85.   // 5. 執行解密
  86.   let decrypted = decipher.update(base64Ciphertext, 'base64', 'utf8');
  87.   decrypted += decipher.final('utf8');

  88.   return decrypted;
  89. }


  90. async function fetchPlayUrl(url) {
  91.   const playUrl = `https://www.keke1.app${url}`
  92.   const content = await get(playUrl)
  93.   if (content.includes('url: playSource.src')) {
  94.     const group = /src:\s?"(http.+\.m3u8)"/.exec(content)
  95.     if (group) {
  96.       return group[1]
  97.     }
  98.   }
  99.   if (content.includes('KKYS[')) {
  100.     const decoded = 'Isu7fOAvI6!&IKpAbVdhf&^F'
  101.     const ppp = /whatTMDwhatTMDPPPP\s?=\s?'(.*)'/.exec(content)
  102.     if (decoded && ppp) {
  103.       return getUrl(decoded, ppp[1])
  104.     }
  105.   }
  106.   return ''
  107. }

  108. (async () => {
  109.   const id = process.argv[2]
  110.   if (!id || !/\d+/.test(id)) {
  111.     console.log(`❌ id 参数缺失`)
  112.   }
  113.   const index = await get('https://www.keke1.app/')

  114.   cookie = await parseCookie(index)

  115.   const content = await get(`https://www.keke1.app/detail/${id}.html`)
  116.   const sources = await updateSourcesPlayUrl(parseSources(content))
  117.   console.log(JSON.stringify(sources))
  118. })()
复制代码


测试下来应该是对请求频率做了限制,测试了一个电视剧就被限制了,谨慎谨慎
回复

使用道具 举报

Archiver|小黑屋|CG分享网 CG教程 CG模型 设计素材

GMT+8, 2025-12-30 07:21 , Processed in 0.126306 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表