diff --git a/config/map.txt b/config/map.txt index a6603726..13760290 100644 --- a/config/map.txt +++ b/config/map.txt @@ -38,7 +38,6 @@ AppFei@@https://ysa.yy-fun.cc/feiapp@@森林动漫[AF] AppGet@@{"host":"https://snysw.xyz/mf4kzs327.txt","key":"1234567887654321"}@@魔方[AG¹] AppGet@@{"host":"https://gitee.com/wmmoliill/wimg/raw/master/img/bk/9.txt","key":"88689667dce61725"}@@茉莉[AG¹] AppGet@@{"host":"http://ys.qist.top","key":"2SWSPFxugBLPPOKo"}@@旗星[AG¹] -AppGet@@{"host":"https://api1.bffree.cn","key":"2015692015692015"}@@橘子[AG¹] AppGet@@{"host":"https://dy.58ys.vip","key":"JEWibY1AgWF0V1xx"}@@五八[AG¹] AppGet@@{"host":"https://mac.555618.xyz","key":"#getapp@TMD@2025"}@@玲珑[AG¹] AppGet@@{"host":"https://app.omofun1.top","key":"66dc309cbeeca454"}@@OMOfun[AG¹] @@ -50,16 +49,13 @@ AppSk@@{"host":"https://sk.xiaoyaoys.top/skkkkkkk.txt","key":"ygcnbcczduwydmrs", AppV6@@{"api":"http://yjyi.juyongjiu.com/icciu_api.php/v1.vod","datasignkey":"6QQNUsP3PkD2ajJCPCY8","apisignkey":"lvdoutv-1.0.0"}@@剧永久[AV⁶] AppV6@@http://jxfmax.juxiafan.com/icciu_api.php/v1.vod@@剧下饭[AV⁶] AppToV5@@http://118.89.203.120:8762@@番喜[ATV⁵] -AppToV5@@http://111.173.114.61:8762@@爱看剧Fax[ATV⁵] AppToV5@@http://38.55.237.41:8762@@皮皮虾[ATV⁵] -AppV2²@@https://www.heli888.cc@@河狸![AV²] AppV2²@@http://38.47.213.61:41271@@闪影[AV²] AppV2²@@http://v.lnhaozhenjin.cn@@好震惊[AV²] AppV2²@@http://jxfmax.juxiafan.com@@剧下饭[AV²] AppV1@@http://ziyuncms.feifan12.xyz/api.php@@紫云[AV¹] getapp3.4.4@@{"host":"https://staraugust123456.oss-cn-hangzhou.aliyuncs.com/2.txt","datakey":"staraugust123456","api":2}@@云云[AG³] getapp3.4.4@@{"host":"https://jingyu4k-1312635929.cos.ap-nanjing.myqcloud.com/1.json","datakey":"AAdgrdghjfgswerA","api":2}@@鲸鱼影视[AG³] -getapp3.4.4@@{"host":"https://www.guahd.com/1.txt","key":"f2A7D4B9E8C16531"}@@瓜萌[AG³] getapp3.4.4@@{"host":"https://99.jl8.top/1.txt","key":"xnybssspqtwotuwj"}@@七月[AG³] getapp3.4.4@@{"host":"http://tvb.yy-fun.cc","key":"jcTz6Jda2aKrH8Tk"}@@掌上追剧[AG³] AppHs@@{"host":"https://dy.jmzp.net.cn","app_id":"shiguang","deviceid":"","versionCode":"10000","UMENG_CHANNEL":"guan"}@@拾光视频[Hs] diff --git "a/json/App\346\250\241\346\235\277\351\205\215\347\275\256.json" "b/json/App\346\250\241\346\235\277\351\205\215\347\275\256.json" index 00d03223..c78b8a10 100644 --- "a/json/App\346\250\241\346\235\277\351\205\215\347\275\256.json" +++ "b/json/App\346\250\241\346\235\277\351\205\215\347\275\256.json" @@ -23,6 +23,190 @@ "password": "", "会员时长": "", "lazyheader": {} + }, + "仓鼠": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://ceshi307386.oss-cn-beijing.aliyuncs.com/ceshi421.txt", + "key": "da61247f5b662597", + "iv": "da61247f5b662597", + "verify": "true" + }, + "紫金": { + "muban": "AppGet", + "host": "", + "hosturl": "https://snysw.xyz/mf4kzs327.txt", + "key": "1234567887654321", + "iv": "1234567887654321", + "verify": "true" + }, + "云云": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://staraugust123456.oss-cn-hangzhou.aliyuncs.com/2.txt", + "key": "staraugust123456", + "iv": "staraugust123456", + "verify": "true" + }, + "奇奇": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://yun-1316442804.cos.ap-guangzhou.myqcloud.com/a.txt", + "key": "123456789abcdefg", + "iv": "123456789abcdefg", + "verify": "true" + }, + "鲸鱼": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://jingyu4k-1312635929.cos.ap-nanjing.myqcloud.com/1.json", + "key": "AAdgrdghjfgswerA", + "iv": "AAdgrdghjfgswerA", + "verify": "true" + }, + "咖啡": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://daen-1256234123.cos.ap-shanghai.myqcloud.com/MuQi/mqxh.txt", + "key": "37kj83zs1q16jk6t", + "iv": "37kj83zs1q16jk6t", + "verify": "true" + }, + "小猪": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://tiantangyoulu.oss-cn-beijing.aliyuncs.com/tengxunyun.txt", + "key": "seb5tq9mykp2w9ry", + "iv": "seb5tq9mykp2w9ry", + "verify": "true" + }, + "影视": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://aysappto.oss-cn-chengdu.aliyuncs.com/qj2.txt", + "key": "sada21321sdq231d", + "iv": "sada21321sdq231d", + "verify": "true" + }, + "数字": { + "muban": "AppGet", + "host": "http://app1-0-0.87333.cc", + "hosturl": "", + "key": "VwsHxkCViDXEExWa", + "iv": "VwsHxkCViDXEExWa", + "verify": "true" + }, + "火锅": { + "muban": "AppGet", + "host": "https://ios.hgyx.vip", + "hosturl": "", + "key": "062dec75d039980e", + "iv": "062dec75d039980e", + "verify": "true" + }, + "五八": { + "muban": "AppGet", + "host": "https://dy.58ys.vip", + "hosturl": "", + "key": "JEWibY1AgWF0V1xx", + "iv": "JEWibY1AgWF0V1xx", + "verify": "true" + }, + "旗星": { + "muban": "AppGet", + "host": "http://ys.qist.top", + "hosturl": "", + "key": "2SWSPFxugBLPPOKo", + "iv": "2SWSPFxugBLPPOKo", + "verify": "true" + }, + "灵虎": { + "muban": "AppGet", + "host": "", + "hosturl": "https://bind.315999.xyz/89.txt", + "key": "#getapp@TMD@2025", + "iv": "#getapp@TMD@2025", + "verify": "true" + }, + "剧梦": { + "muban": "AppGet", + "host": "https://www.jumengwu.com", + "hosturl": "", + "key": "1f0a873caf2550a5", + "iv": "1f0a873caf2550a5", + "verify": "true" + }, + "火狐": { + "muban": "AppGet", + "host": "http://huohu.yihn.cc", + "hosturl": "", + "key": "huohushipingetap", + "iv": "huohushipingetap", + "verify": "true" + }, + "金牌": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://dtqj.ggtvb.cc/dtjp.txt", + "key": "eecbio48dsq131ee", + "iv": "eecbio48dsq131ee", + "verify": "true" + }, + "爱盈": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://aysappto.oss-cn-chengdu.aliyuncs.com/qj3.txt", + "key": "sda1231sasddad21", + "iv": "sda1231sasddad21", + "verify": "true" + }, + "顾我": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://guwozj-1319364746.cos.ap-guangzhou.myqcloud.com/guwo.txt", + "key": "ca94b06ca3c7d80e", + "iv": "ca94b06ca3c7d80e", + "verify": "true" + }, + "爆炸": { + "muban": "AppQiji", + "host": "", + "hosturl": "https://daen-1256234123.cos.ap-shanghai.myqcloud.com/MuQi/mqxh.txt", + "key": "37kj83zs1q16jk6t", + "iv": "37kj83zs1q16jk6t", + "verify": "true" + }, + "丫丫动漫": { + "muban": "AppGet", + "host": "http://tv.yy-fun.cc", + "hosturl": "", + "key": "qkxnwkfjwpcnwycl", + "iv": "qkxnwkfjwpcnwycl", + "verify": "true" + }, + "咕咕动漫": { + "muban": "AppGet", + "host": "https://www.gugu3.com", + "hosturl": "", + "key": "nKfZ8KX6JTNWRzTD", + "iv": "nKfZ8KX6JTNWRzTD", + "verify": "true" + }, + "元咲动漫": { + "muban": "AppGet", + "host": "http://cic.aicg.fun", + "hosturl": "", + "key": "2c4h36abd96se10u", + "iv": "2c4h36abd96se10u", + "verify": "true" + }, + "方舟动漫": { + "muban": "AppGet", + "host": "https://www.cyfz.vip", + "hosturl": "", + "key": "e72cdfd629e8895d", + "iv": "e72cdfd629e8895d", + "verify": "true" } }, "Appmuou": { @@ -40,14 +224,6 @@ "key1": "", "key2": "", "version": "" - }, - "光映视界": { - "host": "", - "hosturl": "https://ymdtsy.lingutv.cn/shark/api.txt", - "key": "IKXRx4M6cB45SNTs", - "key1": "rectangleadsadxa", - "key2": "aassddwwxxllsx1x", - "version": "2.2.0" } } } \ No newline at end of file diff --git "a/json/TG\351\242\221\351\201\223\351\205\215\347\275\256.json" "b/json/TG\351\242\221\351\201\223\351\205\215\347\275\256.json" index 273f60a0..6cda37ec 100644 --- "a/json/TG\351\242\221\351\201\223\351\205\215\347\275\256.json" +++ "b/json/TG\351\242\221\351\201\223\351\205\215\347\275\256.json" @@ -23,10 +23,6 @@ "type_id": "yunpanuc", "type_name": "UC资源" }, - { - "type_id": "xiangnikanj", - "type_name": "短剧频道" - }, { "type_id": "PanjClub", "type_name": "盘酱酱Club" diff --git a/public/sub/order_common.example.html b/public/sub/order_common.example.html index 33cf163c..a82a7930 100644 --- a/public/sub/order_common.example.html +++ b/public/sub/order_common.example.html @@ -1,16 +1,18 @@ 设置中心 番茄小说 -大象影视 腾云驾雾 央视大全 IPTV [优] [盘] [漫] +[短] [官] [听] +[书] [搜] DS cat +DR2 hipy 推送 diff --git "a/spider/catvod/\351\243\216\350\275\246\345\212\250\346\274\253[\346\274\253].js" "b/spider/catvod/\351\243\216\350\275\246\345\212\250\346\274\253[\346\274\253].js" deleted file mode 100644 index 0d1fa82a..00000000 --- "a/spider/catvod/\351\243\216\350\275\246\345\212\250\346\274\253[\346\274\253].js" +++ /dev/null @@ -1,105 +0,0 @@ -/* -@header({ - searchable: 1, - filterable: 1, - quickSearch: 1, - title: '风车动漫', - lang: 'cat' -}) -*/ -import {urljoin, parseList, parseDetail, lazy, request, cheerio, CryptoJS} from "./_dsutil.js"; - -const host = 'https://www.dmla5.com'; - -function init(cfg) { - const ext = cfg.ext; -} - -async function home(filter) { - let html = await request(host); - const $ = cheerio.load(html); - const listItems = $('.stui-header__menu li:gt(0):lt(4)'); - let classes = []; - listItems.each((index, element) => { - const item = $(element); - // 提取数据 - const type_name = item.find('a').text().trim(); - const type_id = urljoin(host, item.find('a').attr('href')).match(/.*\/(.*?)\.html/)[1]; - - classes.push({ - type_name, - type_id, - }); - }); - let res = { - 'class': classes - }; - return JSON.stringify(res); -} - -async function homeVod(params) { - let html = await request(host); - const $ = cheerio.load(html); - const listItems = $('ul.stui-vodlist.clearfix li'); - const d = parseList($, host, listItems); - - return JSON.stringify({ - list: d - }); -} - -async function category(tid, pg, filter, extend) { - let url = `${host}/type/${tid}-${pg}.html`; - let html = await request(url); - const $ = cheerio.load(html); - const listItems = $('.stui-vodlist li'); - const d = parseList($, host, listItems); - - return JSON.stringify({ - list: d - }); -} - -async function detail(id) { - let url = urljoin(host, id); - let html = await request(url); - const $ = cheerio.load(html); - - const vod = parseDetail($, host, url); - return JSON.stringify({ - list: [vod] - }) -} - -async function play(flag, id, flags) { - console.log("play"); - return await lazy(urljoin(host, id)); -} - -async function search(wd, quick, pg) { - let url = `${host}/search/${wd}----------${pg}---.html`; - let html = await request(url); - const $ = cheerio.load(html); - const listItems = $('ul.stui-vodlist__media li'); - const d = parseList($, host, listItems); - - return JSON.stringify({ - list: d - }); -} - -function proxy(params) { - return [200, 'text/plain;charset=utf-8', 'ok', null]; -} - -// 导出函数对象 -export default { - init: init, - home: home, - homeVod: homeVod, - category: category, - detail: detail, - play: play, - search: search, - proxy: proxy, -} \ No newline at end of file diff --git "a/spider/js/TG\346\220\234[\346\220\234].js" "b/spider/js/TG\346\220\234[\346\220\234].js" index 5d5ff90c..5a98a5cf 100755 --- "a/spider/js/TG\346\220\234[\346\220\234].js" +++ "b/spider/js/TG\346\220\234[\346\220\234].js" @@ -10,7 +10,7 @@ }) */ -const Pan_API = 'http://127.0.0.1:6080'; // 网盘链接有效性检测过滤api,需自行替换 +const Pan_API = 'https://pancheck.banye.tech:7777'; // 网盘链接有效性检测过滤api,需自行替换 const Pan_Sift = []; const DEFAULT_CHANNELS = 'douerpan,bdwpzhpd,wydwpzy,sgkwpzy,zyywpzy,Baidu_Netdisk,PanjClub,youxigs,yunpanuc,zyfb123,ysxb48,xiangnikanj';//定义频道 const DEFAULT_SOURCES = ['百度网盘', '夸克网盘', 'UC网盘', '移动云盘', '天翼云盘', '115网盘', '阿里云盘', '123云盘'];//定义搜索网盘类型及顺序 diff --git "a/spider/js/TG\347\233\230\346\220\234[\346\220\234].js" "b/spider/js/TG\347\233\230\346\220\234[\346\220\234].js" index 9ab16fb4..4629447e 100644 --- "a/spider/js/TG\347\233\230\346\220\234[\346\220\234].js" +++ "b/spider/js/TG\347\233\230\346\220\234[\346\220\234].js" @@ -10,7 +10,7 @@ }) */ -const Pan_API = 'http://127.0.0.1:6080'; // PanCheck的API地址 自行替换 +const Pan_API = 'https://pancheck.banye.tech:7777'; // PanCheck的API地址 自行替换 const Pan_So = 'https://so.252035.xyz'; // PanSou地址,自行替换 const PAN_TYPES = '百度网盘,夸克网盘,UC网盘,天翼云盘,移动云盘'; // 默认搜索的网盘类型和排序,逗号分隔 const MAX_RESULTS = 15; // 默认搜索结果数量 (每个网盘类型最多15条) diff --git "a/spider/js/TG\351\242\221\351\201\223.js" "b/spider/js/TG\351\242\221\351\201\223.js" index ffbbdd60..85011738 100755 --- "a/spider/js/TG\351\242\221\351\201\223.js" +++ "b/spider/js/TG\351\242\221\351\201\223.js" @@ -93,7 +93,7 @@ const rule = { host: 'https://t.me', url: '/s/fyclass', searchUrl: '?q=**', - Pan_API: 'http://127.0.0.1:6080', // 网盘链接有效性检测过滤api,需自行替换 + Pan_API: 'https://pancheck.banye.tech:7777', // 网盘链接有效性检测过滤api,需自行替换 logo: 'https://api.xinac.net/icon/?url=https://t.me', searchable: 1, quickSearch: 1, diff --git "a/spider/js/\345\212\250\346\274\253\345\246\226[\346\274\253].js" "b/spider/js/\345\212\250\346\274\253\345\246\226[\346\274\253].js" deleted file mode 100644 index 230e9798..00000000 --- "a/spider/js/\345\212\250\346\274\253\345\246\226[\346\274\253].js" +++ /dev/null @@ -1,89 +0,0 @@ -/* -@header({ - searchable: 2, - filterable: 1, - quickSearch: 1, - title: '动漫豆', - author: '', - '类型': '动漫', - lang: 'ds' -}) -*/ - -var rule = { - author: '', - title: '动漫豆', - 类型: '动漫', - host: 'https://www.dmyao.com/', - searchable: 2, - quickSearch: 1, - filterable: 1, - headers: { - 'User-Agent': 'MOBILE_UA' - }, - url: '/s/fyfilter.html', - filter_url: '{{fl.cateId or "fyclass"}}-{{fl.area}}-{{fl.by}}-{{fl.class}}-{{fl.lang}}-{{fl.letter}}---fypage---{{fl.year}}', - detailUrl: '/show/fyid.html', - searchUrl: '/search/**----------fypage---.html', - class_name: '国产动漫&日韩动漫&欧美动漫&港台动漫&动漫电影', - class_url: 'cnanime&jpanime&ouanime&hkanime&animevod', - play_parse: true, - 推荐: '*', - 一级: '.module-items.module-poster-items-base a;a&&title;.lazyload&&data-original;.module-item-note&&Text;a&&href', - 二级: { - "title": "h1&&Text", - "img": ".module-info-pic&&img&&src", - "desc": ".module-info-item:contains(备注)&&Text;.module-info-tag-link:contains(动画)&&Text;.module-info-tag-link:contains(大陆)&&Text;.module-info-item:contains(主演) .module-info-item-content&&Text;.module-info-item:contains(导演) .module-info-item-content&&Text", - "content": ".module-info-introduction-content&&Text", - "tabs": ".module-tab-items-box&&span", - "lists": ".module-play-list-base:eq(#id) a" - }, - - 搜索: '.module-card-item.module-item;a&&title;.lazyload&&data-original;.module-item-note&&Text;a&&href', - - lazy: async function lazyFunc() { - let html = await request(input); - let kcode = JSON.parse(html.split('aaaa=')[1].split('<')[0]); - let kurl = kcode.url; - - if (/\.(m3u8|mp4)/.test(kurl)) { - input = { - jx: 0, - parse: 0, - url: kurl, - header: { - 'User-Agent': MOBILE_UA, - 'Referer': getHome(kurl) - } - }; - } else { - input = { - jx: 0, - parse: 1, - url: input - }; - } - }, - - filter_def: { - cnanime: { - cateId: 'cnanime' - }, - jpanime: { - cateId: 'jpanime' - }, - ouanime: { - cateId: 'ouanime' - }, - hkanime: { - cateId: 'hkanime' - }, - animevod: { - cateId: 'animevod' - },hongkong: { - cateId: 'hongkong' - } - }, - - filter: {"cnanime":[{"key":"class","name":"剧情","value":[{"n":"全部","v":""},{"n":"搞笑","v":"搞笑"},{"n":"运动","v":"运动"},{"n":"励志","v":"励志"},{"n":"热血","v":"热血"},{"n":"战斗","v":"战斗"},{"n":"竞技","v":"竞技"},{"n":"校园","v":"校园"},{"n":"青春","v":"青春"},{"n":"爱情","v":"爱情"},{"n":"冒险","v":"冒险"},{"n":"后宫","v":"后宫"},{"n":"百合","v":"百合"},{"n":"治愈","v":"治愈"},{"n":"萝莉","v":"萝莉"},{"n":"魔法","v":"魔法"},{"n":"悬疑","v":"悬疑"},{"n":"推理","v":"推理"},{"n":"奇幻","v":"奇幻"},{"n":"神魔","v":"神魔"},{"n":"恐怖","v":"恐怖"},{"n":"血腥","v":"血腥"},{"n":"机战","v":"机战"},{"n":"战争","v":"战争"},{"n":"犯罪","v":"犯罪"},{"n":"剧情","v":"剧情"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2025","v":"2025"},{"n":"2024","v":"2024"},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"},{"n":"1999","v":"1999"},{"n":"1998","v":"1998"},{"n":"1997","v":"1997"},{"n":"1996","v":"1996"},{"n":"1995","v":"1995"},{"n":"1994","v":"1994"},{"n":"1993","v":"1993"},{"n":"1992","v":"1992"},{"n":"1991","v":"1991"},{"n":"1990","v":"1990"},{"n":"1989","v":"1989"},{"n":"1988","v":"1988"},{"n":"1987","v":"1987"},{"n":"1986","v":"1986"},{"n":"1985","v":"1985"},{"n":"1984","v":"1984"},{"n":"1980","v":"1980"},{"n":"1970","v":"1970"}]},{"key":"by","name":"排序","value":[{"n":"时间排序","v":"time"},{"n":"人气排序","v":"hits"},{"n":"评分排序","v":"score"}]}],"jpanime":[{"key":"class","name":"剧情","value":[{"n":"全部","v":""},{"n":"搞笑","v":"搞笑"},{"n":"运动","v":"运动"},{"n":"励志","v":"励志"},{"n":"热血","v":"热血"},{"n":"战斗","v":"战斗"},{"n":"竞技","v":"竞技"},{"n":"校园","v":"校园"},{"n":"青春","v":"青春"},{"n":"爱情","v":"爱情"},{"n":"冒险","v":"冒险"},{"n":"后宫","v":"后宫"},{"n":"百合","v":"百合"},{"n":"治愈","v":"治愈"},{"n":"萝莉","v":"萝莉"},{"n":"魔法","v":"魔法"},{"n":"悬疑","v":"悬疑"},{"n":"推理","v":"推理"},{"n":"奇幻","v":"奇幻"},{"n":"神魔","v":"神魔"},{"n":"恐怖","v":"恐怖"},{"n":"血腥","v":"血腥"},{"n":"机战","v":"机战"},{"n":"战争","v":"战争"},{"n":"犯罪","v":"犯罪"},{"n":"剧情","v":"剧情"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2025","v":"2025"},{"n":"2024","v":"2024"},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"},{"n":"1999","v":"1999"},{"n":"1998","v":"1998"},{"n":"1997","v":"1997"},{"n":"1996","v":"1996"},{"n":"1995","v":"1995"},{"n":"1994","v":"1994"},{"n":"1993","v":"1993"},{"n":"1992","v":"1992"},{"n":"1991","v":"1991"},{"n":"1990","v":"1990"},{"n":"1989","v":"1989"},{"n":"1988","v":"1988"},{"n":"1987","v":"1987"},{"n":"1986","v":"1986"},{"n":"1985","v":"1985"},{"n":"1984","v":"1984"},{"n":"1980","v":"1980"},{"n":"1970","v":"1970"}]},{"key":"by","name":"排序","value":[{"n":"时间排序","v":"time"},{"n":"人气排序","v":"hits"},{"n":"评分排序","v":"score"}]}],"ouanime":[{"key":"class","name":"剧情","value":[{"n":"全部","v":""},{"n":"搞笑","v":"搞笑"},{"n":"运动","v":"运动"},{"n":"励志","v":"励志"},{"n":"热血","v":"热血"},{"n":"战斗","v":"战斗"},{"n":"竞技","v":"竞技"},{"n":"校园","v":"校园"},{"n":"青春","v":"青春"},{"n":"爱情","v":"爱情"},{"n":"冒险","v":"冒险"},{"n":"后宫","v":"后宫"},{"n":"百合","v":"百合"},{"n":"治愈","v":"治愈"},{"n":"萝莉","v":"萝莉"},{"n":"魔法","v":"魔法"},{"n":"悬疑","v":"悬疑"},{"n":"推理","v":"推理"},{"n":"奇幻","v":"奇幻"},{"n":"神魔","v":"神魔"},{"n":"恐怖","v":"恐怖"},{"n":"血腥","v":"血腥"},{"n":"机战","v":"机战"},{"n":"战争","v":"战争"},{"n":"犯罪","v":"犯罪"},{"n":"剧情","v":"剧情"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2025","v":"2025"},{"n":"2024","v":"2024"},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"},{"n":"1999","v":"1999"},{"n":"1998","v":"1998"},{"n":"1997","v":"1997"},{"n":"1996","v":"1996"},{"n":"1995","v":"1995"},{"n":"1994","v":"1994"},{"n":"1993","v":"1993"},{"n":"1992","v":"1992"},{"n":"1991","v":"1991"},{"n":"1990","v":"1990"},{"n":"1989","v":"1989"},{"n":"1988","v":"1988"},{"n":"1987","v":"1987"},{"n":"1986","v":"1986"},{"n":"1985","v":"1985"},{"n":"1984","v":"1984"},{"n":"1980","v":"1980"},{"n":"1970","v":"1970"}]},{"key":"by","name":"排序","value":[{"n":"时间排序","v":"time"},{"n":"人气排序","v":"hits"},{"n":"评分排序","v":"score"}]}],"hkanime":[{"key":"class","name":"剧情","value":[{"n":"全部","v":""},{"n":"搞笑","v":"搞笑"},{"n":"运动","v":"运动"},{"n":"励志","v":"励志"},{"n":"热血","v":"热血"},{"n":"战斗","v":"战斗"},{"n":"竞技","v":"竞技"},{"n":"校园","v":"校园"},{"n":"青春","v":"青春"},{"n":"爱情","v":"爱情"},{"n":"冒险","v":"冒险"},{"n":"后宫","v":"后宫"},{"n":"百合","v":"百合"},{"n":"治愈","v":"治愈"},{"n":"萝莉","v":"萝莉"},{"n":"魔法","v":"魔法"},{"n":"悬疑","v":"悬疑"},{"n":"推理","v":"推理"},{"n":"奇幻","v":"奇幻"},{"n":"神魔","v":"神魔"},{"n":"恐怖","v":"恐怖"},{"n":"血腥","v":"血腥"},{"n":"机战","v":"机战"},{"n":"战争","v":"战争"},{"n":"犯罪","v":"犯罪"},{"n":"剧情","v":"剧情"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2025","v":"2025"},{"n":"2024","v":"2024"},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"},{"n":"1999","v":"1999"},{"n":"1998","v":"1998"},{"n":"1997","v":"1997"},{"n":"1996","v":"1996"},{"n":"1995","v":"1995"},{"n":"1994","v":"1994"},{"n":"1993","v":"1993"},{"n":"1992","v":"1992"},{"n":"1991","v":"1991"},{"n":"1990","v":"1990"},{"n":"1989","v":"1989"},{"n":"1988","v":"1988"},{"n":"1987","v":"1987"},{"n":"1986","v":"1986"},{"n":"1985","v":"1985"},{"n":"1984","v":"1984"},{"n":"1980","v":"1980"},{"n":"1970","v":"1970"}]},{"key":"by","name":"排序","value":[{"n":"时间排序","v":"time"},{"n":"人气排序","v":"hits"},{"n":"评分排序","v":"score"}]}],"animevod":[{"key":"class","name":"剧情","value":[{"n":"全部","v":""},{"n":"搞笑","v":"搞笑"},{"n":"运动","v":"运动"},{"n":"励志","v":"励志"},{"n":"热血","v":"热血"},{"n":"战斗","v":"战斗"},{"n":"竞技","v":"竞技"},{"n":"校园","v":"校园"},{"n":"青春","v":"青春"},{"n":"爱情","v":"爱情"},{"n":"冒险","v":"冒险"},{"n":"后宫","v":"后宫"},{"n":"百合","v":"百合"},{"n":"治愈","v":"治愈"},{"n":"萝莉","v":"萝莉"},{"n":"魔法","v":"魔法"},{"n":"悬疑","v":"悬疑"},{"n":"推理","v":"推理"},{"n":"奇幻","v":"奇幻"},{"n":"神魔","v":"神魔"},{"n":"恐怖","v":"恐怖"},{"n":"血腥","v":"血腥"},{"n":"机战","v":"机战"},{"n":"战争","v":"战争"},{"n":"犯罪","v":"犯罪"},{"n":"剧情","v":"剧情"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2025","v":"2025"},{"n":"2024","v":"2024"},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"},{"n":"1999","v":"1999"},{"n":"1998","v":"1998"},{"n":"1997","v":"1997"},{"n":"1996","v":"1996"},{"n":"1995","v":"1995"},{"n":"1994","v":"1994"},{"n":"1993","v":"1993"},{"n":"1992","v":"1992"},{"n":"1991","v":"1991"},{"n":"1990","v":"1990"},{"n":"1989","v":"1989"},{"n":"1988","v":"1988"},{"n":"1987","v":"1987"},{"n":"1986","v":"1986"},{"n":"1985","v":"1985"},{"n":"1984","v":"1984"},{"n":"1980","v":"1980"},{"n":"1970","v":"1970"}]},{"key":"by","name":"排序","value":[{"n":"时间排序","v":"time"},{"n":"人气排序","v":"hits"},{"n":"评分排序","v":"score"}]}]} -} \ No newline at end of file diff --git "a/spider/js/\345\216\273\350\257\273\344\271\246[\344\271\246].js" "b/spider/js/\345\216\273\350\257\273\344\271\246[\344\271\246].js" new file mode 100644 index 00000000..86b8b485 --- /dev/null +++ "b/spider/js/\345\216\273\350\257\273\344\271\246[\344\271\246].js" @@ -0,0 +1,155 @@ +/* +@header({ + searchable: 1, + filterable: 0, + quickSearch: 1, + title: '去读书[书]', + author: 'EylinSir', + '类型': '小说', + logo: 'http://www.qudushu.com/favicon.ico', + lang: 'ds' +}) +*/ + +var rule = { + 类型: '小说', + author: 'EylinSir', + title: '去读书[书]', + host: 'http://www.qudushu.com', + url: '/book/fyclass/0/fypage.html', + logo: 'http://www.qudushu.com/favicon.ico', + class_name: '玄幻魔法&武侠修真&都市言情&历史军事&穿越架空&游戏竞技', + class_url: 'sort1&sort2&sort3&sort4&sort5&sort6', + searchUrl: '/modules/article/search.php?q=**', + searchable: 1, + quickSearch: 1, + filterable: 0, + timeout: 10000, + play_parse: true, + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36' + }, + request: async function (url, obj) { + obj = obj || {}; + try { + const response = await _fetch(url, { + method: obj.method || 'GET', + headers: obj.headers || this.headers + }); + return response.text(); + } catch (err) { + return ''; + } + }, + + 一级: async function () { + let {input, pdfa, pdfh, pd} = this; + let url = input.startsWith('http') ? input : this.host + '/book/' + input + '/0/1.html'; + let html = await this.request(url); + let d = []; + let items = pdfa(html, '.blockcontent .c_row') || pdfa(html, '.c_row') || []; + for (let item of items) { + let title = pdfh(item, '.c_subject a:eq(1)&&Text'); + let itemUrl = pd(item, '.c_subject a:eq(1)&&href'); + if (!title || !itemUrl) continue; + let remarks = pdfh(item, '.c_tag span:eq(1)&&Text') || ''; + let pic = pd(item, 'img&&src') || ''; + let content = pdfh(item, '.c_description&&Text') || ''; + d.push({ + title: title, + url: itemUrl, + desc: remarks, + pic_url: pic, + content: content, + }); + } + return setResult(d); + }, + + 二级: async function () { + let {input, pdfa, pdfh, pd} = this; + let html = await this.request(input); + let VOD = {}; + VOD.vod_name = pdfh(html, '[property="og:novel:book_name"]&&content') || ''; + VOD.type_name = ''; + VOD.vod_pic = pd(html, '.divbox.cf img&&src') || ''; + VOD.vod_content = pdfh(html, '.tabcontent .tabvalue:eq(0)&&Text') || ''; + VOD.vod_remarks = pdfh(html, 'h3 a&&Text') || ''; + VOD.vod_year = ''; + VOD.vod_area = ''; + VOD.vod_actor = pdfh(html, '[property="og:novel:author"]&&content') || ''; + VOD.vod_director = VOD.vod_actor; + VOD.vod_play_from = '去读书网'; + let toc_url = pd(html, 'a:contains(点击阅读)&&href') || ''; + if (toc_url && !toc_url.startsWith('http')) { + toc_url = this.host + toc_url; + } + let toc_html = toc_url ? await this.request(toc_url) : ''; + let chapters = []; + let chapterItems = pdfa(toc_html, '.index li') || []; + for (let chapter of chapterItems) { + let title = pdfh(chapter, 'a&&Text'); + let chapter_url = pd(chapter, 'a&&href'); + if (!title || !chapter_url) continue; + if (!chapter_url.startsWith('http')) { + chapter_url = this.host + chapter_url; + } + chapters.push(title + '$' + chapter_url); + } + VOD.vod_play_url = chapters.join('#'); + return VOD; + }, + + 搜索: async function () { + let {KEY, pdfa, pdfh, pd} = this; + let url = this.host + this.searchUrl.replace('**', encodeURIComponent(KEY)); + let html = await this.request(url); + if (!html) { + url = this.host + '/modules/article/search.php?q=' + encodeURIComponent(KEY); + html = await this.request(url); + } + let d = []; + let items = pdfa(html, '#jieqi_page_contents .c_row') || []; + for (let item of items) { + let title = pdfh(item, '.c_subject a&&Text'); + let itemUrl = pd(item, '.c_subject a&&href'); + if (!title || !itemUrl) continue; + itemUrl = itemUrl.startsWith('http') ? itemUrl : this.host + itemUrl; + let pic = pd(item, 'img&&src') || ''; + pic = pic.startsWith('http') ? pic : this.host + pic; + d.push({ + title: title, + url: itemUrl, + desc: pdfh(item, '.c_tag span:eq(1)&&Text') || '', + pic_url: pic, + content: '', + }); + } + return setResult(d); + }, + + lazy: async function () { + let {input, pdfh} = this; + let html = await this.request(input); + let title = pdfh(html, 'h1&&Text') || ''; + let content = pdfh(html, '#acontent&&Html') || ''; + if (content) { + content = content.replace(/]*?>.*?<\/script>/gs, '') + .replace(/<\/p>/g, '\n\n') + .replace(/]*?>/g, '\n') + .replace(/<[^>]*?>/g, '') + .replace(/去读书推荐各位书友阅读:.*|去读书 www\.qudushu\.la|如果您中途有事离开,请按.*以便以后接着观看!/g, '') + .replace(/[()]/g, '') + .replace(/ /g, ' ') + .replace(/[ \t]+/g, ' ') + .replace(/\n[ \t]+|[ \t]+\n/g, '\n') + .replace(/\n+/g, '\n\n') + .trim(); + } + return { + parse: 0, + url: 'novel://' + JSON.stringify({title, content}), + js: '' + }; + } +}; diff --git "a/spider/js/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" "b/spider/js/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" index 766d76fe..1edc387c 100644 --- "a/spider/js/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" +++ "b/spider/js/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" @@ -33,8 +33,16 @@ var rule = { let data = JSON.parse(await request(url, { headers: rule.headers })); - let mp3 = data.data.mp3; - return {parse: 0, url: mp3, header: rule.headers}; + let songData = data.data; + return { + parse: 0, + url: songData.mp3, // 播放链接 + header: rule.headers, // 请求头 + lrc: songData.lrc, // 歌词内容 + img: songData.pic, // 封面图片 + title: songData.mname, // 歌名 + singer: songData.sname // 歌手 + }; }, 推荐: "*", 一级: '.mobile-list&&.mobile-list-item;.songname&&Text;.lazyload&&data-src;.authorname&&Text;a&&href', diff --git "a/spider/js/\351\230\205\350\257\273\345\212\251\346\211\213[\344\271\246].js" "b/spider/js/\351\230\205\350\257\273\345\212\251\346\211\213[\344\271\246].js" new file mode 100644 index 00000000..40f61d11 --- /dev/null +++ "b/spider/js/\351\230\205\350\257\273\345\212\251\346\211\213[\344\271\246].js" @@ -0,0 +1,160 @@ +var rule = { + 类型: '小说', + author: 'EylinSir', + title: '阅读助手[书]', + desc: '阅读助手小说源', + host: 'https://api-bc.wtzw.com', + homeUrl: 'https://api-bc.wtzw.com', + url: '/api/v4/category/get-list?gender=fyclass&category_id=fyfilter&need_filters=1&page=fypage&need_category=1', + class_name: '男生&女生&出版', + class_url: '1&2&3', + searchUrl: '/api/v5/search/words?gender=3&imei_ip=2937357107&page=fypage&wd=**', + searchable: 2, + quickSearch: 0, + filterable: 1, + filter: { + "1": [{key: "type", name: "类型", value: [{"n":"玄幻奇幻","v":"202"},{"n":"都市人生","v":"203"},{"n":"武侠仙侠","v":"205"},{"n":"历史军事","v":"56"},{"n":"科幻末世","v":"64"},{"n":"游戏竞技","v":"75"},{"n":"体育赛事","v":"206"},{"n":"奇闻异事","v":"204"}]}], + "2": [{key: "type", name: "类型", value: [{"n":"现代言情","v":"1"},{"n":"古代言情","v":"2"},{"n":"幻想言情","v":"4"},{"n":"宫闱宅斗","v":"209"}]}], + "3": [{key: "type", name: "类型", value: [{"n":"悬疑推理","v":"262"},{"n":"文学艺术","v":"240"},{"n":"历史传记","v":"264"}]}] + }, + filter_url: "{{fl.type}}", + filter_def: {}, + headers: {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'}, + sign_headers: { + "app-version": "51110", "platform": "android", "reg": "0", "AUTHORIZATION": "", + "application-id": "com.****.reader", "net-env": "1", "channel": "unknown", "qm-params": "" + }, + timeout: 10000, + play_parse: true, + + request: async function (url, obj) { + obj = obj || {}; + const response = await _fetch(url, { + method: obj.method || 'GET', + headers: obj.headers || this.headers + }); + return response.text(); + }, + + 预处理: async function () { + this.sign_headers.sign = getSignStr(this.sign_headers); + }, + + 一级: async function (tid, pg, filter, extend) { + let d = []; + const cateMap = {'1':'202', '2':'1', '3':'262'}; + let gender = tid !== '-1' ? tid : '2'; + let category_id = cateMap[gender]; + const validSubTypes = ['202','203','205','56','64','75','206','204','1','2','4','209','262','240','264']; + if (extend?.type && validSubTypes.includes(extend.type)) { + category_id = extend.type; + } else if (filter && validSubTypes.includes(filter)) { + category_id = filter; + } + let params = { + gender: gender, + category_id: category_id, + need_filters: '1', + page: pg || '1', + need_category: '1', + imei_ip: '2937357107' + }; + params.sign = getSignStr(params); + let html = await this.request(buildUrl(`${this.host}/api/v4/category/get-list`, params), {headers: this.sign_headers}); + let json = JSON.parse(html); + if (json?.data?.books) { + d = json.data.books.map(it => ({ + title: it.title, + url: `${this.host}/api/v4/book/detail?id=${it.id}`, + desc: it.author, + pic_url: it.image_link, + content: it.intro + })); + } + return setResult(d); + }, + + 二级: async function () { + let VOD = {}; + let bookId = this.input.match(/id=(\d+)/)[1]; + let detailParams = {id: bookId, imei_ip: '2937357107', teeny_mode: '0'}; + detailParams.sign = getSignStr(detailParams); + let detailHtml = await this.request(buildUrl(`${this.host}/api/v4/book/detail`, detailParams), {headers: this.sign_headers}); + let detailJson = JSON.parse(detailHtml); + if (detailJson?.data?.book) { + let book = detailJson.data.book; + VOD = { + vod_name: book.title, + type_name: book.book_tag_list?.map(tag => tag.title).join(',') || '', + vod_pic: book.image_link, + vod_content: book.intro, + vod_remarks: book.latest_chapter_title, + vod_year: '', vod_area: '', + vod_actor: book.author, vod_director: book.author, + vod_play_from: '阅读助手' + }; + let tocParams = {id: book.id}; + tocParams.sign = getSignStr(tocParams); + let tocHtml = await this.request(buildUrl('https://api-ks.wtzw.com/api/v1/chapter/chapter-list', tocParams), {headers: this.sign_headers}); + let tocJson = JSON.parse(tocHtml); + if (tocJson?.data?.chapter_lists) { + VOD.vod_play_url = tocJson.data.chapter_lists.map(chapter => + `${chapter.title}$${book.id}@@${chapter.id}@@${chapter.title}` + ).join('#'); + } + } + return VOD; + }, + + 搜索: async function () { + let d = []; + let params = { + gender: '3', imei_ip: '2937357107', + page: this.MY_PAGE, wd: this.KEY + }; + params.sign = getSignStr(params); + let html = await this.request(buildUrl(`${this.host}/api/v5/search/words`, params), {headers: this.sign_headers}); + let json = JSON.parse(html); + if (json?.data?.books) { + d = json.data.books.map(it => ({ + title: it.original_title, + desc: it.author, + pic_url: it.image_link, + url: `${this.host}/api/v4/book/detail?id=${it.id}`, + content: it.intro + })); + } + return setResult(d); + }, + + lazy: async function () { + let [bookId, chapterId, title] = this.input.split('@@'); + let content = '内容加载失败'; + let params = {id: bookId, chapterId}; + params.sign = getSignStr(params); + let html = await this.request(buildUrl('https://api-ks.wtzw.com/api/v1/chapter/content', params), {headers: this.sign_headers}); + let json = JSON.parse(html); + if (json?.data?.content) content = decodeContent(json.data.content); + return { + parse: 0, + url: `novel://${JSON.stringify({title, content})}`, + js: '' + }; + } +}; + +function getSignStr(params) { + const sign_key = "d3dGiJc651gSQ8w1"; + return md5(Object.keys(params).sort().reduce((pre, n) => pre + n + "=" + params[n], "") + sign_key); +} + +function decodeContent(content) { + let key = CryptoJS.enc.Utf8.parse("242ccb8230d709e1"); + let ivEncData = CryptoJS.enc.Base64.parse(content); + let iv = CryptoJS.lib.WordArray.create(ivEncData.words.slice(0, 4)); + let encrypted = CryptoJS.lib.WordArray.create(ivEncData.words.slice(4)); + let decrypted = CryptoJS.AES.decrypt({ciphertext: encrypted}, key, { + iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 + }); + return decrypted.toString(CryptoJS.enc.Utf8); +} \ No newline at end of file diff --git "a/spider/js_dr2/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" "b/spider/js_dr2/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" index 9d1baf95..80c3539f 100644 --- "a/spider/js_dr2/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" +++ "b/spider/js_dr2/\347\247\215\345\255\220\351\237\263\344\271\220[\345\220\254].js" @@ -21,20 +21,35 @@ var rule = { }, class_parse: '.aside-menu-list.channel&&[href*=list];a&&Text;a&&href;.(list.*).htm', play_parse: true, + + // --- 重构的核心部分 --- lazy: $js.toString(() => { + // 1. 将详情页 URL 替换为 API 接口 URL input = input.replace(/play\/(\w+)\.htm/, 'ajax/?act=songinfo&id=$1&lang='); - log(input); - let mp3 = JSON.parse(request(input)).data.mp3; - input = {parse: 0, url: mp3, header: rule.headers}; + + // 2. 发起请求并解析 JSON + let html = request(input); + let json = JSON.parse(html); + let data = json.data; + + // 3. 构造播放对象,包含歌词和元数据 + input = { + parse: 0, + url: data.mp3, // 播放链接 + header: rule.headers, // 请求头 + lrc: data.lrc, // 歌词内容 + img: data.pic, // 封面图片 + title: data.mname, // 歌名 + singer: data.sname // 歌手 + }; }), + // --------------------- + limit: 6, - // 图片来源:'@Referer=https://www.zz123.com/', 推荐: "*", 一级: '.mobile-list&&.mobile-list-item;.songname&&Text;.lazyload&&data-src;.authorname&&Text;a&&href', 二级: '*', - // searchUrl:'/search/?key=**&page=fypage', - // 搜索:'*', searchUrl: '/ajax/?act=search&key=**&lang=', - detailUrl: '/play/fyid.html', + detailUrl: '/play/fyid.html', // 修正:原来是 play/fyid.html,这里保持一致,lazy中正则会匹配 搜索: 'json:data;mname;pic;sname;id', } \ No newline at end of file diff --git "a/spider/py/\345\244\251\347\251\272\345\275\261\350\247\206.py" "b/spider/py/\345\244\251\347\251\272\345\275\261\350\247\206.py" deleted file mode 100644 index b8ac80bf..00000000 --- "a/spider/py/\345\244\251\347\251\272\345\275\261\350\247\206.py" +++ /dev/null @@ -1,428 +0,0 @@ -""" -@header({ - searchable: 1, - filterable: 1, - quickSearch: 1, - title: '天空影视', - lang: 'hipy' -}) -""" - -from Crypto.PublicKey import RSA -from Crypto.Util.Padding import pad -from Crypto.Cipher import AES, PKCS1_v1_5 -import sys,time,json,base64,urllib3,hashlib -urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) -sys.path.append('..') -try: - # from base.spider import Spider as BaseSpider - from base.spider import BaseSpider -except ImportError: - from t4.base.spider import BaseSpider - -class Spider(BaseSpider): - host, android_id, init_sign_salt, app_cert_sha1, private_key, token, timeout, headers = ('','','','','','','', - { - 'User-Agent': "okhttp-okgo/jeasonlzy", - 'Connection': "Keep-Alive", - 'Accept-Encoding': "gzip", - 'Accept-Language': "zh-CN,zh;q=0.8", - 'sign': "", - 'devicename': "Xiaomi 15", - 'deviceos': "15", - 'bundleid': "", - 'versionname': "2.1.0", - 'versioncode': "2001000", - 'vendor': "Xiaomi", - 'chid': "26002", - 'subchid': "26002", - 'os': "1", - 'screenpx': "2670*1200", - 'nettype': "wifi", - 'audit': "1", - 'force': "1" - }) - - def init(self, extend=''): - try: - config = json.loads(extend) - except (json.JSONDecodeError, TypeError): - config = {} - self.timeout = config.get('timeout', 15) - self.host = config.get('host', 'http://api-live.vfilm.life') - self.android_id = config.get('android_id', '6617a62678360a86') - self.init_sign_salt = config.get('init_sign_salt', 'lsdfnrtpmslscndy') - self.app_cert_sha1 = config.get('app_cert_sha1', '70:27:C9:DC:98:96:75:CD:35:DB:0C:CE:AC:CA:84:0A:B7:1E:B5:7F') - self.private_key = config.get('private_key', 'MIICWwIBAAKBgQDYJzTUOgYdR/eIhsjpNMYWQGYl3pBycwKDoL6KThpPwrZQ9+xv\nLSaPj92HQknVaWR/RD6tHVRysChoeqAFyyQUe4UXAYnJDNlurpELb5HUIBFgmO97\niIOJCK6zbmnHT6WOHYaODTqrmX6NBgLjoFiDYBPYxG1T/K1uZ47xQDHFQQIDAQAB\nAoGAEpT8Q6phUC8ZppD/wJya0tribSr++/fLJYmyF62zMVwp1DgcCUq2X+0cPD6E\nnmYbD53MTZGR6vId5y1ziEv4Y+nu5EUyDk1xeGIxojpLhxuRoCbBt+LMJ1YUxv6p\n6F4SNwQ10U78m829Ud50mJBvkt2Vg8607SUrWheydvWHyAECQQDvayhgX5XEFaha\nUtPp5pPIkKBqHnLGm4et8be/jIIFhY9CIJbKLsqc0OFwNvz46GtRQwrtHP7LxTEF\nYT0C6CahAkEA5x+OqN/iykZIHc6Z2qZfAiLjPnQJu9DTXC/kt3TlsCc3XPNkXlAu\nq786LluH6dzQfDbLpmODtzNWavfgCtE6oQJAdTsJKDdlg//+0UthTFSE5F48zfle\nxfT9+KQ1Duvj9oQxY3XFn/ZNa3+0A1hJgi977Oxg+z2JXYmOuU2lrDi0QQJAMWwA\nF4B4gIRy21zYbXbyDgTjzvEFO9I1wBrFr60hiH96STgKmFhRAozLpioQcCO1uToG\nZjgVbFFgA1Op5uZCwQJAL1ziHIphaoCpHnnESidt3Nlrzqj/5uEpdHu7ZvPuZYya\nU8e1AhjeP+zKvfJUiXwDGuDZLx5Xe0BK8Bu72sdKcQ==') - self.headers['bundleid'] = config.get('bundleid', 'com.ytwl.fhtq') - self.token = config.get('token', '') - imsi_id = config.get('imsi_id', '1') - self.headers['sign'] = self.sign_encrypt(f'jing##&&&wei##&&&fuwu##{imsi_id}&&&idian##&&&she##{self.android_id}&&&mdian##{self.android_id}&&&olian##&&&an##{self.android_id}') - - def homeContent(self, filter): - if not self.host: return None - timestamp = self.timestamp() - payload = { - 'applock': "0", - 'ncode': self.init_sign(timestamp), - 'force': "1", - 'retime': timestamp - } - response = self.post(f'{self.host}/news/tv/columns', data=payload, headers=self.headers, timeout=self.timeout, verify=False).json() - classes = [] - for i in response['data']['list']: - if i['is_show_recommend'] == 1: - home_class_id = i.get('column_id') - continue - classes.append({'type_id': i['column_id'], 'type_name': i['name']}) - timestamp = self.timestamp() - payload = { - 'column_id': home_class_id or '164', - 'ncode': self.init_sign(timestamp), - 'page': "1", - 'retime': timestamp - } - response = self.post(f'{self.host}/news/tv/sectionsPageByColumn', data=payload, headers=self.headers, timeout=self.timeout, verify=False).json() - section_list = response['data']['section_list'] - videos = [] - for i in section_list: - for j in i.get('tv_list', []): - videos.append({ - 'vod_id': j.get('news_id'), - 'vod_name': j.get('title', j.get('sub_title')), - 'vod_pic': j.get('ver_pic') - }) - return {'class': classes, 'list': videos} - - def categoryContent(self, tid, pg, filter, extend): - timestamp = self.timestamp() - payload = { - 'column_id': tid, - 'ncode': self.init_sign(timestamp), - 'page': pg, - 'retime': timestamp - } - response = self.post(f'{self.host}/news/tv/tvListByColumn', data=payload, headers=self.headers, timeout=self.timeout, verify=False).json() - videos = [] - for i in response['data']['list']: - up_count = i.get('up_count', '') - if up_count: - up_count = f'{up_count}集' - videos.append({ - 'vod_id': i.get('news_id'), - 'vod_name': i.get('title'), - 'vod_pic': i.get('ver_pic'), - 'vod_remarks': up_count, - 'vod_area': i.get('area'), - 'vod_class': i.get('cat'), - 'vod_score': i.get('score'), - 'vod_year': i.get('pubdate') - }) - return {'list': videos, 'page': pg} - - def searchContent(self, key, quick, pg='1'): - timestamp = self.timestamp() - payload = { - 'ncode': self.init_sign(timestamp), - 'signKey': self.signKey(timestamp), - 'page': pg, - 'is_check': "0", - 'keyword': key, - 'retime': timestamp - } - response = self.post(f'{self.host}/search/wordinfo', data=payload, headers=self.headers, timeout=self.timeout, verify=False).json() - videos = [] - for i in response['data']['search_list']: - for j in i.get('list',[]): - vod_remarks = j.get('up_count') - if vod_remarks: - vod_remarks = f'{vod_remarks}集' - else: - vod_remarks = j.get('news_type_name') - videos.append({ - 'vod_id': j.get('news_id'), - 'vod_name': j.get('origin_title',j.get('title')), - 'vod_pic': j.get('ver_pic'), - 'vod_content': j.get('desc'), - 'vod_remarks': vod_remarks, - 'vod_area': j.get('area'), - }) - return {'list': videos, 'page': pg} - - def detailContent(self, ids): - timestamp = self.timestamp() - payload = { - 'ncode': self.init_sign(timestamp), - 'signKey': self.signKey(timestamp), - 'news_id': ids[0], - 'retime': timestamp - } - response = self.post(f'{self.host}/news/tv/detail', data=payload, headers=self.headers, timeout=self.timeout, verify=False).json() - data = response['data'] - timestamp2 = self.timestamp() - payload = { - 'next': "0", - 'pl_id': "", - 'playlink_num': "1", - 'ncode': self.init_sign(timestamp2), - 'format': "high", - 'mobile': "", - 'check': "0", - 'mpl_id': "", - 'news_id': ids[0], - 'retime': timestamp2, - 'resite': "", - 'signKey': self.signKey(timestamp2), - 'bid': "300", - 'retry': "0" - } - response = self.post(f'{self.host}/news/tv/multiDetail', data=payload, headers=self.headers, timeout=self.timeout, verify=False).json() - data_ = response['data']['data'] - data2_ = self.decrypt(data_) - data2 = json.loads(data2_) - max_up_count = data2.get('max_up_count',data2.get('up_count')) - news_id = data2['news_id'] - site_list_test = data2.get('test') - if site_list_test: - site_list = site_list_test.get('site_list',[]) - vod_play_froms = [] - vod_play_froms.extend(site_list) - vod_play_froms = [str(item) for item in vod_play_froms] - vod_play_urls = [] - for i in vod_play_froms: - urls = [] - for j in range(1,int(max_up_count) + 1): - urls.append(f"第{j}集${j}@{news_id}@{i}") - vod_play_urls.append('#'.join(urls)) - videos = [] - up_count = data.get('up_count',data.get('max_up_count')) - if up_count: - up_count = f'{up_count}集' - videos.append({ - 'vod_id': data.get('news_id'), - 'vod_name': data.get('title'), - 'vod_content': data.get('desc'), - 'vod_director': data.get('dir'), - 'vod_actor': data.get('act'), - 'vod_class': data.get('cat'), - 'vod_remarks': up_count, - 'vod_area': data.get('area'), - 'vod_play_from': '$$$'.join(vod_play_froms), - 'vod_play_url': '$$$'.join(vod_play_urls) - }) - return {'list': videos} - - def playerContent(self, flag, id, vipflags): - jx, url, play_header = 0, '', {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 15; 24129PN74C Build/AP3A.240617.008)'} - episodes, news_id, resite = id.split('@', 2) - timestamp = self.timestamp() - payload = { - 'next': "0", - 'pl_id': "", - 'playlink_num': episodes, - 'ncode': self.init_sign(timestamp), - 'format': 'high', - 'mobile': "", - 'check': "0", - 'mpl_id': "", - 'news_id': news_id, - 'retime': timestamp, - 'resite': resite, - 'signKey': self.signKey(timestamp), - 'bid': '300', - 'retry': "0" - } - response = self.post(f'{self.host}/news/tv/multiDetail', data=payload, headers=self.headers,timeout=self.timeout, verify=False).json() - data_ = response['data']['data'] - data_ = self.decrypt(data_) - data = json.loads(data_) - url_list = data.get('url_list', []) - if url_list: - for i in url_list: - play_url = i.get('surl', '') - if play_url.startswith('http'): - url = play_url - break - if url: - return {'jx': 0, 'parse': 0, 'url': url, 'header': play_header} - cp_data = data['cp_data'] - wanneng = cp_data.get('wanneng', '') - parse_url = '' - if wanneng and isinstance(wanneng, dict): - parse_url = wanneng.get('postUrl', '') - type = cp_data.get('TYPE') - if type == 'DIRECT': - for i in cp_data['V']: - for j in i.values(): - if j.startswith(('http://', 'https://')): - play_url = j - break - if 'play_url' in locals() and play_url: - return {'jx': jx, 'parse': 0, 'url': play_url, 'header': play_header} - try: - if parse_url: - parse_data = self.fetch(parse_url, headers={'User-Agent': "okhttp/3.10.0", 'Accept-Encoding': "gzip"}, timeout=self.timeout, verify=False).text - except Exception: - return {'jx': 0, 'parse': 0, 'url': ''} - if not parse_data: - return {'jx': 0, 'parse': 0, 'url': ''} - timestamp2 = self.timestamp() - vid_format = data.get('format', 'high') - payload2 = { - 'pl_id': data.get('pl_id', ''), - 'is_down': data.get('is_down', '0'), - 'data': parse_data, - 'playlink_num': episodes, - 'ncode': self.init_sign(timestamp), - 'format': vid_format, - 'cp_id': data.get('cp_id', ''), - 'mpl_id': data.get('mpl_id', ''), - 'url': data['web_url'], - 'retime': timestamp2, - 'wn_info': json.dumps(data['cp_data'].get('wanneng', '')), - 'site': data['site'], - 'news_type': "null", - 'web_url': data['web_url'], - 'mc': "null", - 'bid': self.bid(vid_format) - } - response = self.post(f'{self.host}/parse/index/parse', data=payload2, headers=self.headers, timeout=self.timeout, verify=False).json() - data2_ = response['data']['data'] - data2_ = self.decrypt(data2_) - data2 = json.loads(data2_) - play_url = data2['video'][0]['url'] - if play_url.startswith('http'): - url = play_url - return {'jx': jx, 'parse': 0, 'url': url, 'header': play_header} - - def timestamp(self): - timestamp = time.time() - return str(int(round(timestamp * 1000))) - - def md5(self,str): - md5_hash = hashlib.md5() - md5_hash.update(str.encode('utf-8')) - return md5_hash.hexdigest() - - def init_sign(self, timestamp): - first_md5 = self.md5(f"{self.init_sign_salt}{self.token}{self.android_id}{timestamp}") - combined = first_md5[:10] + first_md5[22:] - return self.md5(combined) - - def get_strings(self, str_param, str2_param): - strlist = [ - "afv", "Cs", "D", "bd", "cs", "h", "i0", "j0", "K", "L", "M8", "N", "O", "P", "Q", "R", - "k", "l", "m", "n", "o", "p", "q", "r", "s", "t7", "Z", "A", "B", "E", "F", "G", "H", "I", - "J", "S16", "T", "d", "e", "f", "g", "U", "V", "W6", "u", "v", "w", "x", "y", "Xd", "Y", - "Za0", "gw", "Us", "Vd", "Wv", "X", "Y", "Zx4", "afv", "Cs", "D", "bd", "cs", "h", "i", - "j", "K0", "L", "M", "N", "O0", "P", "Q", "R", "k", "l1", "m", "n", "o", "p", "q", "r", - "s1", "t", "Z", "A", "B", "E", "F5", "G", "H", "I0", "J", "S", "T", "d", "e", "f", "g1", - "U1", "V", "W3", "u", "v2", "w", "x", "y", "Xd", "Y", "Za", "gw", "Us", "Vd", "Wv", "X", - "Y", "Zx" - ] - bytes_data = str_param.encode('utf-8') - as_list = strlist.copy() - if str2_param and len(str2_param) > 0: - for s in str2_param.split(','): - as_list.append(s) - sb = [] - for i in range(len(bytes_data)): - abs_val = abs(bytes_data[i] - i) % 100 - if abs_val < len(as_list): - sb.append(as_list[abs_val]) - return ''.join(sb) + "==" - - def send_increment_data(self, str_param, str2_param, str3_param=None): - bytes_data = str2_param.encode('utf-8') - sb = [] - loop_count = len(bytes_data) // 2 - for i in range(loop_count): - index = (len(bytes_data) - (i % 8)) - 1 - b = bytes_data[index] - sb.append(str(abs(bytes_data[i] - b) % 100)) - sb.append("$") - sb.append(str((bytes_data[(len(bytes_data) - 1) - i] + b) % 100)) - sb.append("$") - substring = ''.join(sb)[loop_count:] - strings = self.get_strings(substring, str3_param) - result = str_param + strings - return result - - def sign_encrypt(self,text): - key = "ZXJsaW5nZXJlcm5pYW5zaXl1ZWVyc2hp".encode('utf-8') - cipher = AES.new(key, AES.MODE_ECB) - text_bytes = text.encode('utf-8') - padded_text = pad(text_bytes, AES.block_size) - encrypted_bytes = cipher.encrypt(padded_text) - encrypted_base64 = base64.b64encode(encrypted_bytes).decode('utf-8') - return encrypted_base64 - - def decrypt(self, encrypted_data): - try: - private_key = self.private_key - if not private_key.startswith('-----'): - private_key = f'-----BEGIN RSA PRIVATE KEY-----\n{private_key}\n-----END RSA PRIVATE KEY-----' - private_key = RSA.importKey(private_key) - cipher = PKCS1_v1_5.new(private_key) - decoded_data = base64.b64decode(encrypted_data) - key_size = private_key.size_in_bytes() - decrypted_text_parts = [] - if len(decoded_data) > key_size: - i = 0 - while i < len(decoded_data): - chunk = decoded_data[i:i + key_size] - decrypted_chunk = cipher.decrypt(chunk, None) - if decrypted_chunk is None: - raise ValueError("解密失败,可能是数据损坏或密钥不匹配") - decrypted_text_parts.append(decrypted_chunk.decode('utf-8')) - i += key_size - else: - decrypted_data = cipher.decrypt(decoded_data, None) - if decrypted_data is None: - raise ValueError("解密失败,可能是数据损坏或密钥不匹配") - decrypted_text_parts.append(decrypted_data.decode('utf-8')) - return ''.join(decrypted_text_parts) - except Exception: - return None - - def signKey(self,timestamp): - return self.send_increment_data(timestamp, f'{self.android_id}{self.md5(self.app_cert_sha1)}{timestamp}') - - def bid(self, str_param): - str_to_c2 = { - "fluent": 2, "normal": 4, "super2": 15, "4K": 22, "4k": 23, "原画": 13, - "标清": 3, "极速": 1, "流畅": 0, "蓝光": 14, "超清": 9, "高清": 5, - "360P": 17, "360p": 16, "540P": 8, "540p": 7, "720P": 12, "720p": 11, - "high": 6, "1080P": 19, "1080p": 18, "1280P": 21, "1280p": 20, "super": 10 - } - result_mapping = [ - (0, 2, "200", "fluent"), (3, 4, "300", "normal"), (5, 8, "300", "high"), (9, 10, "500", "super"), - (11, 12, "400", "super2"), - (13, 15, "600", "super2"), (16, 17, "200", "normal"), (18, 19, "500", "super2"), (20, 21, "600", "super2"), - (22, 23, "800", "super2") - ] - if not str_param: - return {} - c2 = str_to_c2.get(str_param, 65535) - for min_val, max_val, bid, fmt in result_mapping: - if min_val <= c2 <= max_val: - return bid - return "300" - - def homeVideoContent(self): - pass - - def getName(self): - pass - - def isVideoFormat(self, url): - pass - - def manualVideoCheck(self): - pass - - def destroy(self): - pass - - def localProxy(self, param): - pass \ No newline at end of file