diff --git a/lrzy/api.json b/lrzy/api.json new file mode 100644 index 0000000..2484fa5 --- /dev/null +++ b/lrzy/api.json @@ -0,0 +1,1560 @@ +{ + "logo": "./assets/logo2025121201.png", + "warningText": "禁止任何商业用途,仅限个人学习爬虫原理使用!", + "wallpaper": "https://tu.ltyuanfang.cn/api/fengjing.php", + "spider": "./jar/dongli-spider.jar", + "sites": [ + { + "key": "Douban", + "name": "📚|豆瓣|推荐", + "type": 3, + "api": "csp_Douban", + "searchable": 0, + "filterable": 1 + }, + { + "key": "配置", + "name": "🔨|配置|中心", + "type": 3, + "api": "csp_ConfigCenter", + "searchable": 0, + "changeable": 0, + "style": { + "type": "list", + "ratio": 1.433 + }, + "ext": "./config/configcenter.json" + }, + { + "key": "wogg", + "name": "💗|玩偶|网盘", + "type": 3, + "api": "csp_Wogg", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://woggpan.888484.xyz/", + "https://wogg.333232.xyz/", + "http://woggpan.xxooo.cf/", + "https://www.wogg.one/", + "http://www.wogg.lol/", + "https://wogg.xxooo.cf/" + ] + } + }, + { + "key": "木偶", + "name": "💗|木偶|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://123.666291.xyz", + "https://666.666291.xyz", + "https://www.muou.site", + "https://www.muou.asia" + ] + } + }, + { + "key": "蜡笔", + "name": "💗|蜡笔|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://www.labi88.sbs", + "https://feimao666.fun", + "http://feimao888.fun" + ] + } + }, + { + "key": "至臻", + "name": "💗|至臻|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://mihdr.top", + "https://www.miqk.cc", + "https://xiaomiai.site", + "https://xiaomi666.fun", + "https://www.mihdr.top", + "https://www.zhizhenpan.fun" + ] + } + }, + { + "key": "多多", + "name": "💗|多多|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://tv.yydsys.top", + "https://tv.yydsys.cc", + "https://tv.214521.xyz" + ] + } + }, + { + "key": "欧哥", + "name": "💗|欧哥|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://woog.nxog.eu.org", + "https://woog.nxog.fun", + "https://woog.430520.xyz", + "https://woog.nxog.de5.net", + "https://woog.装歌.de5.net" + ] + } + }, + { + "key": "二小", + "name": "💗|二小|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://xhww.net", + "https://erxiaofn.site", + "https://erxiaofn.click", + "https://www.xhww.net" + ] + } + }, + { + "key": "虎斑", + "name": "💗|虎斑|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "http://103.45.162.207:20720" + ] + } + }, + { + "key": "闪电", + "name": "💗|闪电|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "https://shandian.blog", + "https://sd.sduc.site" + ] + } + }, + { + "key": "小飒", + "name": "💗|小飒|网盘", + "type": 3, + "api": "csp_MacCMS", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0, + "ext": { + "site": [ + "http://xsayang.fun:12512" + ] + } + }, + { + "key": "Libvio", + "name": "💗|立播|网盘", + "type": 3, + "api": "csp_Libvio", + "searchable": 1, + "filterable": 0, + "changeable": 0, + "ext": "https://www.libvio.mov" + }, + { + "key": "KuaKeS", + "name": "💗|夸社|网盘", + "type": 3, + "api": "csp_KuaKeS", + "searchable": 1, + "filterable": 0, + "changeable": 0, + "ext": {} + }, + { + "key": "盘它", + "name": "💗|盘它|网盘", + "type": 3, + "api": "csp_PanTa", + "searchable": 1, + "filterable": 0, + "changeable": 0, + "style": { + "type": "list" + } + }, + { + "key": "人人", + "name": "💗|人人|网盘", + "type": 3, + "api": "csp_RenRen", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0 + }, + { + "key": "4k指南", + "name": "💗|4K|指南", + "type": 3, + "api": "csp_FourKZn", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 0 + }, + { + "key": "glod", + "name": "👑|金牌 | 影视", + "type": 3, + "api": "csp_Glod", + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "pingguo", + "name": "🍎|苹果|影视", + "type": 3, + "api": "csp_PingGuo", + "searchable": 1, + "changeable": 1, + "ext": { + "siteUrl": "http://asp.xpgtv.com", + "filterKeywords": [ + "及时雨", + "及時雨" + ] + } + }, + { + "key": "guazi", + "name": "🍉|瓜子 | 影视", + "type": 3, + "api": "csp_Guazi", + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "jianpian", + "name": "🎬|贱片|P2P", + "type": 3, + "api": "csp_Jianpian", + "searchable": 1, + "changeable": 1, + "ext": "./config/jianpian.json" + }, + { + "key": "Xb6v", + "name": "🍀|新6V|磁力", + "type": 3, + "api": "csp_Xb6v", + "searchable": 1, + "filterable": 1 + }, + { + "key": "juheduanju", + "name": "🌟|聚合|短剧", + "type": 3, + "api": "csp_JuheShortDrama", + "changeable": 0 + }, + { + "key": "xiqu", + "name": "🎭|戏曲┃大全", + "type": 3, + "api": "csp_Xiqu", + "ext": "" + }, + { + "key": "樱花动漫", + "name": "🌸|樱花|动漫", + "type": 3, + "api": "csp_YHDM", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "CNTV", + "name": "📰|CNTV|新闻", + "type": 3, + "api": "csp_CntvSpider", + "style": { + "type": "rect", + "ratio": 1.433 + }, + "changeable": 1 + }, + { + "key": "tingchina", + "name": "⛵|海盗|听书", + "type": 3, + "api": "csp_TingChina", + "changeable": 0, + "filterable": 1 + }, + { + "key": "wuwei", + "name": "🎧|六月|听书", + "type": 3, + "api": "csp_WuWeiTing", + "changeable": 0, + "filterable": 1 + }, + { + "key": "蜻蜓FM", + "name": "📻|蜻蜓┃FM", + "type": 3, + "api": "csp_QingTing", + "ext": "" + }, + { + "key": "星影", + "name": "✨|星影|直播", + "type": 3, + "api": "csp_AppGet", + "searchable": 1, + "quickSearch": 1, + "changeable": 0, + "filterable": 1, + "timeout": 30, + "ext": { + "site": "http://110.81.153.7:1963/get.txt", + "dataKey": "k7L9mQ2xR4pW8n88", + "dataIv": "k7L9mQ2xR4pW8n88", + "version": "2" + } + }, + { + "key": "Huya", + "name": "🐯|虎牙|直播", + "type": 3, + "api": "csp_Huya", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 1, + "timeout": 10, + "style": { + "type": "rect", + "ratio": 1.433 + } + }, + { + "key": "Douyu", + "name": "🐟|斗鱼|直播", + "type": 3, + "api": "csp_Douyu", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 1, + "timeout": 10, + "style": { + "type": "rect", + "ratio": 1.433 + } + }, + { + "key": "BiliLive", + "name": "🌈|哔哩|直播", + "type": 3, + "api": "csp_BiliLive", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 1, + "timeout": 10, + "style": { + "type": "rect", + "ratio": 1.433 + } + }, + { + "key": "bilibili", + "name": "🌈|哔哩|合集", + "type": 3, + "api": "csp_Bili", + "searchable": 1, + "changeable": 1, + "style": { + "type": "rect", + "ratio": 1.433 + }, + "ext": { + "json": "./config/bilibili.json", + "cookie": "" + } + }, + { + "key": "哔哩哔哩演唱会", + "name": "🌈|哔哩|音乐", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 0, + "ext": { + "json": "./config/blych.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "哔哩哔哩听书", + "name": "🌈|哔哩|听书", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 0, + "ext": { + "json": "./config/blts.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "哔哩哔哩相声", + "name": "🌈|哔哩|相声", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 0, + "ext": { + "json": "./config/blxs.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "哔哩哔哩小品", + "name": "🌈|哔哩|小品", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 0, + "ext": { + "json": "./config/blxp.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "哔哩哔哩戏曲", + "name": "🌈|哔哩|戏曲", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 0, + "ext": { + "json": "./config/blxq.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "少儿教育", + "name": "🌈|少儿|教育", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 1, + "ext": { + "json": "./config/sejy.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "小学课堂", + "name": "🌈|小学|课堂", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 1, + "ext": { + "json": "./config/xxkt.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "初中课堂", + "name": "🌈|初中|课堂", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 1, + "ext": { + "json": "./config/czkt.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "高中课堂", + "name": "🌈|高中|课堂", + "type": 3, + "api": "csp_Bili", + "searchable": 0, + "quickSearch": 0, + "filterable": 1, + "ext": { + "json": "./config/gzkt.json", + "cookie": "" + }, + "style": { + "type": "rect", + "ratio": 1.597 + } + }, + { + "key": "哔哩影视", + "name": "🌈|哔哩|影视", + "type": 3, + "api": "csp_BiliPGC", + "searchable": 1, + "quickSearch": 0, + "filterable": 0, + "changeable": 0, + "style": { + "type": "rect", + "ratio": 1.597 + }, + "ext": { + "json": "./config/blys.json", + "cookie": "" + } + }, + { + "key": "热播影视", + "name": "🎈|热播|APP", + "type": 3, + "api": "csp_AppRJ", + "searchable": 1, + "quickSearch": 1, + "filterable": 0, + "ext": { + "site": [ + "http://v.rbotv.cn" + ] + } + }, + { + "key": "火狐", + "name": "🎃|火狐|APP", + "type": 3, + "api": "csp_AppGet", + "ext": { + "site": "http://122.114.171.79:568/huohushipin.txt", + "dataKey": "huohushipingetap", + "dataIv": "huohushipingetap" + } + }, + { + "key": "白鸽", + "name": "🎃|白鸽|APP", + "type": 3, + "searchable": 1, + "changeable": 1, + "api": "csp_AppGet", + "ext": { + "url": "https://cy.baige.asia", + "dataKey": "599D0FE5178642FD", + "dataIv": "599D0FE5178642FD" + } + }, + { + "key": "剧梦", + "name": "🎃|剧梦|APP", + "type": 3, + "searchable": 1, + "changeable": 1, + "api": "csp_AppGet", + "ext": { + "url": "https://www.jumengwu.com", + "dataKey": "1f0a873caf2550a5", + "dataIv": "1f0a873caf2550a5" + } + }, + { + "key": "魔方", + "name": "🎃|魔方|APP", + "type": 3, + "searchable": 1, + "changeable": 1, + "api": "csp_AppGet", + "ext": { + "site": "https://snysw.xyz/mf4kzs327.txt", + "dataKey": "1234567887654321", + "dataIv": "1234567887654321" + } + }, + { + "key": "茉莉", + "name": "🎃|茉莉|APP", + "type": 3, + "searchable": 1, + "api": "csp_AppGet", + "ext": { + "site": "https://gitee.com/wmmoliill/wimg/raw/master/img/bk/9.txt", + "dataKey": "88689667dce61725", + "dataIv": "88689667dce61725" + } + }, + { + "key": "灵虎", + "name": "🎃|灵虎|APP", + "type": 3, + "quickSearch": 1, + "api": "csp_AppGet", + "ext": { + "site": "https://bind.315999.xyz/89.txt", + "dataKey": "#getapp@TMD@2025", + "dataIv": "#getapp@TMD@2025", + "version": "120" + } + }, + { + "key": "奇奇1", + "name": "🎃|奇1|APP", + "type": 3, + "api": "csp_AppQi", + "changeable": 0, + "quickSearch": 1, + "filterable": 1, + "ext": { + "url": "http://110.42.67.221:8006", + "dataKey": "123456789abcdefg", + "dataIv": "123456789abcdefg", + "search": "searchList7", + "init": "initV122", + "ua": "okhttp/3.10.0" + } + }, + { + "key": "爱盈", + "name": "🎃|爱盈|APP", + "type": 3, + "api": "csp_AppQi", + "changeable": "1", + "quickSearch": 1, + "filterable": 1, + "ext": { + "site": "https://rxysyyds.oss-cn-chengdu.aliyuncs.com/qiji.txt", + "dataKey": "sjvlwnhk6h9znl61", + "dataIv": "sjvlwnhk6h9znl61", + "version": "305", + "ua": "okhttp/3.10.0" + } + }, + { + "key": "金牌", + "name": "🎃|金牌|APP", + "type": 3, + "api": "csp_AppQi", + "changeable": "1", + "quickSearch": 1, + "filterable": 1, + "ext": { + "site": "https://dtqj.ggtvb.cc/dtjp.txt", + "dataKey": "eecbio48dsq131ee", + "dataIv": "eecbio48dsq131ee", + "search": "searchList4", + "version": "305", + "init": "initV122", + "ua": "okhttp/3.10.0" + } + }, + { + "key": "奇奇2", + "name": "🎃|奇2|APP", + "type": 3, + "api": "csp_AppQi", + "ext": { + "site": "https://yun-1316442804.cos.ap-guangzhou.myqcloud.com/a.txt", + "dataKey": "123456789abcdefg", + "dataIv": "123456789abcdefg" + } + }, + { + "key": "Jzb", + "name": "🏀┃说球┃回放", + "type": 3, + "api": "csp_Jzb", + "searchable": 0, + "changeable": 0, + "style": { + "type": "list" + }, + "gridview": 3, + "ext": { + "sites": "" + } + }, + { + "key": "88看球", + "name": "⚽|看球|直播", + "type": 3, + "api": "csp_Kanqiu", + "searchable": 0, + "changeable": 0, + "gridview": 3, + "style": { + "type": "list" + } + }, + { + "key": "push_agent", + "name": "📢|推送|中心", + "type": 3, + "api": "csp_Push", + "hide": 1, + "searchable": 0, + "changeable": 0, + "timeout": 60 + }, + { + "key": "本地文件", + "name": "🐾|本地|文件", + "type": 3, + "searchable": 0, + "changeable": 0, + "api": "csp_Local" + }, + { + "key": "localdb", + "name": "👣|本地数据库", + "type": 3, + "api": "csp_LocalDB", + "searchable": 1, + "quickSearch": 1, + "changeable": 0, + "filterable": 1, + "ext": "" + }, + { + "key": "song_1a48b", + "name": "🎼|网络数据库KTV", + "type": 3, + "api": "csp_KTV", + "searchable": 1, + "quickSearch": 1, + "changeable": 0, + "filterable": 1, + "ext": "" + }, + { + "key": "networkdb", + "name": "💞|网络数据库合集", + "type": 3, + "api": "csp_NetworkDB", + "searchable": 1, + "quickSearch": 1, + "changeable": 0, + "filterable": 1, + "ext": "" + }, + { + "key": "急救教学", + "name": "🚑|急救|教学", + "type": 3, + "api": "csp_FirstAid", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "style": { + "type": "rect", + "ratio": 3.8 + }, + "gridview": "0-0-4.1" + }, + { + "key": "myuc", + "name": "🌆|我的┃优囍", + "type": 3, + "api": "csp_MyUC", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 0, + "indexs": 0, + "style": { + "type": "list" + }, + "timeout": 30, + "ext": "./config/myuc.json" + }, + { + "key": "myquark", + "name": "🌆|我的┃夸氪", + "type": 3, + "api": "csp_MyQuark", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 0, + "indexs": 0, + "style": { + "type": "list" + }, + "timeout": 30, + "ext": "./config/myquark.json" + }, + { + "key": "mybaidu", + "name": "🌆|我的┃百度", + "type": 3, + "api": "csp_MyBaiDu", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 0, + "indexs": 0, + "style": { + "type": "list" + }, + "timeout": 30, + "ext": "./config/mybaidu.json" + }, + { + "key": "myali", + "name": "🌆|我的┃阿里", + "type": 3, + "api": "csp_MyAli", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 0, + "indexs": 0, + "style": { + "type": "list" + }, + "timeout": 30, + "ext": "./config/myali.json" + }, + { + "key": "mytianyi", + "name": "🌆|我的┃天懿", + "type": 3, + "api": "csp_MyTianYi", + "searchable": 0, + "quickSearch": 0, + "changeable": 0, + "filterable": 0, + "indexs": 0, + "style": { + "type": "list" + }, + "timeout": 30 + }, + { + "key": "商店", + "name": "🏬|商店|更新", + "type": 3, + "api": "csp_Market", + "searchable": 0, + "changeable": 0, + "style": { + "type": "oval", + "ratio": 1.1 + }, + "ext": "./config/market.json" + }, + { + "key": "Tg123Search", + "name": "💖|123┃TG搜", + "type": 3, + "api": "csp_Tg123Search", + "hide": 1, + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "TgbaiduSearch", + "name": "💖|百度┃TG搜", + "type": 3, + "api": "csp_TgbaiduSearch", + "hide": 1, + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "Tg189Search", + "name": "💖|天翼┃TG搜", + "type": 3, + "api": "csp_Tg189Search", + "hide": 1, + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "TgQuarkSearch", + "name": "💖|夸克┃TG搜", + "type": 3, + "api": "csp_TgQuarkSearch", + "hide": 1, + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "TgAliSearch", + "name": "💖|阿里┃TG搜", + "type": 3, + "api": "csp_TgAliSearch", + "hide": 1, + "searchable": 1, + "changeable": 1, + "ext": {} + }, + { + "key": "PanSouQuark", + "name": "💖|夸克┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "hide": 1, + "filterable": 0, + "changeable": 1, + "ext": { + "sources": [ + "夸克" + ] + } + }, + { + "key": "PanSouUc", + "name": "💖|优囍┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "changeable": 1, + "hide": 1, + "filterable": 0, + "ext": { + "sources": [ + "UC" + ] + } + }, + { + "key": "PanSouAli", + "name": "💖|阿里┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "hide": 1, + "changeable": 1, + "filterable": 0, + "ext": { + "sources": [ + "阿里" + ] + } + }, + { + "key": "PanSouBaidu", + "name": "💖|百度┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "hide": 1, + "changeable": 1, + "filterable": 0, + "ext": { + "sources": [ + "百度" + ] + } + }, + { + "key": "PanSou123", + "name": "💖|123┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "changeable": 1, + "hide": 1, + "filterable": 0, + "ext": { + "sources": [ + "123盘" + ] + } + }, + { + "key": "PanSou189", + "name": "💖|天翼┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "filterable": 0, + "changeable": 1, + "hide": 1, + "ext": { + "sources": [ + "天翼" + ] + } + }, + { + "key": "PanSou139", + "name": "💖|移动┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "hide": 1, + "changeable": 1, + "filterable": 0, + "ext": { + "sources": [ + "移动" + ] + } + }, + { + "key": "PanSouMagnet", + "name": "💖|磁力┃盘搜", + "type": 3, + "api": "csp_PanSou", + "searchable": 1, + "hide": 1, + "filterable": 0, + "changeable": 1, + "ext": { + "sources": [ + "磁力" + ] + } + } + ], + "lives": [ + { + "name": "冰茶", + "type": 0, + "playerType": 2, + "url": "https://bc.188766.xyz/?ip=&mima=bingcha1130&json=true", + "ua": "bingcha/1.1 (mianfeifenxiang) " + }, + { + "name": "电视直播", + "type": "0", + "pass": true, + "url": "http://gh-proxy.org/raw.githubusercontent.com/Supprise0901/TVBox_live/main/live.txt", + "epg": "https://epg.112114.xyz/?ch={name}&date={date}", + "logo": "https://epg.112114.xyz/logo/{name}.png" + }, + { + "name": "EPG直播", + "type": "0", + "pass": true, + "url": "http://gh-proxy.org/https://raw.githubusercontent.com/Wirili/IPTV/main/live.txt", + "epg": "https://epg.112114.xyz/?ch={name}&date={date}", + "logo": "https://epg.112114.xyz/logo/{name}.png" + } + ], + "parses": [ + { + "name": "爱心", + "type": 4, + "url": "http://119.91.123.253:2345/Api/yun.php?url=", + "ext": { + "header": { + "user-agent": "Mozilla/5.0 (Linux; Android 9; DUK-AL20) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Mobile Safari/537.36" + } + } + }, + { + "name": "淘片", + "type": 0, + "url": "https://jx.yparse.com/index.php?url=", + "ext": { + "header": { + "user-agent": "Mozilla/5.0 (Linux; Android 9; DUK-AL20) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Mobile Safari/537.36" + } + } + } + ], + "flags": [ + "youku", + "qq", + "iqiyi", + "qiyi", + "letv", + "sohu", + "tudou", + "pptv", + "mgtv", + "wasu", + "bilibili", + "leshi", + "renrenmi", + "migu", + "B站(解析)", + "B站(AVC)", + "B站(HEVC)", + "B站(AV1)" + ], + "ijk": [ + { + "group": "软解码", + "options": [ + { + "category": 4, + "name": "opensles", + "value": "0" + }, + { + "category": 4, + "name": "overlay-format", + "value": "842225234" + }, + { + "category": 4, + "name": "framedrop", + "value": "1" + }, + { + "category": 4, + "name": "soundtouch", + "value": "1" + }, + { + "category": 4, + "name": "start-on-prepared", + "value": "1" + }, + { + "category": 1, + "name": "http-detect-range-support", + "value": "0" + }, + { + "category": 1, + "name": "fflags", + "value": "fastseek" + }, + { + "category": 2, + "name": "skip_loop_filter", + "value": "48" + }, + { + "category": 4, + "name": "reconnect", + "value": "1" + }, + { + "category": 4, + "name": "enable-accurate-seek", + "value": "0" + }, + { + "category": 4, + "name": "mediacodec", + "value": "0" + }, + { + "category": 4, + "name": "mediacodec-auto-rotate", + "value": "0" + }, + { + "category": 4, + "name": "mediacodec-handle-resolution-change", + "value": "0" + }, + { + "category": 4, + "name": "mediacodec-hevc", + "value": "0" + }, + { + "category": 1, + "name": "dns_cache_timeout", + "value": "600000000" + } + ] + }, + { + "group": "硬解码", + "options": [ + { + "category": 4, + "name": "opensles", + "value": "0" + }, + { + "category": 4, + "name": "overlay-format", + "value": "842225234" + }, + { + "category": 4, + "name": "framedrop", + "value": "1" + }, + { + "category": 4, + "name": "soundtouch", + "value": "1" + }, + { + "category": 4, + "name": "start-on-prepared", + "value": "1" + }, + { + "category": 1, + "name": "http-detect-range-support", + "value": "0" + }, + { + "category": 1, + "name": "fflags", + "value": "fastseek" + }, + { + "category": 2, + "name": "skip_loop_filter", + "value": "48" + }, + { + "category": 4, + "name": "reconnect", + "value": "1" + }, + { + "category": 4, + "name": "enable-accurate-seek", + "value": "0" + }, + { + "category": 4, + "name": "mediacodec", + "value": "1" + }, + { + "category": 4, + "name": "mediacodec-auto-rotate", + "value": "1" + }, + { + "category": 4, + "name": "mediacodec-handle-resolution-change", + "value": "1" + }, + { + "category": 4, + "name": "mediacodec-hevc", + "value": "1" + }, + { + "category": 1, + "name": "dns_cache_timeout", + "value": "600000000" + } + ] + } + ], + "ads": [ + "mimg.0c1q0l.cn", + "www.googletagmanager.com", + "www.google-analytics.com", + "mc.usihnbcq.cn", + "mg.g1mm3d.cn", + "mscs.svaeuzh.cn", + "cnzz.hhttm.top", + "tp.vinuxhome.com", + "cnzz.mmstat.com", + "www.baihuillq.com", + "s23.cnzz.com", + "z3.cnzz.com", + "c.cnzz.com", + "stj.v1vo.top", + "z12.cnzz.com", + "img.mosflower.cn", + "tips.gamevvip.com", + "ehwe.yhdtns.com", + "xdn.cqqc3.com", + "www.jixunkyy.cn", + "sp.chemacid.cn", + "hm.baidu.com", + "s9.cnzz.com", + "z6.cnzz.com", + "um.cavuc.com", + "mav.mavuz.com", + "wofwk.aoidf3.com", + "z5.cnzz.com", + "xc.hubeijieshikj.cn", + "tj.tianwenhu.com", + "xg.gars57.cn", + "k.jinxiuzhilv.com", + "cdn.bootcss.com", + "ppl.xunzhuo123.com", + "xomk.jiangjunmh.top", + "img.xunzhuo123.com", + "z1.cnzz.com", + "s13.cnzz.com", + "xg.huataisangao.cn", + "z7.cnzz.com", + "xg.huataisangao.cn", + "z2.cnzz.com", + "s96.cnzz.com", + "q11.cnzz.com", + "thy.dacedsfa.cn", + "xg.whsbpw.cn", + "s19.cnzz.com", + "z8.cnzz.com", + "s4.cnzz.com", + "f5w.as12df.top", + "ae01.alicdn.com", + "www.92424.cn", + "k.wudejia.com", + "vivovip.mmszxc.top", + "qiu.xixiqiu.com", + "cdnjs.hnfenxun.com", + "cms.qdwght.com" + ], + "doh": [ + { + "name": "Google", + "url": "https://dns.google/dns-query", + "ips": [ + "8.8.4.4", + "8.8.8.8" + ] + }, + { + "name": "Cloudflare", + "url": "https://cloudflare-dns.com/dns-query", + "ips": [ + "1.1.1.1", + "1.0.0.1", + "2606:4700:4700::1111", + "2606:4700:4700::1001" + ] + }, + { + "name": "AdGuard", + "url": "https://dns.adguard.com/dns-query", + "ips": [ + "94.140.14.140", + "94.140.14.141" + ] + }, + { + "name": "DNSWatch", + "url": "https://resolver2.dns.watch/dns-query", + "ips": [ + "84.200.69.80", + "84.200.70.40" + ] + }, + { + "name": "Quad9", + "url": "https://dns.quad9.net/dns-query", + "ips": [ + "9.9.9.9", + "149.112.112.112" + ] + } + ], + "rules": [ + { + "name": "proxy", + "hosts": [ + "hlsztemgsplive.miguvideo.com=hlsztemgsplive.188766.xyz", + "cache.ott.fifalive.itv.cmvideo.cn=fifalive.188766.xyz", + "iptv.huuc.edu.cn=huucv6.188766.xyz", + "raw.githubusercontent.com", + "googlevideo.com", + "cdn.v82u1l.com", + "cdn.iz8qkg.com", + "cdn.kin6c1.com", + "c.biggggg.com", + "c.olddddd.com", + "haiwaikan.com", + "www.histar.tv", + "youtube.com", + "uhibo.com", + ".*boku.*", + ".*nivod.*", + ".*ulivetv.*" + ] + }, + { + "name": "海外看", + "hosts": [ + "haiwaikan" + ], + "regex": [ + "10.0099", + "10.3333", + "16.0599", + "8.1748", + "12.33", + "10.85" + ] + }, + { + "name": "火山嗅探", + "hosts": [ + "huoshan.com" + ], + "regex": [ + "item_id=" + ] + }, + { + "name": "抖音嗅探", + "hosts": [ + "douyin.com" + ], + "regex": [ + "is_play_url=" + ] + }, + { + "name": "農民嗅探", + "hosts": [ + "toutiaovod.com" + ], + "regex": [ + "video/tos/cn" + ] + }, + { + "name": "新视觉嗅探", + "hosts": [ + "muzhi-video.bj.bcebos.com" + ], + "regex": [ + "202403/" + ] + }, + { + "name": "七新嗅探", + "hosts": [ + "api.52wyb.com" + ], + "regex": [ + "m3u8?pt=m3u8" + ] + }, + { + "name": "夜市點擊", + "hosts": [ + "yeslivetv.com" + ], + "script": [ + "document.getElementsByClassName('vjs-big-play-button')[0].click()" + ] + }, + { + "name": "毛驢點擊", + "hosts": [ + "www.maolvys.com" + ], + "script": [ + "document.getElementsByClassName('swal-button swal-button--confirm')[0].click()" + ] + } + ], + "headers": [ + { + "host": "hlsztemgsplive.miguvideo.com", + "header": { + "User-Agent": "bingcha/1.1 (mianfeifenxiang) " + } + } + ] +} \ No newline at end of file diff --git a/lrzy/assets/db2025121201.png b/lrzy/assets/db2025121201.png new file mode 100644 index 0000000..843050f Binary files /dev/null and b/lrzy/assets/db2025121201.png differ diff --git a/lrzy/assets/logo2025121201.png b/lrzy/assets/logo2025121201.png new file mode 100644 index 0000000..3e10165 Binary files /dev/null and b/lrzy/assets/logo2025121201.png differ diff --git a/lrzy/cj.json b/lrzy/cj.json new file mode 100644 index 0000000..9f16577 --- /dev/null +++ b/lrzy/cj.json @@ -0,0 +1,600 @@ +{ + "logo": "./assets/logo2025121201.png", + "sites": [ + { + "key": "TV-量子资源", + "name": "TV-量子资源", + "type": 1, + "api": "https://cj.lziapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-1080资源", + "name": "TV-1080资源", + "type": 1, + "api": "https://api.1080zyku.com/inc/api_mac10.php", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-360资源", + "name": "TV-360资源", + "type": 1, + "api": "https://360zy.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-天涯资源", + "name": "TV-天涯资源", + "type": 1, + "api": "https://tyyszy.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-暴风资源", + "name": "TV-暴风资源", + "type": 1, + "api": "https://bfzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-索尼-闪电资源", + "name": "TV-索尼-闪电资源", + "type": 1, + "api": "https://xsd.sdzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-索尼资源", + "name": "TV-索尼资源", + "type": 1, + "api": "https://suoniapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-红牛资源", + "name": "TV-红牛资源", + "type": 1, + "api": "https://www.hongniuzy2.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-茅台资源", + "name": "TV-茅台资源", + "type": 1, + "api": "https://caiji.maotaizy.cc/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-虎牙资源", + "name": "TV-虎牙资源", + "type": 1, + "api": "https://www.huyaapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-豆瓣资源", + "name": "TV-豆瓣资源", + "type": 1, + "api": "https://caiji.dbzy.tv/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-豆瓣资源2", + "name": "TV-豆瓣资源2", + "type": 1, + "api": "https://dbzy.tv/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-豆瓣资源3", + "name": "TV-豆瓣资源3", + "type": 1, + "api": "https://caiji.dbzy5.com/api.php/provide/vod/from/dbm3u8/at/josn", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-豪华资源", + "name": "TV-豪华资源", + "type": 1, + "api": "https://hhzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-CK资源", + "name": "TV-CK资源", + "type": 1, + "api": "https://ckzy.me/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-U酷资源", + "name": "TV-U酷资源", + "type": 1, + "api": "https://api.ukuapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-U酷资源2", + "name": "TV-U酷资源2", + "type": 1, + "api": "https://api.ukuapi88.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-ikun资源", + "name": "TV-ikun资源", + "type": 1, + "api": "https://ikunzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-wujinapi无尽", + "name": "TV-wujinapi无尽", + "type": 1, + "api": "https://api.wujinapi.cc/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-丫丫点播", + "name": "TV-丫丫点播", + "type": 1, + "api": "https://cj.yayazy.net/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-光速资源", + "name": "TV-光速资源", + "type": 1, + "api": "https://api.guangsuapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-卧龙点播", + "name": "TV-卧龙点播", + "type": 1, + "api": "https://collect.wolongzyw.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-卧龙资源", + "name": "TV-卧龙资源", + "type": 1, + "api": "https://collect.wolongzy.cc/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-卧龙资源2", + "name": "TV-卧龙资源2", + "type": 1, + "api": "https://wolongzyw.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-新浪点播", + "name": "TV-新浪点播", + "type": 1, + "api": "https://api.xinlangapi.com/xinlangapi.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-无尽资源", + "name": "TV-无尽资源", + "type": 1, + "api": "https://api.wujinapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-无尽资源2", + "name": "TV-无尽资源2", + "type": 1, + "api": "https://api.wujinapi.me/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-无尽资源3", + "name": "TV-无尽资源3", + "type": 1, + "api": "https://api.wujinapi.net/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-旺旺短剧", + "name": "TV-旺旺短剧", + "type": 1, + "api": "https://wwzy.tv/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-最大点播", + "name": "TV-最大点播", + "type": 1, + "api": "http://zuidazy.me/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-最大资源", + "name": "TV-最大资源", + "type": 1, + "api": "https://api.zuidapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-樱花资源", + "name": "TV-樱花资源", + "type": 1, + "api": "https://m3u8.apiyhzy.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-步步高资源", + "name": "TV-步步高资源", + "type": 1, + "api": "https://api.yparse.com/api/json", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-牛牛点播", + "name": "TV-牛牛点播", + "type": 1, + "api": "https://api.niuniuzy.me/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-百度云资源", + "name": "TV-百度云资源", + "type": 1, + "api": "https://api.apibdzy.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-神马云", + "name": "TV-神马云", + "type": 1, + "api": "https://api.1080zyku.com/inc/apijson.php/", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-速博资源", + "name": "TV-速博资源", + "type": 1, + "api": "https://subocaiji.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-金鹰点播", + "name": "TV-金鹰点播", + "type": 1, + "api": "https://jinyingzy.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-金鹰资源", + "name": "TV-金鹰资源", + "type": 1, + "api": "https://jyzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-閃電资源", + "name": "TV-閃電资源", + "type": 1, + "api": "https://sdzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-非凡资源", + "name": "TV-非凡资源", + "type": 1, + "api": "https://cj.ffzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-飘零资源", + "name": "TV-飘零资源", + "type": 1, + "api": "https://p2100.net/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-魔爪资源", + "name": "TV-魔爪资源", + "type": 1, + "api": "https://mozhuazy.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-魔都动漫", + "name": "TV-魔都动漫", + "type": 1, + "api": "https://caiji.moduapi.cc/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + }, + { + "key": "TV-魔都资源", + "name": "TV-魔都资源", + "type": 1, + "api": "https://www.mdzyapi.com/api.php/provide/vod", + "searchable": 1, + "quickSearch": 1, + "changeable": 1, + "filterable": 1, + "timeout": 10 + } + ], + "headers": [ + { + "host": "mgtv.ottiptv.cc", + "header": { + "User-Agent": "okHttp/Mod-1.4.0.0", + "Referer": "https://mgtv.ottiptv.cc/" + } + } + ], + "lives": [ + { + "name": "冰茶", + "type": 0, + "playerType": 2, + "url": "https://fy.188766.xyz/?ip=&mima=mianfeidehaimaiqian&json=true", + "ua": "bingcha/1.1(mianfeifenxiang)" + } + ], + "parses": [ + { + "name": "解析聚合", + "type": 3, + "url": "Web" + }, + { + "name": "777", + "type": 0, + "url": "https://www.huaqi.live/?url=" + }, + { + "name": "jsonplayer", + "type": 0, + "url": "https://jx.jsonplayer.com/player/?url=" + }, + { + "name": "xmflv", + "type": 0, + "url": "https://jx.xmflv.com/?url=" + } + ], + "flags": [ + "youku", + "tudou", + "qq", + "qiyi", + "iqiyi", + "leshi", + "letv", + "sohu", + "imgo", + "mgtv", + "bilibili", + "pptv", + "PPTV", + "migu" + ], + "doh": [ + { + "name": "Google", + "url": "https://dns.google/dns-query", + "ips": [ + "8.8.4.4", + "8.8.8.8" + ] + }, + { + "name": "Cloudflare", + "url": "https://cloudflare-dns.com/dns-query", + "ips": [ + "1.1.1.1", + "1.0.0.1", + "2606:4700:4700::1111", + "2606:4700:4700::1001" + ] + }, + { + "name": "AdGuard", + "url": "https://dns.adguard.com/dns-query", + "ips": [ + "94.140.14.140", + "94.140.14.141" + ] + }, + { + "name": "DNSWatch", + "url": "https://resolver2.dns.watch/dns-query", + "ips": [ + "84.200.69.80", + "84.200.70.40" + ] + }, + { + "name": "Quad9", + "url": "https://dns.quad9.net/dns-query", + "ips": [ + "9.9.9.9", + "149.112.112.112" + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/config/bilibili.json b/lrzy/config/bilibili.json new file mode 100644 index 0000000..690a9a8 --- /dev/null +++ b/lrzy/config/bilibili.json @@ -0,0 +1,5716 @@ +{ + "cookie": "", + "class": [ + { + "type_name": "沙雕动画", + "type_id": "沙雕动画" + }, + { + "type_name": "纪录片", + "type_id": "纪录片超清" + }, + { + "type_name": "演唱会", + "type_id": "演唱会超清" + }, + { + "type_name": "流行音乐", + "type_id": "音乐超清" + }, + { + "type_name": "美食", + "type_id": "美食超清" + }, + { + "type_name": "食谱", + "type_id": "食谱" + }, + { + "type_name": "体育", + "type_id": "体育超清" + }, + { + "type_name": "球星", + "type_id": "球星" + }, + { + "type_name": "教育", + "type_id": "中小学教育" + }, + { + "type_name": "幼儿教育", + "type_id": "幼儿教育" + }, + { + "type_name": "旅游", + "type_id": "旅游" + }, + { + "type_name": "风景", + "type_id": "风景4K" + }, + { + "type_name": "说案", + "type_id": "说案" + }, + { + "type_name": "知名UP主", + "type_id": "知名UP主" + }, + { + "type_name": "探索发现", + "type_id": "探索发现超清" + }, + { + "type_name": "鬼畜", + "type_id": "鬼畜" + }, + { + "type_name": "搞笑", + "type_id": "搞笑超清" + }, + { + "type_name": "儿童", + "type_id": "儿童超清" + }, + { + "type_name": "动物世界", + "type_id": "动物世界超清" + }, + { + "type_name": "相声小品", + "type_id": "相声小品超清" + }, + { + "type_name": "戏曲", + "type_id": "戏曲" + }, + { + "type_name": "解说", + "type_id": "解说" + }, + { + "type_name": "演讲", + "type_id": "演讲" + }, + { + "type_name": "小姐姐", + "type_id": "小姐姐超清" + }, + { + "type_name": "荒野求生", + "type_id": "荒野求生超清" + }, + { + "type_name": "健身", + "type_id": "健身" + }, + { + "type_name": "帕梅拉", + "type_id": "帕梅拉" + }, + { + "type_name": "太极拳", + "type_id": "太极拳" + }, + { + "type_name": "广场舞", + "type_id": "广场舞" + }, + { + "type_name": "舞蹈", + "type_id": "舞蹈" + }, + { + "type_name": "音乐", + "type_id": "音乐" + }, + { + "type_name": "歌曲", + "type_id": "歌曲" + }, + { + "type_name": "MV", + "type_id": "MV4K" + }, + { + "type_name": "舞曲", + "type_id": "舞曲超清" + }, + { + "type_name": "4K", + "type_id": "4K" + }, + { + "type_name": "电影", + "type_id": "电影" + }, + { + "type_name": "电视剧", + "type_id": "电视剧" + }, + { + "type_name": "白噪音", + "type_id": "白噪音超清" + }, + { + "type_name": "考公考证", + "type_id": "考公考证" + }, + { + "type_name": "平面设计教学", + "type_id": "平面设计教学" + }, + { + "type_name": "软件教程", + "type_id": "软件教程" + }, + { + "type_name": "Windows", + "type_id": "Windows" + } + ], + "filters": { + "考公考证": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "演唱会超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "演唱会超清" + }, + { + "n": "A阿杜", + "v": "阿杜演唱会超清" + }, + { + "n": "A阿黛尔", + "v": "阿黛尔演唱会超清" + }, + { + "n": "BBeyond", + "v": "Beyond演唱会超清" + }, + { + "n": "BBy2", + "v": "By2演唱会超清" + }, + { + "n": "BBIGBANG", + "v": "BIGBANG演唱会超清" + }, + { + "n": "B布兰妮", + "v": "布兰妮演唱会超清" + }, + { + "n": "B坂井泉水", + "v": "坂井泉水演唱会超清" + }, + { + "n": "C陈奕迅", + "v": "陈奕迅演唱会超清" + }, + { + "n": "C蔡依林", + "v": "蔡依林演唱会超清" + }, + { + "n": "C初音未来", + "v": "初音未来演唱会超清" + }, + { + "n": "C蔡健雅", + "v": "蔡健雅演唱会超清" + }, + { + "n": "C陈小春", + "v": "陈小春演唱会超清" + }, + { + "n": "C草蜢", + "v": "草蜢演唱会超清" + }, + { + "n": "C陈慧娴", + "v": "陈慧娴演唱会超清" + }, + { + "n": "C崔健", + "v": "崔健演唱会超清" + }, + { + "n": "C仓木麻衣", + "v": "仓木麻衣演唱会超清" + }, + { + "n": "D戴荃", + "v": "戴荃演唱会超清" + }, + { + "n": "D动力火车", + "v": "动力火车演唱会超清" + }, + { + "n": "D邓丽君", + "v": "邓丽君演唱会超清" + }, + { + "n": "D丁当", + "v": "丁当演唱会超清" + }, + { + "n": "D刀郎", + "v": "刀郎演唱会超清" + }, + { + "n": "D邓紫棋", + "v": "邓紫棋演唱会超清" + }, + { + "n": "D戴佩妮", + "v": "戴佩妮演唱会超清" + }, + { + "n": "D邓丽君", + "v": "邓丽君演唱会超清" + }, + { + "n": "F飞儿乐队", + "v": "飞儿乐队演唱会超清" + }, + { + "n": "F费玉清", + "v": "费玉清演唱会超清" + }, + { + "n": "F费翔", + "v": "费翔演唱会超清" + }, + { + "n": "F方大同", + "v": "方大同演唱会超清" + }, + { + "n": "F房东的猫", + "v": "房东的猫演唱会超清" + }, + { + "n": "F凤飞飞", + "v": "凤飞飞演唱会超清" + }, + { + "n": "F凤凰传奇", + "v": "凤凰传奇演唱会超清" + }, + { + "n": "G郭采洁", + "v": "郭采洁演唱会超清" + }, + { + "n": "G光良", + "v": "光良演唱会超清" + }, + { + "n": "G郭静", + "v": "郭静演唱会超清" + }, + { + "n": "G郭富城", + "v": "郭富城演唱会超清" + }, + { + "n": "H胡彦斌", + "v": "胡彦斌演唱会超清" + }, + { + "n": "H胡夏", + "v": "胡夏演唱会超清" + }, + { + "n": "H韩红", + "v": "韩红演唱会超清" + }, + { + "n": "H黄品源", + "v": "黄品源演唱会超清" + }, + { + "n": "H黄小琥", + "v": "黄小琥演唱会超清" + }, + { + "n": "H花儿乐队", + "v": "花儿乐队演唱会超清" + }, + { + "n": "H黄家强", + "v": "黄家强演唱会超清" + }, + { + "n": "H后街男孩", + "v": "后街男孩演唱会超清" + }, + { + "n": "J经典老歌", + "v": "经典老歌演唱会超清" + }, + { + "n": "J贾斯丁比伯", + "v": "贾斯丁比伯演唱会超清" + }, + { + "n": "J金池", + "v": "金池演唱会超清" + }, + { + "n": "J金志文", + "v": "金志文演唱会超清" + }, + { + "n": "J焦迈奇", + "v": "焦迈奇演唱会超清" + }, + { + "n": "K筷子兄弟", + "v": "筷子兄弟演唱会超清" + }, + { + "n": "L李玟", + "v": "李玟演唱会超清" + }, + { + "n": "L林忆莲", + "v": "林忆莲演唱会超清" + }, + { + "n": "L李克勤", + "v": "李克勤演唱会超清" + }, + { + "n": "L刘宪华", + "v": "刘宪华演唱会超清" + }, + { + "n": "L李圣杰", + "v": "李圣杰演唱会超清" + }, + { + "n": "L林宥嘉", + "v": "林宥嘉演唱会超清" + }, + { + "n": "L梁静茹", + "v": "梁静茹演唱会超清" + }, + { + "n": "L李健", + "v": "李健演唱会超清" + }, + { + "n": "L林俊杰", + "v": "林俊杰演唱会超清" + }, + { + "n": "L李玉刚", + "v": "李玉刚演唱会超清" + }, + { + "n": "L林志炫", + "v": "林志炫演唱会超清" + }, + { + "n": "L李荣浩", + "v": "李荣浩演唱会超清" + }, + { + "n": "L李宇春", + "v": "李宇春演唱会超清" + }, + { + "n": "L洛天依", + "v": "洛天依演唱会超清" + }, + { + "n": "L林子祥", + "v": "林子祥演唱会超清" + }, + { + "n": "L李宗盛", + "v": "李宗盛演唱会超清" + }, + { + "n": "L黎明", + "v": "黎明演唱会超清" + }, + { + "n": "L刘德华", + "v": "刘德华演唱会超清" + }, + { + "n": "L罗大佑", + "v": "罗大佑演唱会超清" + }, + { + "n": "L林肯公园", + "v": "林肯公园演唱会超清" + }, + { + "n": "LLadyGaga", + "v": "LadyGaga演唱会超清" + }, + { + "n": "L旅行团乐队", + "v": "旅行团乐队演唱会超清" + }, + { + "n": "M莫文蔚", + "v": "莫文蔚演唱会超清" + }, + { + "n": "M毛不易", + "v": "毛不易演唱会超清" + }, + { + "n": "M梅艳芳", + "v": "梅艳芳演唱会超清" + }, + { + "n": "M迈克尔杰克逊", + "v": "迈克尔杰克逊演唱会超清" + }, + { + "n": "N南拳妈妈", + "v": "南拳妈妈演唱会超清" + }, + { + "n": "P朴树", + "v": "朴树演唱会超清" + }, + { + "n": "Q齐秦", + "v": "齐秦演唱会超清" + }, + { + "n": "Q青鸟飞鱼", + "v": "青鸟飞鱼演唱会超清" + }, + { + "n": "R容祖儿", + "v": "容祖儿演唱会超清" + }, + { + "n": "R任贤齐", + "v": "任贤齐演唱会超清" + }, + { + "n": "S水木年华", + "v": "水木年华演唱会超清" + }, + { + "n": "S孙燕姿", + "v": "孙燕姿演唱会超清" + }, + { + "n": "S苏打绿", + "v": "苏打绿演唱会超清" + }, + { + "n": "SSHE", + "v": "SHE演唱会超清" + }, + { + "n": "S孙楠", + "v": "孙楠演唱会超清" + }, + { + "n": "T陶喆", + "v": "陶喆演唱会超清" + }, + { + "n": "T谭咏麟", + "v": "谭咏麟演唱会超清" + }, + { + "n": "T田馥甄", + "v": "田馥甄演唱会超清" + }, + { + "n": "T谭维维", + "v": "谭维维演唱会超清" + }, + { + "n": "T逃跑计划", + "v": "逃跑计划演唱会超清" + }, + { + "n": "T田震", + "v": "田震演唱会超清" + }, + { + "n": "T谭晶", + "v": "谭晶演唱会超清" + }, + { + "n": "T屠洪刚", + "v": "屠洪刚演唱会超清" + }, + { + "n": "T泰勒·斯威夫特", + "v": "泰勒·斯威夫特演唱会超清" + }, + { + "n": "W王力宏", + "v": "王力宏演唱会超清" + }, + { + "n": "W王杰", + "v": "王杰演唱会超清" + }, + { + "n": "W吴克群", + "v": "吴克群演唱会超清" + }, + { + "n": "W王心凌", + "v": "王心凌演唱会超清" + }, + { + "n": "W王靖雯", + "v": "好声音王靖雯演唱会超清" + }, + { + "n": "W汪峰", + "v": "汪峰演唱会超清" + }, + { + "n": "W伍佰", + "v": "伍佰演唱会超清" + }, + { + "n": "W王菲", + "v": "王菲演唱会超清" + }, + { + "n": "W五月天", + "v": "五月天演唱会超清" + }, + { + "n": "W汪苏泷", + "v": "汪苏泷演唱会超清" + }, + { + "n": "X徐佳莹", + "v": "徐佳莹演唱会超清" + }, + { + "n": "X弦子", + "v": "弦子演唱会超清" + }, + { + "n": "X萧亚轩", + "v": "萧亚轩演唱会超清" + }, + { + "n": "X许巍", + "v": "许巍演唱会超清" + }, + { + "n": "X薛之谦", + "v": "薛之谦演唱会超清" + }, + { + "n": "X许嵩", + "v": "许嵩演唱会超清" + }, + { + "n": "X小虎队", + "v": "小虎队演唱会超清" + }, + { + "n": "X萧敬腾", + "v": "萧敬腾演唱会超清" + }, + { + "n": "X谢霆锋", + "v": "谢霆锋演唱会超清" + }, + { + "n": "X徐小凤", + "v": "徐小凤演唱会超清" + }, + { + "n": "X信乐队", + "v": "信乐队演唱会超清" + }, + { + "n": "Y夜愿乐队", + "v": "夜愿乐队演唱会超清" + }, + { + "n": "Y羽泉", + "v": "羽泉演唱会超清" + }, + { + "n": "Y郁可唯", + "v": "郁可唯演唱会超清" + }, + { + "n": "Y叶倩文", + "v": "叶倩文演唱会超清" + }, + { + "n": "Y杨坤", + "v": "杨坤演唱会超清" + }, + { + "n": "Y庾澄庆", + "v": "庾澄庆演唱会超清" + }, + { + "n": "Y尤长靖", + "v": "尤长靖演唱会超清" + }, + { + "n": "Y易烊千玺", + "v": "易烊千玺演唱会超清" + }, + { + "n": "Y袁娅维", + "v": "袁娅维演唱会超清" + }, + { + "n": "Y杨丞琳", + "v": "杨丞琳演唱会超清" + }, + { + "n": "Y杨千嬅", + "v": "杨千嬅演唱会超清" + }, + { + "n": "Y杨宗纬", + "v": "杨宗纬演唱会超清" + }, + { + "n": "Z郑秀文", + "v": "郑秀文演唱会超清" + }, + { + "n": "Z周杰伦", + "v": "周杰伦演唱会超清" + }, + { + "n": "Z张学友", + "v": "张学友演唱会超清" + }, + { + "n": "Z张信哲", + "v": "张信哲演唱会超清" + }, + { + "n": "Z张宇", + "v": "张宇演唱会超清" + }, + { + "n": "Z周华健", + "v": "周华健演唱会超清" + }, + { + "n": "Z张韶涵", + "v": "张韶涵演唱会超清" + }, + { + "n": "Z周深", + "v": "周深演唱会超清" + }, + { + "n": "Z纵贯线", + "v": "纵贯线演唱会超清" + }, + { + "n": "Z赵雷", + "v": "赵雷演唱会超清" + }, + { + "n": "Z周传雄", + "v": "周传雄演唱会超清" + }, + { + "n": "Z张国荣", + "v": "张国荣演唱会超清" + }, + { + "n": "Z周慧敏", + "v": "周慧敏演唱会超清" + }, + { + "n": "Z张惠妹", + "v": "张惠妹演唱会超清" + }, + { + "n": "Z周笔畅", + "v": "周笔畅演唱会超清" + }, + { + "n": "Z郑中基", + "v": "郑中基演唱会超清" + }, + { + "n": "Z张艺兴", + "v": "张艺兴演唱会超清" + }, + { + "n": "Z张震岳", + "v": "张震岳演唱会超清" + }, + { + "n": "Z张雨生", + "v": "张雨生演唱会超清" + }, + { + "n": "Z郑智化", + "v": "郑智化演唱会超清" + }, + { + "n": "Z卓依婷", + "v": "卓依婷演唱会超清" + }, + { + "n": "Z中岛美雪", + "v": "中岛美雪演唱会超清" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "探索发现超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "电影": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "鬼畜": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "沙雕动画": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "沙雕动画" + }, + { + "n": "虾仁动画", + "v": "虾仁动画" + }, + { + "n": "沙雕穿越", + "v": "沙雕穿越" + }, + { + "n": "中国动漫", + "v": "中国动漫" + }, + { + "n": "欧美动漫", + "v": "欧美动漫" + }, + { + "n": "动漫电影", + "v": "动漫电影" + }, + { + "n": "日本动漫", + "v": "日本动漫" + }, + { + "n": "其他动漫", + "v": "其他动漫" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "幼儿教育": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "幼儿教育", + "v": "幼儿教育" + }, + { + "n": "三字经", + "v": "三字经" + }, + { + "n": "百家姓", + "v": "百家姓" + }, + { + "n": "弟子规", + "v": "弟子规" + }, + { + "n": "声律启蒙", + "v": "声律启蒙" + }, + { + "n": "笠翁对韵", + "v": "笠翁对韵" + }, + { + "n": "睡前故事", + "v": "睡前故事" + }, + { + "n": "宝宝巴士", + "v": "宝宝巴士" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "说案": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "说案" + }, + { + "n": "汤圆", + "v": "汤圆说案" + }, + { + "n": "唐唐", + "v": "唐唐说案" + }, + { + "n": "罗翔", + "v": "罗翔说刑法" + }, + { + "n": "何家弘", + "v": "何家弘说案" + }, + { + "n": "韩诺", + "v": "韩诺说案" + }, + { + "n": "老V", + "v": "老V说案" + }, + { + "n": "禁播档案‼️", + "v": "禁播档案" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "音乐超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "音乐超清" + }, + { + "n": "抖音音乐", + "v": "抖音音乐MV" + }, + { + "n": "快手音乐", + "v": "快手音乐MV" + }, + { + "n": "酷狗音乐", + "v": "酷狗音乐MV" + }, + { + "n": "酷我音乐", + "v": "酷我音乐MV" + }, + { + "n": "QQ音乐", + "v": "QQ音乐MV" + }, + { + "n": "无损音乐", + "v": "无损音乐" + }, + { + "n": "钢琴曲", + "v": "钢琴曲" + }, + { + "n": "萨克斯", + "v": "萨克斯" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + + "中小学教育": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "中小学教育" + }, + { + "n": "小学教育", + "v": "小学教育" + }, + { + "n": "初中教育", + "v": "初中教育" + }, + { + "n": "高中教育", + "v": "高中教育" + }, + { + "n": "幼儿教育", + "v": "幼儿教育" + }, + { + "n": "诗词", + "v": "古代诗词" + }, + { + "n": "小说", + "v": "小说解说" + }, + { + "n": "电脑学习", + "v": "电脑学习" + }, + { + "n": "程序设计", + "v": "程序设计" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "演讲": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "全部演讲4K" + }, + { + "n": "A艾跃进", + "v": "艾跃进演讲4K" + }, + { + "n": "C超级演说家", + "v": "超级演说家4K" + }, + { + "n": "D电影", + "v": "电影演讲4K" + }, + { + "n": "D典籍里的中国", + "v": "典籍里的中国4K" + }, + { + "n": "G感动中国", + "v": "感动中国4K" + }, + { + "n": "G郭继承", + "v": "郭继承演讲4K" + }, + { + "n": "H华春莹", + "v": "华春莹演讲4K" + }, + { + "n": "L雷军", + "v": "雷军演讲4K" + }, + { + "n": "L罗翔", + "v": "罗翔演讲4K" + }, + { + "n": "R任正非", + "v": "任正非演讲4K" + }, + { + "n": "TED", + "v": "TED演讲4K" + }, + { + "n": "W汪文斌", + "v": "汪文斌演讲4K" + }, + { + "n": "Y一刻", + "v": "一刻演讲4K" + }, + { + "n": "Z赵立坚", + "v": "赵立坚演讲4K" + }, + { + "n": "Z郑强", + "v": "郑强演讲4K" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "解说": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "解说" + }, + { + "n": "电影", + "v": "电影解说" + }, + { + "n": "电视", + "v": "电视解说" + }, + { + "n": "历史", + "v": "历史解说" + }, + { + "n": "动漫", + "v": "动漫解说" + }, + { + "n": "小说", + "v": "小说解说" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "风景4K": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "风景4K" + }, + { + "n": "A澳门", + "v": "澳门风景4K" + }, + { + "n": "A安徽", + "v": "安徽风景4K" + }, + { + "n": "B布达拉宫", + "v": "布达拉宫风景4K" + }, + { + "n": "B北京", + "v": "北京风景4K" + }, + { + "n": "C重庆", + "v": "重庆风景4K" + }, + { + "n": "C草原", + "v": "草原风景4K" + }, + { + "n": "D大海", + "v": "大海风景4K" + }, + { + "n": "F福建", + "v": "福建风景4K" + }, + { + "n": "G广东", + "v": "广东风景4K" + }, + { + "n": "G广西", + "v": "广西风景4K" + }, + { + "n": "G贵州", + "v": "贵州风景4K" + }, + { + "n": "G甘肃", + "v": "甘肃风景4K" + }, + { + "n": "H海南", + "v": "海南风景4K" + }, + { + "n": "H河北", + "v": "河北风景4K" + }, + { + "n": "H河南", + "v": "河南风景4K" + }, + { + "n": "H湖北", + "v": "湖北风景4K" + }, + { + "n": "H湖南", + "v": "湖南风景4K" + }, + { + "n": "H黑龙江", + "v": "黑龙江风景4K" + }, + { + "n": "J吉林", + "v": "吉林风景4K" + }, + { + "n": "J江苏", + "v": "江苏风景4K" + }, + { + "n": "J江西", + "v": "江西风景4K" + }, + { + "n": "L辽宁", + "v": "辽宁风景4K" + }, + { + "n": "M民宿", + "v": "民宿风景4K" + }, + { + "n": "N内蒙古", + "v": "内蒙古风景4K" + }, + { + "n": "N宁夏", + "v": "宁夏风景4K" + }, + { + "n": "Q青海", + "v": "青海风景4K" + }, + { + "n": "S上海", + "v": "上海风景4K" + }, + { + "n": "S陕西", + "v": "陕西风景4K" + }, + { + "n": "S四川", + "v": "四川风景4K" + }, + { + "n": "S山西", + "v": "山西风景4K" + }, + { + "n": "S山东", + "v": "山东风景4K" + }, + { + "n": "T天津", + "v": "天津风景4K" + }, + { + "n": "T台湾", + "v": "台湾风景4K" + }, + { + "n": "T天空", + "v": "天空风景4K" + }, + { + "n": "X西湖", + "v": "西湖风景4K" + }, + { + "n": "X西藏", + "v": "西藏风景4K" + }, + { + "n": "X新疆", + "v": "新疆风景4K" + }, + { + "n": "X香港", + "v": "香港风景4K" + }, + { + "n": "Y云南", + "v": "云南风景4K" + }, + { + "n": "Z浙江", + "v": "浙江风景4K" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "MV4K": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "MV4K" + }, + { + "n": "A阿杜", + "v": "阿杜MV4K" + }, + { + "n": "A阿黛尔", + "v": "阿黛尔MV4K" + }, + { + "n": "BBeyond", + "v": "BeyondMV4K" + }, + { + "n": "BBy2", + "v": "By2MV4K" + }, + { + "n": "BBIGBANG", + "v": "BIGBANGMV4K" + }, + { + "n": "B布兰妮", + "v": "布兰妮MV4K" + }, + { + "n": "C陈奕迅", + "v": "陈奕迅MV4K" + }, + { + "n": "C蔡依林", + "v": "蔡依林MV4K" + }, + { + "n": "C初音未来", + "v": "初音未来MV4K" + }, + { + "n": "C蔡健雅", + "v": "蔡健雅MV4K" + }, + { + "n": "C陈小春", + "v": "陈小春MV4K" + }, + { + "n": "C草蜢", + "v": "草蜢MV4K" + }, + { + "n": "C陈慧娴", + "v": "陈慧娴MV4K" + }, + { + "n": "C崔健", + "v": "崔健MV4K" + }, + { + "n": "C仓木麻衣", + "v": "仓木麻衣MV4K" + }, + { + "n": "D戴荃", + "v": "戴荃MV4K" + }, + { + "n": "D动力火车", + "v": "动力火车MV4K" + }, + { + "n": "D邓丽君", + "v": "邓丽君MV4K" + }, + { + "n": "D丁当", + "v": "丁当MV4K" + }, + { + "n": "D刀郎", + "v": "刀郎MV4K" + }, + { + "n": "D邓紫棋", + "v": "邓紫棋MV4K" + }, + { + "n": "D戴佩妮", + "v": "戴佩妮MV4K" + }, + { + "n": "D邓丽君", + "v": "邓丽君MV4K" + }, + { + "n": "F飞儿乐队", + "v": "飞儿乐队MV4K" + }, + { + "n": "F费玉清", + "v": "费玉清MV4K" + }, + { + "n": "F费翔", + "v": "费翔MV4K" + }, + { + "n": "F方大同", + "v": "方大同MV4K" + }, + { + "n": "F房东的猫", + "v": "房东的猫MV4K" + }, + { + "n": "F凤飞飞", + "v": "凤飞飞MV4K" + }, + { + "n": "F凤凰传奇", + "v": "凤凰传奇MV4K" + }, + { + "n": "G古风歌曲", + "v": "古风歌曲4K" + }, + { + "n": "G国乐大典", + "v": "国乐大典4K" + }, + { + "n": "G郭采洁", + "v": "郭采洁MV4K" + }, + { + "n": "G光良", + "v": "光良MV4K" + }, + { + "n": "G郭静", + "v": "郭静MV4K" + }, + { + "n": "G郭富城", + "v": "郭富城MV4K" + }, + { + "n": "H胡彦斌", + "v": "胡彦斌MV4K" + }, + { + "n": "H胡夏", + "v": "胡夏MV4K" + }, + { + "n": "H韩红", + "v": "韩红MV4K" + }, + { + "n": "H黄品源", + "v": "黄品源MV4K" + }, + { + "n": "H黄小琥", + "v": "黄小琥MV4K" + }, + { + "n": "H花儿乐队", + "v": "花儿乐队MV4K" + }, + { + "n": "H黄家强", + "v": "黄家强MV4K" + }, + { + "n": "H后街男孩", + "v": "后街男孩MV4K" + }, + { + "n": "J经典老歌", + "v": "经典老歌4K" + }, + { + "n": "J贾斯丁比伯", + "v": "贾斯丁比伯MV4K" + }, + { + "n": "J金池", + "v": "金池MV4K" + }, + { + "n": "J金志文", + "v": "金志文MV4K" + }, + { + "n": "J焦迈奇", + "v": "焦迈奇MV4K" + }, + { + "n": "K筷子兄弟", + "v": "筷子兄弟MV4K" + }, + { + "n": "L李玟", + "v": "李玟MV4K" + }, + { + "n": "L林忆莲", + "v": "林忆莲MV4K" + }, + { + "n": "L李克勤", + "v": "李克勤MV4K" + }, + { + "n": "L刘宪华", + "v": "刘宪华MV4K" + }, + { + "n": "L李圣杰", + "v": "李圣杰MV4K" + }, + { + "n": "L林宥嘉", + "v": "林宥嘉MV4K" + }, + { + "n": "L梁静茹", + "v": "梁静茹MV4K" + }, + { + "n": "L李健", + "v": "李健MV4K" + }, + { + "n": "L林俊杰", + "v": "林俊杰MV4K" + }, + { + "n": "L李玉刚", + "v": "李玉刚MV4K" + }, + { + "n": "L林志炫", + "v": "林志炫MV4K" + }, + { + "n": "L李荣浩", + "v": "李荣浩MV4K" + }, + { + "n": "L李宇春", + "v": "李宇春MV4K" + }, + { + "n": "L洛天依", + "v": "洛天依MV4K" + }, + { + "n": "L林子祥", + "v": "林子祥MV4K" + }, + { + "n": "L李宗盛", + "v": "李宗盛MV4K" + }, + { + "n": "L黎明", + "v": "黎明MV4K" + }, + { + "n": "L刘德华", + "v": "刘德华MV4K" + }, + { + "n": "L罗大佑", + "v": "罗大佑MV4K" + }, + { + "n": "L林肯公园", + "v": "林肯公园MV4K" + }, + { + "n": "LLadyGaga", + "v": "LadyGagaMV4K" + }, + { + "n": "L旅行团乐队", + "v": "旅行团乐队MV4K" + }, + { + "n": "M莫文蔚", + "v": "莫文蔚MV4K" + }, + { + "n": "M毛不易", + "v": "毛不易MV4K" + }, + { + "n": "M梅艳芳", + "v": "梅艳芳MV4K" + }, + { + "n": "M迈克尔杰克逊", + "v": "迈克尔杰克逊MV4K" + }, + { + "n": "N南拳妈妈", + "v": "南拳妈妈MV4K" + }, + { + "n": "P朴树", + "v": "朴树MV4K" + }, + { + "n": "Q齐秦", + "v": "齐秦MV4K" + }, + { + "n": "Q青鸟飞鱼", + "v": "青鸟飞鱼MV4K" + }, + { + "n": "R容祖儿", + "v": "容祖儿MV4K" + }, + { + "n": "R热歌", + "v": "热歌MV4K" + }, + { + "n": "R任贤齐", + "v": "任贤齐MV4K" + }, + { + "n": "S水木年华", + "v": "水木年华MV4K" + }, + { + "n": "S孙燕姿", + "v": "孙燕姿MV4K" + }, + { + "n": "S苏打绿", + "v": "苏打绿MV4K" + }, + { + "n": "SSHE", + "v": "SHEMV4K" + }, + { + "n": "S孙楠", + "v": "孙楠MV4K" + }, + { + "n": "T陶喆", + "v": "陶喆MV4K" + }, + { + "n": "T谭咏麟", + "v": "谭咏麟MV4K" + }, + { + "n": "T田馥甄", + "v": "田馥甄MV4K" + }, + { + "n": "T谭维维", + "v": "谭维维MV4K" + }, + { + "n": "T逃跑计划", + "v": "逃跑计划MV4K" + }, + { + "n": "T田震", + "v": "田震MV4K" + }, + { + "n": "T谭晶", + "v": "谭晶MV4K" + }, + { + "n": "T屠洪刚", + "v": "屠洪刚MV4K" + }, + { + "n": "T泰勒·斯威夫特", + "v": "泰勒·斯威夫特MV4K" + }, + { + "n": "W王力宏", + "v": "王力宏MV4K" + }, + { + "n": "W王杰", + "v": "王杰MV4K" + }, + { + "n": "W吴克群", + "v": "吴克群MV4K" + }, + { + "n": "W王心凌", + "v": "王心凌MV4K" + }, + { + "n": "W汪峰", + "v": "汪峰MV4K" + }, + { + "n": "W伍佰", + "v": "伍佰MV4K" + }, + { + "n": "W王菲", + "v": "王菲MV4K" + }, + { + "n": "W五月天", + "v": "五月天MV4K" + }, + { + "n": "W汪苏泷", + "v": "汪苏泷MV4K" + }, + { + "n": "X徐佳莹", + "v": "徐佳莹MV4K" + }, + { + "n": "X弦子", + "v": "弦子MV4K" + }, + { + "n": "X萧亚轩", + "v": "萧亚轩MV4K" + }, + { + "n": "X许巍", + "v": "许巍MV4K" + }, + { + "n": "X薛之谦", + "v": "薛之谦MV4K" + }, + { + "n": "X许嵩", + "v": "许嵩MV4K" + }, + { + "n": "X小虎队", + "v": "小虎队MV4K" + }, + { + "n": "X萧敬腾", + "v": "萧敬腾MV4K" + }, + { + "n": "X谢霆锋", + "v": "谢霆锋MV4K" + }, + { + "n": "X徐小凤", + "v": "徐小凤MV4K" + }, + { + "n": "X信乐队", + "v": "信乐队MV4K" + }, + { + "n": "Y夜愿乐队", + "v": "夜愿乐队MV4K" + }, + { + "n": "Y原创音乐", + "v": "原创音乐MV4K" + }, + { + "n": "Y羽泉", + "v": "羽泉MV4K" + }, + { + "n": "Y粤语", + "v": "粤语MV4K" + }, + { + "n": "Y郁可唯", + "v": "郁可唯MV4K" + }, + { + "n": "Y叶倩文", + "v": "叶倩文MV4K" + }, + { + "n": "Y杨坤", + "v": "杨坤MV4K" + }, + { + "n": "Y庾澄庆", + "v": "庾澄庆MV4K" + }, + { + "n": "Y尤长靖", + "v": "尤长靖MV4K" + }, + { + "n": "Y易烊千玺", + "v": "易烊千玺MV4K" + }, + { + "n": "Y袁娅维", + "v": "袁娅维MV4K" + }, + { + "n": "Y杨丞琳", + "v": "杨丞琳MV4K" + }, + { + "n": "Y杨千嬅", + "v": "杨千嬅MV4K" + }, + { + "n": "Y杨宗纬", + "v": "杨宗纬MV4K" + }, + { + "n": "Z周杰伦", + "v": "周杰伦MV4K" + }, + { + "n": "Z张学友", + "v": "张学友MV4K" + }, + { + "n": "Z张信哲", + "v": "张信哲MV4K" + }, + { + "n": "Z张宇", + "v": "张宇MV4K" + }, + { + "n": "Z周华健", + "v": "周华健MV4K" + }, + { + "n": "Z张韶涵", + "v": "张韶涵MV4K" + }, + { + "n": "Z周深", + "v": "周深MV4K" + }, + { + "n": "Z纵贯线", + "v": "纵贯线MV4K" + }, + { + "n": "Z赵雷", + "v": "赵雷MV4K" + }, + { + "n": "Z周传雄", + "v": "周传雄MV4K" + }, + { + "n": "Z张国荣", + "v": "张国荣MV4K" + }, + { + "n": "Z周慧敏", + "v": "周慧敏MV4K" + }, + { + "n": "Z张惠妹", + "v": "张惠妹MV4K" + }, + { + "n": "Z周笔畅", + "v": "周笔畅MV4K" + }, + { + "n": "Z郑中基", + "v": "郑中基MV4K" + }, + { + "n": "Z张艺兴", + "v": "张艺兴MV4K" + }, + { + "n": "Z张震岳", + "v": "张震岳MV4K" + }, + { + "n": "Z中国好声音", + "v": "中国好声音MV4K" + }, + { + "n": "Z张雨生", + "v": "张雨生MV4K" + }, + { + "n": "Z郑智化", + "v": "郑智化MV4K" + }, + { + "n": "Z卓依婷", + "v": "卓依婷MV4K" + }, + { + "n": "Z中岛美雪", + "v": "中岛美雪MV4K" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "帕梅拉": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "帕梅拉" + }, + { + "n": "瘦腿", + "v": "帕梅拉瘦腿" + }, + { + "n": "腹部", + "v": "帕梅拉腹部" + }, + { + "n": "手臂", + "v": "帕梅拉手臂" + }, + { + "n": "热身", + "v": "帕梅拉热身" + }, + { + "n": "舞蹈", + "v": "帕梅拉舞蹈" + }, + { + "n": "燃脂", + "v": "帕梅拉燃脂" + }, + { + "n": "有氧", + "v": "帕梅拉有氧" + }, + { + "n": "拉伸", + "v": "帕梅拉拉伸" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "知名UP主": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "知名UP主" + }, + { + "n": "菠萝赛东", + "v": "菠萝赛东" + }, + { + "n": "冯提莫", + "v": "冯提莫" + }, + { + "n": "林延秋", + "v": "林延秋" + }, + { + "n": "-LKs-", + "v": "-LKs-" + }, + { + "n": "小约翰可汗", + "v": "小约翰可汗" + }, + { + "n": "low馆长", + "v": "low馆长" + }, + { + "n": "自说自话的总裁", + "v": "自说自话的总裁" + }, + { + "n": "所长林超", + "v": "所长林超" + }, + { + "n": "世界未解之谜M", + "v": "世界未解之谜M" + }, + { + "n": "李永乐老师官方", + "v": "李永乐老师官方" + }, + { + "n": "罗兹", + "v": "罗兹" + }, + { + "n": "回到2049", + "v": "回到2049" + }, + { + "n": "二次元的中科院物理所", + "v": "二次元的中科院物理所" + }, + { + "n": "毕导THU", + "v": "毕导THU" + }, + { + "n": "罗翔讲刑法", + "v": "罗翔讲刑法" + }, + { + "n": "戴博士实验室", + "v": "戴博士实验室" + }, + { + "n": "芳斯塔芙", + "v": "芳斯塔芙" + }, + { + "n": "参赛者网", + "v": "参赛者网" + }, + { + "n": "三维地图看世界", + "v": "三维地图看世界" + }, + { + "n": "有机社会", + "v": "有机社会" + }, + { + "n": "乌鸦校尉CaptainWuya", + "v": "乌鸦校尉CaptainWuya" + }, + { + "n": "果壳", + "v": "果壳" + }, + { + "n": "严伯钧", + "v": "严伯钧" + }, + { + "n": "是你们的康康", + "v": "是你们的康康" + }, + { + "n": "老爸评测", + "v": "老爸评测" + }, + { + "n": "硬核的半佛仙人", + "v": "硬核的半佛仙人" + }, + { + "n": "盗月社食遇记", + "v": "盗月社食遇记" + }, + { + "n": "我是郭杰瑞", + "v": "我是郭杰瑞" + }, + { + "n": "无穷小亮的科普日常", + "v": "无穷小亮的科普日常" + }, + { + "n": "papi酱", + "v": "papi酱" + }, + { + "n": "老番茄", + "v": "老番茄" + }, + { + "n": "绵羊料理", + "v": "绵羊料理" + }, + { + "n": "老师好我叫何同学", + "v": "老师好我叫何同学" + }, + { + "n": "敬汉卿", + "v": "敬汉卿" + }, + { + "n": "周六野Zoey", + "v": "周六野Zoey" + }, + { + "n": "木鱼水心", + "v": "木鱼水心" + }, + { + "n": "凉风Kaze", + "v": "凉风Kaze" + }, + { + "n": "小潮院长", + "v": "小潮院长" + }, + { + "n": "中国BOY超级大猩猩", + "v": "中国BOY超级大猩猩" + }, + { + "n": "李子柒", + "v": "李子柒" + }, + { + "n": "敖厂长", + "v": "敖厂长" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "太极拳": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "太极拳" + }, + { + "n": "邱慧芳", + "v": "太极拳邱慧芳" + }, + { + "n": "陈氏", + "v": "太极拳陈氏" + }, + { + "n": "武当", + "v": "太极拳武当" + }, + { + "n": "二十四式", + "v": "太极拳二十四式" + }, + { + "n": "三十六式", + "v": "太极拳三十六式" + }, + { + "n": "五禽戏", + "v": "五禽戏" + }, + { + "n": "八段锦", + "v": "八段锦" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "舞蹈": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "舞蹈" + }, + { + "n": "宅舞", + "v": "宅舞" + }, + { + "n": "街舞", + "v": "街舞" + }, + { + "n": "中国舞", + "v": "中国舞" + }, + { + "n": "广场舞", + "v": "广场舞" + }, + { + "n": "交谊舞", + "v": "交谊舞" + }, + { + "n": "教程", + "v": "舞蹈教程" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "音乐": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "音乐" + }, + { + "n": "钢琴曲", + "v": "钢琴曲" + }, + { + "n": "协奏曲", + "v": "协奏曲r" + }, + { + "n": "中国古风音乐", + "v": "中国古风音乐" + }, + { + "n": "背景音乐", + "v": "背景音乐" + }, + { + "n": "助眠音乐r", + "v": "助眠音乐" + }, + { + "n": "胎教音乐", + "v": "胎教音乐" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "歌曲": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "歌曲" + }, + { + "n": "香港歌曲", + "v": "香港歌曲" + }, + { + "n": "台湾歌曲", + "v": "台湾歌曲" + }, + { + "n": "内地歌曲", + "v": "内地歌曲" + }, + { + "n": "英文歌曲", + "v": "英文歌曲" + }, + { + "n": "日文歌曲", + "v": "日文歌曲" + }, + { + "n": "小语种歌曲", + "v": "小语种歌曲" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "平面设计教学": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "平面设计教学" + }, + { + "n": "Adobe Photoshop", + "v": "Adobe Photoshop教程" + }, + { + "n": "Adobe Illustrator", + "v": "Adobe Illustrator教程" + }, + { + "n": "CorelDRAW", + "v": "CorelDRAW教程" + }, + { + "n": "Adobe InDesign", + "v": "Adobe InDesign教程" + }, + { + "n": "Adobe Pagermaker", + "v": "Adobe Pagermaker教程" + }, + { + "n": "SAI", + "v": "SAI教程" + }, + { + "n": "Adobe Bridge", + "v": "Adobe Bridge教程" + }, + { + "n": "Adobe Pagermaker", + "v": "Adobe Pagermake教程r" + }, + { + "n": "3D Studio Max", + "v": "3D Studio Max教程" + }, + { + "n": "PR", + "v": "PR教程" + }, + { + "n": "AE", + "v": "AE教程" + }, + { + "n": "CINEMA 4D", + "v": "CINEMA 4D教程" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "软件教程": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "软件教程" + }, + { + "n": "MT管理器", + "v": "MT管理器" + }, + { + "n": "NP管理器", + "v": "NP管理器" + }, + { + "n": "mixplorer", + "v": "mixplorer" + }, + { + "n": "脱壳", + "v": "脱壳" + }, + { + "n": "爬虫", + "v": "爬虫" + }, + { + "n": "json&jar", + "v": "json&jar" + }, + { + "n": "网盘挂载", + "v": "网盘挂载" + }, + { + "n": "alist+WebDav", + "v": "alist+WebDav" + }, + { + "n": "TVBox修改", + "v": "TVBox修改教程" + }, + { + "n": "EXCEL", + "v": "EXCEL教程" + }, + { + "n": "Git入门到精通", + "v": "Git入门到精通" + }, + { + "n": "java", + "v": "java教程" + }, + { + "n": "phyton", + "v": "phyton教程" + }, + { + "n": "xml", + "v": "xml教程" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "Windows": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "小姐姐超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "广场舞超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "舞曲超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "白噪音超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "搞笑超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "体育超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "4K": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "足球比赛合集超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "篮球超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "动物世界超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "荒野求生超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "纪录片超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "中文", + "value": [ + { + "n": "地区🎶排序", + "v": "历史记录片 地球记录片 宇宙记录片 海洋记录片 战争记录片 大自然生存记录片" + }, + { + "n": "默认", + "v": "PLdocumentary" + }, + { + "n": "CCTV纪录片", + "v": "PLCCTV 纪录片" + }, + { + "n": "BBC纪录片", + "v": "PLBBC 纪录片" + }, + { + "n": "国家地理", + "v": "PL国家地理 纪录片" + }, + { + "n": "Netflix纪录片", + "v": "PLnetflix 纪录片" + }, + { + "n": "BBC", + "v": "PLBBC documentary" + }, + { + "n": "National Geographic", + "v": "PLNational Geographic documentary" + }, + { + "n": "Netflix", + "v": "PLnetflix documentary" + }, + { + "n": "历史", + "v": "PL历史 纪录片" + }, + { + "n": "野性", + "v": "PL野性 纪录片" + }, + { + "n": "地球", + "v": "PL地球 纪录片" + }, + { + "n": "宇宙", + "v": "PL宇宙 纪录片" + }, + { + "n": "海洋", + "v": "PL海洋 纪录片" + }, + { + "n": "人文", + "v": "PL人文 纪录片" + }, + { + "n": "战争", + "v": "PL战争 纪录片" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "食谱": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "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": "苏菜食谱" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "健身": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "健身" + }, + { + "n": "瘦腿", + "v": "瘦腿" + }, + { + "n": "腹部", + "v": "腹部" + }, + { + "n": "手臂", + "v": "手臂" + }, + { + "n": "热身", + "v": "热身" + }, + { + "n": "帕梅拉", + "v": "帕梅拉" + }, + { + "n": "燃脂", + "v": "燃脂" + }, + { + "n": "有氧", + "v": "有氧" + }, + { + "n": "拉伸", + "v": "拉伸" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "窗白噪音": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "美食超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "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": "闽菜美食超清" + }, + { + "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": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "广场舞": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "球星": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "球星" + }, + { + "n": "梅西", + "v": "梅西" + }, + { + "n": "C罗", + "v": "C罗" + }, + { + "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": "NBA", + "v": "NBA" + }, + { + "n": "詹姆斯", + "v": "詹姆斯" + }, + { + "n": "库里", + "v": "库里" + }, + { + "n": "杜兰特", + "v": "杜兰特" + }, + { + "n": "UFC", + "v": "UFC" + }, + { + "n": "斯诺克", + "v": "斯诺克" + }, + { + "n": "网球", + "v": "网球" + }, + { + "n": "F1", + "v": "F1" + }, + { + "n": "高尔夫", + "v": "高尔夫" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "电视剧": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "相声小品超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "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": "喜剧综艺" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "戏曲": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "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": "婺剧" + }, + { + "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": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "旅游": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "游泳": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "泳姿" + }, + { + "n": "蝶泳", + "v": "蝶泳" + }, + { + "n": "仰泳", + "v": "仰泳" + }, + { + "n": "蛙泳", + "v": "蛙泳" + }, + { + "n": "自由泳", + "v": "自由泳" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/config/blts.json b/lrzy/config/blts.json new file mode 100644 index 0000000..4a5b5eb --- /dev/null +++ b/lrzy/config/blts.json @@ -0,0 +1,52 @@ +{ + "class": [ + { + "type_name": "有声小说", + "type_id": "有声小说" + }, + { + "type_name": "玄幻有声小说", + "type_id": "玄幻有声小说" + }, + { + "type_name": "奇幻有声小说", + "type_id": "奇幻有声小说" + }, + { + "type_name": "都市有声小说", + "type_id": "都市有声小说" + }, + { + "type_name": "言情有声小说", + "type_id": "言情有声小说" + }, + { + "type_name": "武侠有声小说", + "type_id": "武侠有声小说" + }, + { + "type_name": "仙侠有声小说", + "type_id": "仙侠有声小说" + }, + { + "type_name": "科幻有声小说", + "type_id": "科幻有声小说" + }, + { + "type_name": "重生有声小说", + "type_id": "重生有声小说" + }, + { + "type_name": "穿越有声小说", + "type_id": "穿越有声小说" + }, + { + "type_name": "恐怖惊悚有声小说", + "type_id": "恐怖惊悚有声小说" + }, + { + "type_name": "网游竞技有声小说", + "type_id": "网游竞技有声小说" + } + ] +} \ No newline at end of file diff --git a/lrzy/config/blxp.json b/lrzy/config/blxp.json new file mode 100644 index 0000000..9ebaf36 --- /dev/null +++ b/lrzy/config/blxp.json @@ -0,0 +1,52 @@ +{ + "class": [ + { + "type_name": "春晚小品", + "type_id": "春晚小品" + }, + { + "type_name": "赵本山", + "type_id": "赵本山" + }, + { + "type_name": "陈佩斯", + "type_id": "陈佩斯" + }, + { + "type_name": "冯巩", + "type_id": "冯巩" + }, + { + "type_name": "宋小宝", + "type_id": "宋小宝" + }, + { + "type_name": "赵丽蓉", + "type_id": "赵丽蓉" + }, + { + "type_name": "郭达", + "type_id": "郭达" + }, + { + "type_name": "潘长江", + "type_id": "潘长江" + }, + { + "type_name": "郭冬临", + "type_id": "郭冬临" + }, + { + "type_name": "严顺开", + "type_id": "严顺开" + }, + { + "type_name": "文松", + "type_id": "文松" + }, + { + "type_name": "开心麻花", + "type_id": "开心麻花" + } + ] +} \ No newline at end of file diff --git a/lrzy/config/blxq.json b/lrzy/config/blxq.json new file mode 100644 index 0000000..2fb33f0 --- /dev/null +++ b/lrzy/config/blxq.json @@ -0,0 +1,200 @@ +{ + "class": [ + { + "type_name": "潮剧", + "type_id": "潮剧" + }, + { + "type_name": "粤剧", + "type_id": "粤剧" + }, + { + "type_name": "京剧", + "type_id": "京剧" + }, + { + "type_name": "越剧", + "type_id": "越剧" + }, + { + "type_name": "芗剧", + "type_id": "芗剧" + }, + { + "type_name": "蒲剧", + "type_id": "蒲剧" + }, + { + "type_name": "闽剧", + "type_id": "闽剧" + }, + { + "type_name": "喊麦", + "type_id": "喊麦" + }, + { + "type_name": "陕北说书", + "type_id": "陕北说书" + }, + { + "type_name": "庐剧", + "type_id": "庐剧" + }, + { + "type_name": "吕剧", + "type_id": "吕剧" + }, + { + "type_name": "眉户", + "type_id": "眉户" + }, + { + "type_name": "歌仔戏", + "type_id": "歌仔戏" + }, + { + "type_name": "黄梅戏", + "type_id": "黄梅戏" + }, + { + "type_name": "黄梅戏", + "type_id": "黄梅戏" + }, + { + "type_name": "评剧", + "type_id": "评剧" + }, + { + "type_name": "豫剧", + "type_id": "豫剧" + }, + { + "type_name": "沪剧", + "type_id": "沪剧" + }, + { + "type_name": "昆曲", + "type_id": "昆曲" + }, + { + "type_name": "花鼓戏", + "type_id": "花鼓戏" + }, + { + "type_name": "超清潮剧", + "type_id": "超清潮剧" + }, + { + "type_name": "百花潮剧院", + "type_id": "百花潮剧院" + }, + { + "type_name": "香港潮剧", + "type_id": "香港潮剧" + }, + { + "type_name": "潮剧院", + "type_id": "潮剧院" + }, + { + "type_name": "潮剧团", + "type_id": "潮剧团" + }, + { + "type_name": "潮剧全剧", + "type_id": "潮剧全剧" + }, + { + "type_name": "潮剧选段", + "type_id": "潮剧选段" + }, + { + "type_name": "名家潮剧", + "type_id": "名家潮剧" + }, + { + "type_name": "潮汕小品", + "type_id": "潮汕小品" + }, + { + "type_name": "潮汕讲古", + "type_id": "潮汕讲古" + }, + { + "type_name": "河北梆子", + "type_id": "河北梆子" + }, + { + "type_name": "梆子腔", + "type_id": "梆子腔" + }, + { + "type_name": "晋剧", + "type_id": "晋剧" + }, + { + "type_name": "龙江剧", + "type_id": "龙江剧" + }, + { + "type_name": "越调", + "type_id": "越调" + }, + { + "type_name": "河南曲剧", + "type_id": "河南曲剧" + }, + { + "type_name": "山东梆子", + "type_id": "山东梆子" + }, + { + "type_name": "淮剧", + "type_id": "淮剧" + }, + { + "type_name": "滑稽戏", + "type_id": "滑稽戏" + }, + { + "type_name": "婺剧", + "type_id": "婺剧" + }, + { + "type_name": "绍剧", + "type_id": "绍剧" + }, + { + "type_name": "徽剧", + "type_id": "徽剧" + }, + { + "type_name": "雁剧", + "type_id": "雁剧" + }, + { + "type_name": "上党梆子", + "type_id": "上党梆子" + }, + { + "type_name": "秦腔", + "type_id": "秦腔" + }, + { + "type_name": "武安平调", + "type_id": "武安平调" + }, + { + "type_name": "二人台", + "type_id": "二人台" + }, + { + "type_name": "吉剧", + "type_id": "吉剧" + }, + { + "type_name": "高腔", + "type_id": "高腔" + } + ] +} \ No newline at end of file diff --git a/lrzy/config/blxs.json b/lrzy/config/blxs.json new file mode 100644 index 0000000..bc8c218 --- /dev/null +++ b/lrzy/config/blxs.json @@ -0,0 +1,32 @@ +{ + "class": [ + { + "type_name": "单口相声", + "type_id": "单口相声" + }, + { + "type_name": "群口相声", + "type_id": "群口相声" + }, + { + "type_name": "德云社", + "type_id": "德云社" + }, + { + "type_name": "青曲社", + "type_id": "青曲社" + }, + { + "type_name": "郭德纲", + "type_id": "郭德纲" + }, + { + "type_name": "岳云鹏", + "type_id": "岳云鹏" + }, + { + "type_name": "曹云金", + "type_id": "曹云金" + } + ] +} \ No newline at end of file diff --git a/lrzy/config/blych.json b/lrzy/config/blych.json new file mode 100644 index 0000000..3a9b610 --- /dev/null +++ b/lrzy/config/blych.json @@ -0,0 +1,702 @@ +{ + "class": [ + { + "type_name": "演唱会筛选", + "type_id": "演唱会超清" + }, + { + "type_name": "粤语", + "type_id": "粤语歌曲超清" + }, + { + "type_name": "热榜", + "type_id": "2022年热们歌曲超清" + }, + { + "type_name": "抖音神曲", + "type_id": "抖音神曲超清" + }, + { + "type_name": "经典老歌", + "type_id": "经典老歌超清" + }, + { + "type_name": "DJ", + "type_id": "DJ歌曲超清" + }, + { + "type_name": "网红翻唱", + "type_id": "网红翻唱歌曲超清" + }, + { + "type_name": "韩国女团", + "type_id": "韩国女团演唱会超清" + } + ], + "filters": { + "演唱会超清": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "综合排序", + "v": "0" + }, + { + "n": "最多点击", + "v": "click" + }, + { + "n": "最新发布", + "v": "pubdate" + }, + { + "n": "最多弹幕", + "v": "dm" + }, + { + "n": "最多收藏", + "v": "stow" + } + ] + }, + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "演唱会超清" + }, + { + "n": "A阿杜", + "v": "阿杜演唱会超清" + }, + { + "n": "A阿黛尔", + "v": "阿黛尔演唱会超清" + }, + { + "n": "BBeyond", + "v": "Beyond演唱会超清" + }, + { + "n": "BBy2", + "v": "By2演唱会超清" + }, + { + "n": "BBIGBANG", + "v": "BIGBANG演唱会超清" + }, + { + "n": "B布兰妮", + "v": "布兰妮演唱会超清" + }, + { + "n": "B坂井泉水", + "v": "坂井泉水演唱会超清" + }, + { + "n": "C陈奕迅", + "v": "陈奕迅演唱会超清" + }, + { + "n": "C蔡依林", + "v": "蔡依林演唱会超清" + }, + { + "n": "C初音未来", + "v": "初音未来演唱会超清" + }, + { + "n": "C蔡健雅", + "v": "蔡健雅演唱会超清" + }, + { + "n": "C陈小春", + "v": "陈小春演唱会超清" + }, + { + "n": "C草蜢", + "v": "草蜢演唱会超清" + }, + { + "n": "C陈慧娴", + "v": "陈慧娴演唱会超清" + }, + { + "n": "C崔健", + "v": "崔健演唱会超清" + }, + { + "n": "C仓木麻衣", + "v": "仓木麻衣演唱会超清" + }, + { + "n": "D戴荃", + "v": "戴荃演唱会超清" + }, + { + "n": "D动力火车", + "v": "动力火车演唱会超清" + }, + { + "n": "D邓丽君", + "v": "邓丽君演唱会超清" + }, + { + "n": "D丁当", + "v": "丁当演唱会超清" + }, + { + "n": "D刀郎", + "v": "刀郎演唱会超清" + }, + { + "n": "D邓紫棋", + "v": "邓紫棋演唱会超清" + }, + { + "n": "D戴佩妮", + "v": "戴佩妮演唱会超清" + }, + { + "n": "D邓丽君", + "v": "邓丽君演唱会超清" + }, + { + "n": "F飞儿乐队", + "v": "飞儿乐队演唱会超清" + }, + { + "n": "F费玉清", + "v": "费玉清演唱会超清" + }, + { + "n": "F费翔", + "v": "费翔演唱会超清" + }, + { + "n": "F方大同", + "v": "方大同演唱会超清" + }, + { + "n": "F房东的猫", + "v": "房东的猫演唱会超清" + }, + { + "n": "F凤飞飞", + "v": "凤飞飞演唱会超清" + }, + { + "n": "F凤凰传奇", + "v": "凤凰传奇演唱会超清" + }, + { + "n": "G郭采洁", + "v": "郭采洁演唱会超清" + }, + { + "n": "G光良", + "v": "光良演唱会超清" + }, + { + "n": "G郭静", + "v": "郭静演唱会超清" + }, + { + "n": "G郭富城", + "v": "郭富城演唱会超清" + }, + { + "n": "H胡彦斌", + "v": "胡彦斌演唱会超清" + }, + { + "n": "H胡夏", + "v": "胡夏演唱会超清" + }, + { + "n": "H韩红", + "v": "韩红演唱会超清" + }, + { + "n": "H黄品源", + "v": "黄品源演唱会超清" + }, + { + "n": "H黄小琥", + "v": "黄小琥演唱会超清" + }, + { + "n": "H花儿乐队", + "v": "花儿乐队演唱会超清" + }, + { + "n": "H黄家强", + "v": "黄家强演唱会超清" + }, + { + "n": "H后街男孩", + "v": "后街男孩演唱会超清" + }, + { + "n": "J经典老歌", + "v": "经典老歌演唱会超清" + }, + { + "n": "J贾斯丁比伯", + "v": "贾斯丁比伯演唱会超清" + }, + { + "n": "J金池", + "v": "金池演唱会超清" + }, + { + "n": "J金志文", + "v": "金志文演唱会超清" + }, + { + "n": "J焦迈奇", + "v": "焦迈奇演唱会超清" + }, + { + "n": "K筷子兄弟", + "v": "筷子兄弟演唱会超清" + }, + { + "n": "L李玟", + "v": "李玟演唱会超清" + }, + { + "n": "L林忆莲", + "v": "林忆莲演唱会超清" + }, + { + "n": "L李克勤", + "v": "李克勤演唱会超清" + }, + { + "n": "L刘宪华", + "v": "刘宪华演唱会超清" + }, + { + "n": "L李圣杰", + "v": "李圣杰演唱会超清" + }, + { + "n": "L林宥嘉", + "v": "林宥嘉演唱会超清" + }, + { + "n": "L梁静茹", + "v": "梁静茹演唱会超清" + }, + { + "n": "L李健", + "v": "李健演唱会超清" + }, + { + "n": "L林俊杰", + "v": "林俊杰演唱会超清" + }, + { + "n": "L李玉刚", + "v": "李玉刚演唱会超清" + }, + { + "n": "L林志炫", + "v": "林志炫演唱会超清" + }, + { + "n": "L李荣浩", + "v": "李荣浩演唱会超清" + }, + { + "n": "L李宇春", + "v": "李宇春演唱会超清" + }, + { + "n": "L洛天依", + "v": "洛天依演唱会超清" + }, + { + "n": "L林子祥", + "v": "林子祥演唱会超清" + }, + { + "n": "L李宗盛", + "v": "李宗盛演唱会超清" + }, + { + "n": "L黎明", + "v": "黎明演唱会超清" + }, + { + "n": "L刘德华", + "v": "刘德华演唱会超清" + }, + { + "n": "L罗大佑", + "v": "罗大佑演唱会超清" + }, + { + "n": "L林肯公园", + "v": "林肯公园演唱会超清" + }, + { + "n": "LLadyGaga", + "v": "LadyGaga演唱会超清" + }, + { + "n": "L旅行团乐队", + "v": "旅行团乐队演唱会超清" + }, + { + "n": "M莫文蔚", + "v": "莫文蔚演唱会超清" + }, + { + "n": "M毛不易", + "v": "毛不易演唱会超清" + }, + { + "n": "M梅艳芳", + "v": "梅艳芳演唱会超清" + }, + { + "n": "M迈克尔杰克逊", + "v": "迈克尔杰克逊演唱会超清" + }, + { + "n": "N南拳妈妈", + "v": "南拳妈妈演唱会超清" + }, + { + "n": "P朴树", + "v": "朴树演唱会超清" + }, + { + "n": "Q齐秦", + "v": "齐秦演唱会超清" + }, + { + "n": "Q青鸟飞鱼", + "v": "青鸟飞鱼演唱会超清" + }, + { + "n": "R容祖儿", + "v": "容祖儿演唱会超清" + }, + { + "n": "R任贤齐", + "v": "任贤齐演唱会超清" + }, + { + "n": "S水木年华", + "v": "水木年华演唱会超清" + }, + { + "n": "S孙燕姿", + "v": "孙燕姿演唱会超清" + }, + { + "n": "S苏打绿", + "v": "苏打绿演唱会超清" + }, + { + "n": "SSHE", + "v": "SHE演唱会超清" + }, + { + "n": "S孙楠", + "v": "孙楠演唱会超清" + }, + { + "n": "T陶喆", + "v": "陶喆演唱会超清" + }, + { + "n": "T谭咏麟", + "v": "谭咏麟演唱会超清" + }, + { + "n": "T田馥甄", + "v": "田馥甄演唱会超清" + }, + { + "n": "T谭维维", + "v": "谭维维演唱会超清" + }, + { + "n": "T逃跑计划", + "v": "逃跑计划演唱会超清" + }, + { + "n": "T田震", + "v": "田震演唱会超清" + }, + { + "n": "T谭晶", + "v": "谭晶演唱会超清" + }, + { + "n": "T屠洪刚", + "v": "屠洪刚演唱会超清" + }, + { + "n": "T泰勒·斯威夫特", + "v": "泰勒·斯威夫特演唱会超清" + }, + { + "n": "W王力宏", + "v": "王力宏演唱会超清" + }, + { + "n": "W王杰", + "v": "王杰演唱会超清" + }, + { + "n": "W吴克群", + "v": "吴克群演唱会超清" + }, + { + "n": "W王心凌", + "v": "王心凌演唱会超清" + }, + { + "n": "W王靖雯", + "v": "好声音王靖雯演唱会超清" + }, + { + "n": "W汪峰", + "v": "汪峰演唱会超清" + }, + { + "n": "W伍佰", + "v": "伍佰演唱会超清" + }, + { + "n": "W王菲", + "v": "王菲演唱会超清" + }, + { + "n": "W五月天", + "v": "五月天演唱会超清" + }, + { + "n": "W汪苏泷", + "v": "汪苏泷演唱会超清" + }, + { + "n": "X徐佳莹", + "v": "徐佳莹演唱会超清" + }, + { + "n": "X弦子", + "v": "弦子演唱会超清" + }, + { + "n": "X萧亚轩", + "v": "萧亚轩演唱会超清" + }, + { + "n": "X许巍", + "v": "许巍演唱会超清" + }, + { + "n": "X薛之谦", + "v": "薛之谦演唱会超清" + }, + { + "n": "X许嵩", + "v": "许嵩演唱会超清" + }, + { + "n": "X小虎队", + "v": "小虎队演唱会超清" + }, + { + "n": "X萧敬腾", + "v": "萧敬腾演唱会超清" + }, + { + "n": "X谢霆锋", + "v": "谢霆锋演唱会超清" + }, + { + "n": "X徐小凤", + "v": "徐小凤演唱会超清" + }, + { + "n": "X信乐队", + "v": "信乐队演唱会超清" + }, + { + "n": "Y夜愿乐队", + "v": "夜愿乐队演唱会超清" + }, + { + "n": "Y羽泉", + "v": "羽泉演唱会超清" + }, + { + "n": "Y郁可唯", + "v": "郁可唯演唱会超清" + }, + { + "n": "Y叶倩文", + "v": "叶倩文演唱会超清" + }, + { + "n": "Y杨坤", + "v": "杨坤演唱会超清" + }, + { + "n": "Y庾澄庆", + "v": "庾澄庆演唱会超清" + }, + { + "n": "Y尤长靖", + "v": "尤长靖演唱会超清" + }, + { + "n": "Y易烊千玺", + "v": "易烊千玺演唱会超清" + }, + { + "n": "Y袁娅维", + "v": "袁娅维演唱会超清" + }, + { + "n": "Y杨丞琳", + "v": "杨丞琳演唱会超清" + }, + { + "n": "Y杨千嬅", + "v": "杨千嬅演唱会超清" + }, + { + "n": "Y杨宗纬", + "v": "杨宗纬演唱会超清" + }, + { + "n": "Z郑秀文", + "v": "郑秀文演唱会超清" + }, + { + "n": "Z周杰伦", + "v": "周杰伦演唱会超清" + }, + { + "n": "Z张学友", + "v": "张学友演唱会超清" + }, + { + "n": "Z张信哲", + "v": "张信哲演唱会超清" + }, + { + "n": "Z张宇", + "v": "张宇演唱会超清" + }, + { + "n": "Z周华健", + "v": "周华健演唱会超清" + }, + { + "n": "Z张韶涵", + "v": "张韶涵演唱会超清" + }, + { + "n": "Z周深", + "v": "周深演唱会超清" + }, + { + "n": "Z纵贯线", + "v": "纵贯线演唱会超清" + }, + { + "n": "Z赵雷", + "v": "赵雷演唱会超清" + }, + { + "n": "Z周传雄", + "v": "周传雄演唱会超清" + }, + { + "n": "Z张国荣", + "v": "张国荣演唱会超清" + }, + { + "n": "Z周慧敏", + "v": "周慧敏演唱会超清" + }, + { + "n": "Z张惠妹", + "v": "张惠妹演唱会超清" + }, + { + "n": "Z周笔畅", + "v": "周笔畅演唱会超清" + }, + { + "n": "Z郑中基", + "v": "郑中基演唱会超清" + }, + { + "n": "Z张艺兴", + "v": "张艺兴演唱会超清" + }, + { + "n": "Z张震岳", + "v": "张震岳演唱会超清" + }, + { + "n": "Z张雨生", + "v": "张雨生演唱会超清" + }, + { + "n": "Z郑智化", + "v": "郑智化演唱会超清" + }, + { + "n": "Z卓依婷", + "v": "卓依婷演唱会超清" + }, + { + "n": "Z中岛美雪", + "v": "中岛美雪演唱会超清" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/config/blys.json b/lrzy/config/blys.json new file mode 100644 index 0000000..15e2e8d --- /dev/null +++ b/lrzy/config/blys.json @@ -0,0 +1,379 @@ +{ + "class": [ + { + "type_name": "番剧", + "type_id": "1" + }, + { + "type_name": "国创", + "type_id": "4" + }, + { + "type_name": "电影", + "type_id": "2" + }, + + { + "type_name": "剧集", + "type_id": "5" + }, + { + "type_name": "综艺", + "type_id": "7" + }, + { + "type_name": "纪录", + "type_id": "3" + } + ], + "filters": { + "2": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "播放数量", + "v": "2" + }, + { + "n": "更新时间", + "v": "0" + }, + { + "n": "最高评分", + "v": "4" + }, + { + "n": "弹幕数量", + "v": "1" + }, + { + "n": "追看人数", + "v": "3" + }, + { + "n": "开播时间", + "v": "5" + }, + { + "n": "上映时间", + "v": "6" + } + ] + }, + { + "key": "season_status", + "name": "付费", + "value": [ + { + "n": "全部", + "v": "-1" + }, + { + "n": "免费", + "v": "1" + }, + { + "n": "付费", + "v": "2%2C6" + }, + { + "n": "大会员", + "v": "4%2C6" + } + ] + } + ], + "5": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "播放数量", + "v": "2" + }, + { + "n": "更新时间", + "v": "0" + }, + { + "n": "最高评分", + "v": "4" + }, + { + "n": "弹幕数量", + "v": "1" + }, + { + "n": "追看人数", + "v": "3" + }, + { + "n": "开播时间", + "v": "5" + }, + { + "n": "上映时间", + "v": "6" + } + ] + }, + { + "key": "season_status", + "name": "付费", + "value": [ + { + "n": "全部", + "v": "-1" + }, + { + "n": "免费", + "v": "1" + }, + { + "n": "付费", + "v": "2%2C6" + }, + { + "n": "大会员", + "v": "4%2C6" + } + ] + } + ], + "7": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "播放数量", + "v": "2" + }, + { + "n": "更新时间", + "v": "0" + }, + { + "n": "最高评分", + "v": "4" + }, + { + "n": "弹幕数量", + "v": "1" + }, + { + "n": "追看人数", + "v": "3" + }, + { + "n": "开播时间", + "v": "5" + }, + { + "n": "上映时间", + "v": "6" + } + ] + }, + { + "key": "season_status", + "name": "付费", + "value": [ + { + "n": "全部", + "v": "-1" + }, + { + "n": "免费", + "v": "1" + }, + { + "n": "付费", + "v": "2%2C6" + }, + { + "n": "大会员", + "v": "4%2C6" + } + ] + } + ], + "3": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "播放数量", + "v": "2" + }, + { + "n": "更新时间", + "v": "0" + }, + { + "n": "最高评分", + "v": "4" + }, + { + "n": "弹幕数量", + "v": "1" + }, + { + "n": "追看人数", + "v": "3" + }, + { + "n": "开播时间", + "v": "5" + }, + { + "n": "上映时间", + "v": "6" + } + ] + }, + { + "key": "season_status", + "name": "付费", + "value": [ + { + "n": "全部", + "v": "-1" + }, + { + "n": "免费", + "v": "1" + }, + { + "n": "付费", + "v": "2%2C6" + }, + { + "n": "大会员", + "v": "4%2C6" + } + ] + } + ], + "1": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "播放数量", + "v": "2" + }, + { + "n": "更新时间", + "v": "0" + }, + { + "n": "最高评分", + "v": "4" + }, + { + "n": "弹幕数量", + "v": "1" + }, + { + "n": "追看人数", + "v": "3" + }, + { + "n": "开播时间", + "v": "5" + }, + { + "n": "上映时间", + "v": "6" + } + ] + }, + { + "key": "season_status", + "name": "付费", + "value": [ + { + "n": "全部", + "v": "-1" + }, + { + "n": "免费", + "v": "1" + }, + { + "n": "付费", + "v": "2%2C6" + }, + { + "n": "大会员", + "v": "4%2C6" + } + ] + } + ], + "4": [ + { + "key": "order", + "name": "排序", + "value": [ + { + "n": "播放数量", + "v": "2" + }, + { + "n": "更新时间", + "v": "0" + }, + { + "n": "最高评分", + "v": "4" + }, + { + "n": "弹幕数量", + "v": "1" + }, + { + "n": "追看人数", + "v": "3" + }, + { + "n": "开播时间", + "v": "5" + }, + { + "n": "上映时间", + "v": "6" + } + ] + }, + { + "key": "season_status", + "name": "付费", + "value": [ + { + "n": "全部", + "v": "-1" + }, + { + "n": "免费", + "v": "1" + }, + { + "n": "付费", + "v": "2%2C6" + }, + { + "n": "大会员", + "v": "4%2C6" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/config/configcenter.json b/lrzy/config/configcenter.json new file mode 100644 index 0000000..58886ba --- /dev/null +++ b/lrzy/config/configcenter.json @@ -0,0 +1,299 @@ +[ + { + "name": "通用", + "list": [ + { + "name": "ABI", + "key": "abiSelection", + "icon": "", + "des": "手动选择ABI" + }, + { + "name": "Go引擎", + "key": "mediaproxyProbe", + "icon": "", + "des": "Go引擎状态查看" + }, + { + "name": "Go引擎", + "key": "mediaproxyDNS", + "icon": "", + "des": "Go引擎DNS设置" + }, + { + "name": "盘搜", + "key": "pansouDomain", + "icon": "", + "des": "盘搜域名设置" + }, + { + "name": "凯速", + "key": "loginOrlogooutKStore", + "icon": "", + "des": "登录|退出" + }, + { + "name": "Cookie", + "key": "backupCookieToKStore", + "icon": "", + "des": "备份到凯速" + }, + { + "name": "Cookie", + "key": "downloadCookieToLocal", + "icon": "", + "des": "从凯速下载到本地" + } + ] + }, + { + "name": "哔哩", + "list": [ + { + "name": "退出登录", + "key": "cleanBilibiliCookie", + "icon": "", + "des": "清除cookie" + }, + { + "name": "登录", + "key": "setBilibiliCookie", + "icon": "", + "des": "设置cookie" + } + ] + }, + { + "name": "百度", + "list": [ + { + "name": "注册", + "key": "baiduSignUp", + "icon": "", + "des": "🎉新用户注册保存送100G永久空间" + }, + { + "name": "退出登录", + "key": "cleanBaiduCookie", + "icon": "", + "des": "清除cookie" + }, + { + "name": "登录", + "key": "setBaiduCookie", + "icon": "", + "des": "设置cookie" + }, + { + "name": "多线程", + "key": "setBaiduMultiThread", + "icon": "", + "des": "" + }, + { + "name": "手动清理", + "key": "cleanBaiduTempDir", + "icon": "", + "des": "手动清理tv_temp_saved目录全部文件" + }, + { + "name": "自动清理", + "key": "baiduVideoCacheTime", + "icon": "", + "des": "设置自动清理tv_temp_saved目录文件缓存时间" + } + ] + }, + { + "name": "夸氪", + "list": [ + { + "name": "注册", + "key": "quarkSignUp", + "icon": "", + "des": "🎉新用户注册保存送1T永久空间" + }, + { + "name": "退出登录", + "key": "cleanQuarkCookie", + "icon": "", + "des": "清除cookie" + }, + { + "name": "登录", + "key": "setQuarkCookie", + "icon": "", + "des": "设置cookie" + }, + { + "name": "多线程", + "key": "setQuarkMultiThread", + "icon": "", + "des": "" + }, + { + "name": "手动清理", + "key": "cleanQuarkTempDir", + "icon": "", + "des": "手动清理tv_temp_saved目录全部文件" + }, + { + "name": "自动清理", + "key": "quarkVideoCacheTime", + "icon": "", + "des": "设置自动清理tv_temp_saved目录文件缓存时间" + } + ] + }, + { + "name": "优囍", + "list": [ + { + "name": "注册", + "key": "ucSignUp", + "icon": "", + "des": "🎉新用户注册保存送1T永久空间" + }, + { + "name": "退出登录", + "key": "cleanUcCookie", + "icon": "", + "des": "清除Cookie" + }, + { + "name": "登录", + "key": "setUcCookie", + "icon": "", + "des": "设置Cookie" + }, + { + "name": "多线程", + "key": "setUcMultiThread", + "icon": "", + "des": "" + }, + { + "name": "手动清理", + "key": "cleanUcTempDir", + "icon": "", + "des": "手动清理tv_temp_saved目录全部文件" + }, + { + "name": "自动清理", + "key": "ucVideoCacheTime", + "icon": "", + "des": "设置自动清理tv_temp_saved目录文件缓存时间" + } + ] + }, + { + "name": "阿里", + "list": [ + { + "name": "退出登录", + "key": "cleanAliCookie", + "icon": "", + "des": "清除Cookie" + }, + { + "name": "登录", + "key": "setAliCookie", + "icon": "", + "des": "设置Cookie" + }, + { + "name": "多线程", + "key": "setAliMultiThread", + "icon": "", + "des": "" + }, + { + "name": "手动清理", + "key": "cleanAliTempDir", + "icon": "", + "des": "手动清理tv_temp_saved目录全部文件" + }, + { + "name": "自动清理", + "key": "aliVideoCacheTime", + "icon": "", + "des": "设置自动清理tv_temp_saved目录文件缓存时间" + } + ] + }, + { + "name": "天懿", + "list": [ + { + "name": "退出登录", + "key": "cleanTianyiCookie", + "icon": "", + "des": "清除cookie" + }, + { + "name": "登录", + "key": "setTianyiCookie", + "icon": "", + "des": "设置Cookie" + }, + { + "name": "多线程", + "key": "setTianyiMultiThread", + "icon": "", + "des": "" + } + ] + }, + { + "name": "壹贰叁", + "list": [ + { + "name": "退出登录", + "key": "clean123Cookie", + "icon": "", + "des": "清除cookie" + }, + { + "name": "清空保存", + "key": "clean123UserInfo", + "icon": "", + "des": "清除账号信息" + }, + { + "name": "登录", + "key": "set123Cookie", + "icon": "", + "des": "设置Cookie" + }, + { + "name": "多线程", + "key": "set123MultiThread", + "icon": "", + "des": "" + } + ] + }, + { + "name": "数据库", + "list": [ + { + "name": "本地数据库映射配置", + "key": "localDatabaseMapping", + "icon": "", + "des": "设置" + }, + { + "name": "网络数据库映射配置", + "key": "networkDatabaseMapping", + "icon": "", + "des": "设置" + }, + { + "name": "网络数据库", + "key": "networkDatabaseManagement", + "icon": "", + "des": "管理" + } + ] + } +] \ No newline at end of file diff --git a/lrzy/config/czkt.json b/lrzy/config/czkt.json new file mode 100644 index 0000000..8e89f18 --- /dev/null +++ b/lrzy/config/czkt.json @@ -0,0 +1,1398 @@ +{ + "class": [ + { + "type_name": "7年级语文", + "type_id": "7年级语文" + }, + { + "type_name": "7年级数学", + "type_id": "7年级数学" + }, + { + "type_name": "7年级英语", + "type_id": "7年级英语" + }, + { + "type_name": "7年级历史", + "type_id": "7年级历史" + }, + { + "type_name": "7年级地理", + "type_id": "7年级地理" + }, + { + "type_name": "7年级生物", + "type_id": "7年级生物" + }, + { + "type_name": "7年级物理", + "type_id": "7年级物理" + }, + { + "type_name": "7年级化学", + "type_id": "7年级化学" + }, + { + "type_name": "8年级语文", + "type_id": "8年级语文" + }, + { + "type_name": "8年级数学", + "type_id": "8年级数学" + }, + { + "type_name": "8年级英语", + "type_id": "8年级英语" + }, + { + "type_name": "8年级历史", + "type_id": "8年级历史" + }, + { + "type_name": "8年级地理", + "type_id": "8年级地理" + }, + { + "type_name": "8年级生物", + "type_id": "8年级生物" + }, + { + "type_name": "8年级物理", + "type_id": "8年级物理" + }, + { + "type_name": "8年级化学", + "type_id": "8年级化学" + }, + { + "type_name": "9年级语文", + "type_id": "9年级语文" + }, + { + "type_name": "9年级数学", + "type_id": "9年级数学" + }, + { + "type_name": "9年级英语", + "type_id": "9年级英语" + }, + { + "type_name": "9年级历史", + "type_id": "9年级历史" + }, + { + "type_name": "9年级地理", + "type_id": "9年级地理" + }, + { + "type_name": "9年级生物", + "type_id": "9年级生物" + }, + { + "type_name": "9年级物理", + "type_id": "9年级物理" + }, + { + "type_name": "9年级化学", + "type_id": "9年级化学" + } + ], + "filters": { + "7年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级语文" + }, + { + "n": "人教版", + "v": "人教版7年级语文" + }, + { + "n": "北师大版", + "v": "北师大版7年级语文" + }, + { + "n": "苏教版", + "v": "苏教版7年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级英语" + }, + { + "n": "人教版", + "v": "人教版7年级英语" + }, + { + "n": "北师大版", + "v": "北师大版7年级英语" + }, + { + "n": "苏教版", + "v": "苏教版7年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级数学" + }, + { + "n": "人教版", + "v": "人教版7年级数学" + }, + { + "n": "北师大版", + "v": "北师大版7年级数学" + }, + { + "n": "苏教版", + "v": "苏教版7年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级化学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级化学" + }, + { + "n": "人教版", + "v": "人教版7年级化学" + }, + { + "n": "北师大版", + "v": "北师大版7年级化学" + }, + { + "n": "苏教版", + "v": "苏教版7年级化学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级物理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级物理" + }, + { + "n": "人教版", + "v": "人教版7年级物理" + }, + { + "n": "北师大版", + "v": "北师大版7年级物理" + }, + { + "n": "苏教版", + "v": "苏教版7年级物理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级生物": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级生物" + }, + { + "n": "人教版", + "v": "人教版7年级生物" + }, + { + "n": "北师大版", + "v": "北师大版7年级生物" + }, + { + "n": "苏教版", + "v": "苏教版7年级生物" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级历史": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级历史" + }, + { + "n": "人教版", + "v": "人教版7年级历史" + }, + { + "n": "北师大版", + "v": "北师大版7年级历史" + }, + { + "n": "苏教版", + "v": "苏教版7年级历史" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "7年级地理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版7年级地理" + }, + { + "n": "人教版", + "v": "人教版7年级地理" + }, + { + "n": "北师大版", + "v": "北师大版7年级地理" + }, + { + "n": "苏教版", + "v": "苏教版7年级地理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级语文" + }, + { + "n": "人教版", + "v": "人教版8年级语文" + }, + { + "n": "北师大版", + "v": "北师大版8年级语文" + }, + { + "n": "苏教版", + "v": "苏教版8年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级英语" + }, + { + "n": "人教版", + "v": "人教版8年级英语" + }, + { + "n": "北师大版", + "v": "北师大版8年级英语" + }, + { + "n": "苏教版", + "v": "苏教版8年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级数学" + }, + { + "n": "人教版", + "v": "人教版8年级数学" + }, + { + "n": "北师大版", + "v": "北师大版8年级数学" + }, + { + "n": "苏教版", + "v": "苏教版8年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级化学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级化学" + }, + { + "n": "人教版", + "v": "人教版8年级化学" + }, + { + "n": "北师大版", + "v": "北师大版8年级化学" + }, + { + "n": "苏教版", + "v": "苏教版8年级化学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级物理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级物理" + }, + { + "n": "人教版", + "v": "人教版8年级物理" + }, + { + "n": "北师大版", + "v": "北师大版8年级物理" + }, + { + "n": "苏教版", + "v": "苏教版8年级物理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级生物": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级生物" + }, + { + "n": "人教版", + "v": "人教版8年级生物" + }, + { + "n": "北师大版", + "v": "北师大版8年级生物" + }, + { + "n": "苏教版", + "v": "苏教版8年级生物" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级历史": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级历史" + }, + { + "n": "人教版", + "v": "人教版8年级历史" + }, + { + "n": "北师大版", + "v": "北师大版8年级历史" + }, + { + "n": "苏教版", + "v": "苏教版8年级历史" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "8年级地理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版8年级地理" + }, + { + "n": "人教版", + "v": "人教版8年级地理" + }, + { + "n": "北师大版", + "v": "北师大版8年级地理" + }, + { + "n": "苏教版", + "v": "苏教版8年级地理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级语文" + }, + { + "n": "人教版", + "v": "人教版9年级语文" + }, + { + "n": "北师大版", + "v": "北师大版9年级语文" + }, + { + "n": "苏教版", + "v": "苏教版9年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级英语" + }, + { + "n": "人教版", + "v": "人教版9年级英语" + }, + { + "n": "北师大版", + "v": "北师大版9年级英语" + }, + { + "n": "苏教版", + "v": "苏教版9年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级数学" + }, + { + "n": "人教版", + "v": "人教版9年级数学" + }, + { + "n": "北师大版", + "v": "北师大版9年级数学" + }, + { + "n": "苏教版", + "v": "苏教版9年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级化学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级化学" + }, + { + "n": "人教版", + "v": "人教版9年级化学" + }, + { + "n": "北师大版", + "v": "北师大版9年级化学" + }, + { + "n": "苏教版", + "v": "苏教版9年级化学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级物理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级物理" + }, + { + "n": "人教版", + "v": "人教版9年级物理" + }, + { + "n": "北师大版", + "v": "北师大版9年级物理" + }, + { + "n": "苏教版", + "v": "苏教版9年级物理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级生物": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级生物" + }, + { + "n": "人教版", + "v": "人教版9年级生物" + }, + { + "n": "北师大版", + "v": "北师大版9年级生物" + }, + { + "n": "苏教版", + "v": "苏教版9年级生物" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级历史": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级历史" + }, + { + "n": "人教版", + "v": "人教版9年级历史" + }, + { + "n": "北师大版", + "v": "北师大版9年级历史" + }, + { + "n": "苏教版", + "v": "苏教版9年级历史" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "9年级地理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版9年级地理" + }, + { + "n": "人教版", + "v": "人教版9年级地理" + }, + { + "n": "北师大版", + "v": "北师大版9年级地理" + }, + { + "n": "苏教版", + "v": "苏教版9年级地理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/config/gzkt.json b/lrzy/config/gzkt.json new file mode 100644 index 0000000..ea8a3e0 --- /dev/null +++ b/lrzy/config/gzkt.json @@ -0,0 +1,1576 @@ +{ + "class": [ + { + "type_name": "高一语文", + "type_id": "高一语文" + }, + { + "type_name": "高一数学", + "type_id": "高一数学" + }, + { + "type_name": "高一英语", + "type_id": "高一英语" + }, + { + "type_name": "高一历史", + "type_id": "高一历史" + }, + { + "type_name": "高一地理", + "type_id": "高一地理" + }, + { + "type_name": "高一生物", + "type_id": "高一生物" + }, + { + "type_name": "高一思想政治", + "type_id": "高一思想政治" + }, + { + "type_name": "高一物理", + "type_id": "高一物理" + }, + { + "type_name": "高一化学", + "type_id": "高一化学" + }, + { + "type_name": "高二语文", + "type_id": "高二语文" + }, + { + "type_name": "高二数学", + "type_id": "高二数学" + }, + { + "type_name": "高二英语", + "type_id": "高二英语" + }, + { + "type_name": "高二历史", + "type_id": "高二历史" + }, + { + "type_name": "高二地理", + "type_id": "高二地理" + }, + { + "type_name": "高二生物", + "type_id": "高二生物" + }, + { + "type_name": "高二思想政治", + "type_id": "高二思想政治" + }, + { + "type_name": "高二物理", + "type_id": "高二物理" + }, + { + "type_name": "高二化学", + "type_id": "高二化学" + }, + { + "type_name": "高三语文", + "type_id": "高三语文" + }, + { + "type_name": "高三数学", + "type_id": "高三数学" + }, + { + "type_name": "高三英语", + "type_id": "高三英语" + }, + { + "type_name": "高三历史", + "type_id": "高三历史" + }, + { + "type_name": "高三地理", + "type_id": "高三地理" + }, + { + "type_name": "高三生物", + "type_id": "高三生物" + }, + { + "type_name": "高三思想政治", + "type_id": "高三思想政治" + }, + { + "type_name": "高三物理", + "type_id": "高三物理" + }, + { + "type_name": "高三化学", + "type_id": "高三化学" + }, + { + "type_name": "高中信息技术", + "type_id": "高中信息技术" + } + ], + "filters": { + "高一语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一语文" + }, + { + "n": "人教版", + "v": "人教版高一语文" + }, + { + "n": "北师大版", + "v": "北师大版高一语文" + }, + { + "n": "苏教版", + "v": "苏教版高一语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一英语" + }, + { + "n": "人教版", + "v": "人教版高一英语" + }, + { + "n": "北师大版", + "v": "北师大版高一英语" + }, + { + "n": "苏教版", + "v": "苏教版高一英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一数学" + }, + { + "n": "人教版", + "v": "人教版高一数学" + }, + { + "n": "北师大版", + "v": "北师大版高一数学" + }, + { + "n": "苏教版", + "v": "苏教版高一数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一物理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一物理" + }, + { + "n": "人教版", + "v": "人教版高一物理" + }, + { + "n": "北师大版", + "v": "北师大版高一物理" + }, + { + "n": "苏教版", + "v": "苏教版高一物理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一化学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一化学" + }, + { + "n": "人教版", + "v": "人教版高一化学" + }, + { + "n": "北师大版", + "v": "北师大版高一化学" + }, + { + "n": "苏教版", + "v": "苏教版高一化学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一历史": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一历史" + }, + { + "n": "人教版", + "v": "人教版高一历史" + }, + { + "n": "北师大版", + "v": "北师大版高一历史" + }, + { + "n": "苏教版", + "v": "苏教版高一历史" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一生物": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一生物" + }, + { + "n": "人教版", + "v": "人教版高一生物" + }, + { + "n": "北师大版", + "v": "北师大版高一生物" + }, + { + "n": "苏教版", + "v": "苏教版高一生物" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一思想政治": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一思想政治" + }, + { + "n": "人教版", + "v": "人教版高一思想政治" + }, + { + "n": "北师大版", + "v": "北师大版高一思想政治" + }, + { + "n": "苏教版", + "v": "苏教版高一思想政治" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高一地理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高一地理" + }, + { + "n": "人教版", + "v": "人教版高一地理" + }, + { + "n": "北师大版", + "v": "北师大版高一地理" + }, + { + "n": "苏教版", + "v": "苏教版高一地理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二语文" + }, + { + "n": "人教版", + "v": "人教版高二语文" + }, + { + "n": "北师大版", + "v": "北师大版高二语文" + }, + { + "n": "苏教版", + "v": "苏教版高二语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二英语" + }, + { + "n": "人教版", + "v": "人教版高二英语" + }, + { + "n": "北师大版", + "v": "北师大版高二英语" + }, + { + "n": "苏教版", + "v": "苏教版高二英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二数学" + }, + { + "n": "人教版", + "v": "人教版高二数学" + }, + { + "n": "北师大版", + "v": "北师大版高二数学" + }, + { + "n": "苏教版", + "v": "苏教版高二数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二物理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二物理" + }, + { + "n": "人教版", + "v": "人教版高二物理" + }, + { + "n": "北师大版", + "v": "北师大版高二物理" + }, + { + "n": "苏教版", + "v": "苏教版高二物理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二化学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二化学" + }, + { + "n": "人教版", + "v": "人教版高二化学" + }, + { + "n": "北师大版", + "v": "北师大版高二化学" + }, + { + "n": "苏教版", + "v": "苏教版高二化学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二历史": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二历史" + }, + { + "n": "人教版", + "v": "人教版高二历史" + }, + { + "n": "北师大版", + "v": "北师大版高二历史" + }, + { + "n": "苏教版", + "v": "苏教版高二历史" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二生物": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二生物" + }, + { + "n": "人教版", + "v": "人教版高二生物" + }, + { + "n": "北师大版", + "v": "北师大版高二生物" + }, + { + "n": "苏教版", + "v": "苏教版高二生物" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二思想政治": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二思想政治" + }, + { + "n": "人教版", + "v": "人教版高二思想政治" + }, + { + "n": "北师大版", + "v": "北师大版高二思想政治" + }, + { + "n": "苏教版", + "v": "苏教版高二思想政治" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高二地理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高二地理" + }, + { + "n": "人教版", + "v": "人教版高二地理" + }, + { + "n": "北师大版", + "v": "北师大版高二地理" + }, + { + "n": "苏教版", + "v": "苏教版高二地理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三语文" + }, + { + "n": "人教版", + "v": "人教版高三语文" + }, + { + "n": "北师大版", + "v": "北师大版高三语文" + }, + { + "n": "苏教版", + "v": "苏教版高三语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三英语" + }, + { + "n": "人教版", + "v": "人教版高三英语" + }, + { + "n": "北师大版", + "v": "北师大版高三英语" + }, + { + "n": "苏教版", + "v": "苏教版高三英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三数学" + }, + { + "n": "人教版", + "v": "人教版高三数学" + }, + { + "n": "北师大版", + "v": "北师大版高三数学" + }, + { + "n": "苏教版", + "v": "苏教版高三数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三物理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三物理" + }, + { + "n": "人教版", + "v": "人教版高三物理" + }, + { + "n": "北师大版", + "v": "北师大版高三物理" + }, + { + "n": "苏教版", + "v": "苏教版高三物理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三化学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三化学" + }, + { + "n": "人教版", + "v": "人教版高三化学" + }, + { + "n": "北师大版", + "v": "北师大版高三化学" + }, + { + "n": "苏教版", + "v": "苏教版高三化学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三历史": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三历史" + }, + { + "n": "人教版", + "v": "人教版高三历史" + }, + { + "n": "北师大版", + "v": "北师大版高三历史" + }, + { + "n": "苏教版", + "v": "苏教版高三历史" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三生物": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三生物" + }, + { + "n": "人教版", + "v": "人教版高三生物" + }, + { + "n": "北师大版", + "v": "北师大版高三生物" + }, + { + "n": "苏教版", + "v": "苏教版高三生物" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三思想政治": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三思想政治" + }, + { + "n": "人教版", + "v": "人教版高三思想政治" + }, + { + "n": "北师大版", + "v": "北师大版高三思想政治" + }, + { + "n": "苏教版", + "v": "苏教版高三思想政治" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "高三地理": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版高三地理" + }, + { + "n": "人教版", + "v": "人教版高三地理" + }, + { + "n": "北师大版", + "v": "北师大版高三地理" + }, + { + "n": "苏教版", + "v": "苏教版高三地理" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/config/jianpian.json b/lrzy/config/jianpian.json new file mode 100644 index 0000000..f4e370b --- /dev/null +++ b/lrzy/config/jianpian.json @@ -0,0 +1,426 @@ +{ + "1": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ], + "2": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ], + "3": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ], + "4": [ + { + "key": "area", + "name": "地區", + "init": "1", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "国产", + "v": "1" + }, + { + "n": "中国香港", + "v": "3" + }, + { + "n": "中国台湾", + "v": "6" + }, + { + "n": "美国", + "v": "5" + }, + { + "n": "韩国", + "v": "18" + }, + { + "n": "日本", + "v": "2" + } + ] + }, + { + "key": "year", + "name": "年份", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "2025", + "v": "107" + }, + { + "n": "2024", + "v": "119" + }, + { + "n": "2023", + "v": "153" + }, + { + "n": "2022", + "v": "101" + }, + { + "n": "2021", + "v": "118" + }, + { + "n": "2020", + "v": "16" + }, + { + "n": "2019", + "v": "7" + }, + { + "n": "2018", + "v": "2" + }, + { + "n": "2017", + "v": "3" + }, + { + "n": "2016", + "v": "22" + } + ] + }, + { + "key": "by", + "name": "排序", + "init": "updata", + "value": [ + { + "n": "热门", + "v": "hot" + }, + { + "n": "更新", + "v": "updata" + }, + { + "n": "评分", + "v": "rating" + } + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/config/local_database_mapping.json b/lrzy/config/local_database_mapping.json new file mode 100644 index 0000000..8bd51cd --- /dev/null +++ b/lrzy/config/local_database_mapping.json @@ -0,0 +1,238 @@ +{ + "version": "3.0", + "databases": { + "movie_ea5fb": { + "name": "🎬 配置参考", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/movie_ea5fb.db", + "count_query": "SELECT COUNT(*) FROM vod_unified_data", + "category_count_query": "SELECT type_name, COUNT(*) FROM vod_unified_data GROUP BY type_name", + "categories_query": "SELECT DISTINCT type_name, type_name FROM vod_unified_data WHERE type_name IS NOT NULL AND type_name != '' ORDER BY type_name", + "tables": { + "main": { + "table_name": "vod_unified_data", + "category_filter_field": "type_name", + "search_fields": [ + "vod_name", + "vod_actor", + "vod_director" + ], + "field_mapping": { + "vod_id": "vod_id", + "vod_name": "vod_name", + "vod_pic": "vod_pic", + "type_name": "type_name", + "vod_actor": "vod_actor", + "vod_director": "vod_director", + "vod_content": "vod_content", + "vod_play_from": "vod_play_from", + "vod_play_url": "vod_play_url", + "vod_remarks": "vod_remarks", + "vod_year": "vod_year", + "vod_area": "vod_area" + } + } + } + }, + "movie_b8b5e": { + "name": "🎬 movie_b8b5e", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/movie_b8b5e.db", + "count_query": "SELECT COUNT(*) FROM vod_unified_data", + "category_count_query": "SELECT type_name, COUNT(*) FROM vod_unified_data GROUP BY type_name", + "categories_query": "SELECT DISTINCT type_name, type_name FROM vod_unified_data WHERE type_name IS NOT NULL AND type_name != '' ORDER BY type_name", + "tables": { + "main": { + "table_name": "vod_unified_data", + "category_filter_field": "type_name", + "search_fields": [ + "vod_name" + ], + "field_mapping": { + "vod_id": "vod_id", + "vod_name": "vod_name", + "vod_pic": "_IGNORE_FIELD_", + "type_name": "type_name", + "vod_play_url": "vod_play_url", + "vod_actor": "_IGNORE_FIELD_", + "vod_director": "_IGNORE_FIELD_", + "vod_remarks": "_IGNORE_FIELD_", + "vod_pubdate": "_IGNORE_FIELD_", + "vod_area": "_IGNORE_FIELD_", + "vod_year": "_IGNORE_FIELD_", + "vod_content": "_IGNORE_FIELD_" + } + } + } + }, + "song_b4d4b": { + "name": "🎵 song_b4d4b.db", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/song_b4d4b.db", + "count_query": "SELECT COUNT(*) FROM songs", + "category_count_query": "SELECT genre, COUNT(*) FROM songs GROUP BY genre", + "categories_query": "SELECT DISTINCT genre, genre FROM songs WHERE genre IS NOT NULL AND genre != '' ORDER BY genre", + "tables": { + "main": { + "table_name": "songs", + "category_filter_field": "genre", + "search_fields": [ + "song_name" + ], + "field_mapping": { + "vod_id": "id", + "vod_name": "song_name", + "vod_pic": "_IGNORE_FIELD_", + "type_name": "genre", + "vod_play_url": "url", + "vod_remarks": "created_at" + } + } + } + }, + "song_aed2f": { + "name": "🎵 配置参考0", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/song_aed2f.db", + "count_query": "SELECT COUNT(*) FROM song", + "category_count_query": "SELECT type_id, COUNT(*) FROM song GROUP BY type_id", + "categories_query": "SELECT id, name FROM song_type ORDER BY id", + "tables": { + "main": { + "table_name": "song AS T1 JOIN song_type AS T2 ON T1.type_id = T2.id", + "category_filter_field": "T1.type_id", + "search_fields": [ + "T1.name", + "T1.singer_names" + ], + "field_mapping": { + "vod_id": "T1.id", + "vod_name": "T1.name", + "vod_pic": "T1.url", + "type_name": "T2.name", + "vod_actor": "T1.singer_names", + "vod_content": "T1.edition", + "vod_play_url": "'http://em.21dtv.com/songs/' || T1.number || '.' || T1.format", + "vod_remarks": "T1.format" + } + } + } + }, + "lsp_d1944": { + "name": "🎬 配置参考1", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/lsp_d1944.db", + "count_query": "SELECT COUNT(*) FROM videos", + "category_count_query": "SELECT category_id, COUNT(*) FROM videos GROUP BY category_id", + "categories_query": "SELECT id, name FROM categories ORDER BY id", + "tables": { + "main": { + "table_name": "videos AS T1 JOIN categories AS T2 ON T1.category_id = T2.id", + "category_filter_field": "T1.category_id", + "search_fields": [ + "T1.name", + "T1.actor" + ], + "field_mapping": { + "vod_id": "T1.id", + "vod_name": "REPLACE(REPLACE(T1.name, '目录', ''), '为你推荐', '')", + "vod_pic": "T1.image", + "type_name": "T2.name", + "vod_content": "T1.content", + "vod_play_url": "T1.play_url", + "vod_remarks": "T1.remarks" + } + } + } + }, + "lsp_eb2984": { + "name": "🎬 配置参考2", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/eb2984.db", + "count_query": "SELECT COUNT(*) FROM videos", + "category_count_query": "SELECT cate_id, COUNT(*) FROM videos GROUP BY cate_id", + "categories_query": "SELECT DISTINCT cate_id, cate_name FROM videos WHERE cate_id IS NOT NULL AND cate_name IS NOT NULL AND cate_name != '' ORDER BY cate_id", + "tables": { + "main": { + "table_name": "videos", + "category_filter_field": "cate_id", + "search_fields": [ + "title" + ], + "field_mapping": { + "vod_id": "id", + "vod_name": "REPLACE(REPLACE(REPLACE(title, '目录', ''), '为你推荐', ''), '', '')", + "vod_pic": "pic", + "type_name": "cate_name", + "vod_content": "cate_name", + "vod_play_url": "play_url", + "vod_remarks": "cate_name" + } + } + } + }, + "lsp_9b0a3": { + "name": "🎬 配置参考3", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/9b0a3.db", + "count_query": "SELECT COUNT(*) FROM videos", + "category_count_query": "SELECT category_id, COUNT(*) FROM videos GROUP BY category_id", + "categories_query": "SELECT id, name FROM categories ORDER BY id", + "tables": { + "main": { + "table_name": "videos AS T1 JOIN categories AS T2 ON T1.category_id = T2.id", + "category_filter_field": "T1.category_id", + "search_fields": [ + "T1.name" + ], + "field_mapping": { + "vod_id": "T1.id", + "vod_name": "T1.name", + "vod_pic": "T1.image", + "type_name": "T2.name", + "vod_content": "T1.content", + "vod_play_url": "T1.play_url", + "vod_remarks": "T1.remarks" + } + } + } + }, + "lsp_d4788": { + "name": "🎬配置参考4", + "valid": 1, + "hide": 0, + "path": "/storage/emulated/0/dp/db/d4788.db", + "count_query": "SELECT COUNT(*) FROM cj", + "category_count_query": "SELECT type_name, COUNT(*) FROM cj GROUP BY type_name", + "categories_query": "SELECT DISTINCT type_name, type_name FROM cj WHERE type_name IS NOT NULL AND type_name != '' ORDER BY type_name", + "tables": { + "main": { + "table_name": "cj", + "category_filter_field": "type_name", + "search_fields": [ + "vod_name", + "vod_actor" + ], + "field_mapping": { + "vod_id": "vod_id", + "vod_name": "vod_name", + "vod_pic": "vod_pic", + "type_name": "type_name", + "vod_actor": "vod_actor", + "vod_content": "vod_content", + "vod_play_from": "vod_play_from", + "vod_play_url": "vod_play_url", + "vod_remarks": "vod_remarks" + } + } + } + } + } +} \ No newline at end of file diff --git a/lrzy/config/market.json b/lrzy/config/market.json new file mode 100644 index 0000000..7e1f23f --- /dev/null +++ b/lrzy/config/market.json @@ -0,0 +1,64 @@ +[ + { + "name": "本地包", + "list": [ + { + "name": "官方网站", + "url": "https://chigua.eu.org", + "icon": "", + "copy": "", + "version": "" + }, + { + "name": "使用说明", + "url": "https://v6.gh-proxy.org/https://raw.githubusercontent.com/chitue/dongliTV/refs/heads/main/README.md", + "icon": "", + "copy": "", + "version": "" + }, + { + "name": "更新日志", + "url": "https://v6.gh-proxy.org/https://raw.githubusercontent.com/chitue/dongliTV/refs/heads/main/CHANGELOG.md", + "icon": "", + "copy": "", + "version": "" + }, + { + "name": "本地包", + "url": "dongliTV", + "icon": "", + "copy": "", + "version": "" + } + ] + }, + { + "name": "蜂蜜影视", + "list": [ + { + "name": "蜂蜜影视", + "url": "https://v6.gh-proxy.org//https://raw.githubusercontent.com/FongMi/Release/fongmi/apk/leanback-armeabi_v7a.apk", + "icon": "", + "version": "电视32位" + }, + { + "name": "蜂蜜影视", + "url": "https://v6.gh-proxy.org/https://raw.githubusercontent.com/FongMi/Release/fongmi/apk/leanback-arm64_v8a.apk", + "icon": "", + "version": "电视64位" + }, + { + "name": "蜂蜜影视", + "url": "https://v6.gh-proxy.org/https://raw.githubusercontent.com/FongMi/Release/fongmi/apk/mobile-armeabi_v7a.apk", + "icon": "", + "version": "手机32位" + }, + { + "name": "蜂蜜影视", + "url": "https://v6.gh-proxy.org/https://raw.githubusercontent.com/FongMi/Release/fongmi/apk/mobile-arm64_v8a.apk", + "icon": "", + "version": "手机64位" + } + ] + } +] \ No newline at end of file diff --git a/lrzy/config/myali.json b/lrzy/config/myali.json new file mode 100644 index 0000000..754ceea --- /dev/null +++ b/lrzy/config/myali.json @@ -0,0 +1,23 @@ +{ + "categories": [ + { + "key": "dlfx", + "hide": false, + "name": "🔥热门推荐", + "shares": [ + { + "name": "体育健康", + "remarks": "体育健康", + "url": "https://www.alipan.com/s/erRH4Hz48Xo", + "pwd": "" + }, + { + "name": "剑来", + "remarks": "剑澜青萍", + "url": "https://www.alipan.com/s/wh4opyM12mJ", + "pwd": "" + } + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/config/mybaidu.json b/lrzy/config/mybaidu.json new file mode 100644 index 0000000..60b63c8 --- /dev/null +++ b/lrzy/config/mybaidu.json @@ -0,0 +1,24 @@ +{ + "categories": [ + { + "key": "dlfx", + "hide": false, + "name": "🔥热门推荐", + "shares": [ + { + "name": "体育健康", + "remarks": "体育健康", + "url": "https://pan.baidu.com/s/13JGvmZlFIqJblaDFRGthVQ?pwd=2026", + "pwd": "2026" + }, + { + "name": "剑来", + "remarks": "含第一季", + "url": "https://pan.baidu.com/s/1ohbEQ-1afBlUjODD16CtFw?pwd=5ve6", + "pwd": "5ve6" + } + + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/config/myquark.json b/lrzy/config/myquark.json new file mode 100644 index 0000000..0044f7e --- /dev/null +++ b/lrzy/config/myquark.json @@ -0,0 +1,21 @@ +{ + "categories": [ + { + "key": "dlfx", + "hide": false, + "name": "🔥热门推荐", + "shares": [ + { + "name": "应用商店", + "remarks": "应用推荐", + "url": "514a56ac6d23" + }, + { + "name": "热门短剧", + "remarks": "短剧推荐", + "url": "0eec2b76c93a" + } + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/config/myuc.json b/lrzy/config/myuc.json new file mode 100644 index 0000000..49e2f26 --- /dev/null +++ b/lrzy/config/myuc.json @@ -0,0 +1,23 @@ +{ + "categories": [ + { + "key": "dlfx", + "hide": false, + "name": "🔥热门推荐", + "shares": [ + { + "name": "应用商店", + "remarks": "应用推荐", + "url": "https://drive.uc.cn/s/084710ec4dc04?public=1", + "pwd": "" + }, + { + "name": "剑来", + "remarks": "剑澜青萍", + "url": "https://drive.uc.cn/s/9b3b5f24ca074?public=1", + "pwd": "" + } + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/config/network_database_mapping.json b/lrzy/config/network_database_mapping.json new file mode 100644 index 0000000..1212947 --- /dev/null +++ b/lrzy/config/network_database_mapping.json @@ -0,0 +1,98 @@ +{ + "version": "4.0", + "databases": { + "song_1a48b": { + "name": "🎵 KTV", + "valid": 1, + "hide": 1, + "size": 95191040, + "sha256": "1a48b4e3b78ee28cb878607f26637ffbb129fabddd45af8b8857ef9108468419", + "path": "https://v6.gh-proxy.org/https://github.com/chitue/dongliTV/releases/download/databases-20251223/song_1a48b.db", + "count_query": "SELECT COUNT(*) FROM song", + "category_count_query": "SELECT type_id, COUNT(*) FROM song GROUP BY type_id", + "categories_query": "SELECT id, name FROM song_type ORDER BY id", + "tables": { + "main": { + "table_name": "song AS T1 JOIN song_type AS T2 ON T1.type_id = T2.id LEFT JOIN song_language AS T3 ON T1.language_id = T3.id", + "category_filter_field": "T1.type_id", + "search_fields": [ + "T1.name", + "T1.singer_names" + ], + "field_mapping": { + "vod_id": "T1.id", + "vod_name": "T1.name", + "vod_pic": "T1.url", + "type_name": "T2.name", + "vod_actor": "T1.singer_names", + "vod_content": "T1.edition", + "vod_play_url": "'http://ktvmedia.mysoto.cc/songs/' || T1.number || '.' || T1.format", + "vod_remarks": "T1.singer_names || ' | ' || IFNULL(T3.name, '未知语言')" + } + } + } + }, + "movie_b8b5e": { + "name": "🎬 movie_b8b5e", + "valid": 1, + "hide": 0, + "size": 1347584, + "sha256": "b8b5ec0a290416464624ead7c5476fc0e0559898385777d8e1ef9d1fb5637d33", + "path": "https://v6.gh-proxy.org/https://github.com/chitue/dongliTV/releases/download/databases-20251223/movie_b8b5e.db", + "count_query": "SELECT COUNT(*) FROM vod_unified_data", + "category_count_query": "SELECT type_name, COUNT(*) FROM vod_unified_data GROUP BY type_name", + "categories_query": "SELECT DISTINCT type_name, type_name FROM vod_unified_data WHERE type_name IS NOT NULL AND type_name != '' ORDER BY type_name", + "tables": { + "main": { + "table_name": "vod_unified_data", + "category_filter_field": "type_name", + "search_fields": [ + "vod_name" + ], + "field_mapping": { + "vod_id": "vod_id", + "vod_name": "vod_name", + "vod_pic": "_IGNORE_FIELD_", + "type_name": "type_name", + "vod_play_url": "vod_play_url", + "vod_actor": "_IGNORE_FIELD_", + "vod_director": "_IGNORE_FIELD_", + "vod_remarks": "_IGNORE_FIELD_", + "vod_pubdate": "_IGNORE_FIELD_", + "vod_area": "_IGNORE_FIELD_", + "vod_year": "_IGNORE_FIELD_", + "vod_content": "_IGNORE_FIELD_" + } + } + } + }, + "song_b4d4b": { + "name": "🎵 song_b4d4b", + "valid": 1, + "hide": 0, + "size": 663552, + "sha256": "b4d4b5dc86e74bf2ff96a56f199e19f1d90ebbfff49c864833c421efa13e1db4", + "path": "https://v6.gh-proxy.org/https://github.com/chitue/dongliTV/releases/download/databases-20251223/song_b4d4b.db", + "count_query": "SELECT COUNT(*) FROM songs", + "category_count_query": "SELECT genre, COUNT(*) FROM songs GROUP BY genre", + "categories_query": "SELECT DISTINCT genre, genre FROM songs WHERE genre IS NOT NULL AND genre != '' ORDER BY genre", + "tables": { + "main": { + "table_name": "songs", + "category_filter_field": "genre", + "search_fields": [ + "song_name" + ], + "field_mapping": { + "vod_id": "id", + "vod_name": "song_name", + "vod_pic": "_IGNORE_FIELD_", + "type_name": "genre", + "vod_play_url": "url", + "vod_remarks": "created_at" + } + } + } + } + } +} \ No newline at end of file diff --git a/lrzy/config/sejy.json b/lrzy/config/sejy.json new file mode 100644 index 0000000..db0d684 --- /dev/null +++ b/lrzy/config/sejy.json @@ -0,0 +1,454 @@ +{ + "class": [ + { + "type_name": "儿童早教", + "type_id": "儿童早教" + }, + { + "type_name": "儿童启蒙故事", + "type_id": "儿童启蒙故事" + }, + { + "type_name": "儿童英语启蒙", + "type_id": "儿童英语启蒙" + }, + { + "type_name": "儿童歌曲", + "type_id": "儿童歌曲" + }, + { + "type_name": "儿童绘画", + "type_id": "儿童绘画" + }, + { + "type_name": "睡前故事", + "type_id": "睡前故事" + }, + { + "type_name": "儿童动画", + "type_id": "儿童动画" + }, + { + "type_name": "儿童音乐", + "type_id": "儿童音乐" + }, + { + "type_name": "儿童安全教育", + "type_id": "儿童安全教育" + }, + { + "type_name": "贝瓦儿歌", + "type_id": "贝瓦儿歌" + }, + { + "type_name": "悟空识字", + "type_id": "悟空识字" + }, + { + "type_name": "宝宝巴士", + "type_id": "宝宝巴士" + }, + { + "type_name": "儿歌多多", + "type_id": "儿歌多多" + }, + { + "type_name": "学而思", + "type_id": "学而思" + } + ], + "filters": { + "儿童早教": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童启蒙故事": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童英语启蒙": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童歌曲": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童绘画": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "睡前故事": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童动画": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童音乐": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿童安全教育": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "贝瓦儿歌": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "悟空识字": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "宝宝巴士": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "儿歌多多": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "学而思": [ + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/config/xxkt.json b/lrzy/config/xxkt.json new file mode 100644 index 0000000..7daba97 --- /dev/null +++ b/lrzy/config/xxkt.json @@ -0,0 +1,1050 @@ +{ + "class": [ + { + "type_name": "1年级语文", + "type_id": "1年级语文" + }, + { + "type_name": "1年级数学", + "type_id": "1年级数学" + }, + { + "type_name": "1年级英语", + "type_id": "1年级英语" + }, + { + "type_name": "2年级语文", + "type_id": "2年级语文" + }, + { + "type_name": "2年级数学", + "type_id": "2年级数学" + }, + { + "type_name": "2年级英语", + "type_id": "2年级英语" + }, + { + "type_name": "3年级语文", + "type_id": "3年级语文" + }, + { + "type_name": "3年级数学", + "type_id": "3年级数学" + }, + { + "type_name": "3年级英语", + "type_id": "3年级英语" + }, + { + "type_name": "4年级语文", + "type_id": "4年级语文" + }, + { + "type_name": "4年级数学", + "type_id": "4年级数学" + }, + { + "type_name": "4年级英语", + "type_id": "4年级英语" + }, + { + "type_name": "5年级语文", + "type_id": "5年级语文" + }, + { + "type_name": "5年级数学", + "type_id": "5年级数学" + }, + { + "type_name": "5年级英语", + "type_id": "5年级英语" + }, + { + "type_name": "6年级语文", + "type_id": "6年级语文" + }, + { + "type_name": "6年级数学", + "type_id": "6年级数学" + }, + { + "type_name": "6年级英语", + "type_id": "6年级英语" + } + ], + "filters": { + "1年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版1年级语文" + }, + { + "n": "人教版", + "v": "人教版1年级语文" + }, + { + "n": "北师大版", + "v": "北师大版1年级语文" + }, + { + "n": "苏教版", + "v": "苏教版1年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "1年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版1年级英语" + }, + { + "n": "人教版", + "v": "人教版1年级英语" + }, + { + "n": "北师大版", + "v": "北师大版1年级英语" + }, + { + "n": "苏教版", + "v": "苏教版1年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "1年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版1年级数学" + }, + { + "n": "人教版", + "v": "人教版1年级数学" + }, + { + "n": "北师大版", + "v": "北师大版1年级数学" + }, + { + "n": "苏教版", + "v": "苏教版1年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "2年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版2年级语文" + }, + { + "n": "人教版", + "v": "人教版2年级语文" + }, + { + "n": "北师大版", + "v": "北师大版2年级语文" + }, + { + "n": "苏教版", + "v": "苏教版2年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "2年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版2年级英语" + }, + { + "n": "人教版", + "v": "人教版2年级英语" + }, + { + "n": "北师大版", + "v": "北师大版2年级英语" + }, + { + "n": "苏教版", + "v": "苏教版2年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "2年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版2年级数学" + }, + { + "n": "人教版", + "v": "人教版2年级数学" + }, + { + "n": "北师大版", + "v": "北师大版2年级数学" + }, + { + "n": "苏教版", + "v": "苏教版2年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "3年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版3年级语文" + }, + { + "n": "人教版", + "v": "人教版3年级语文" + }, + { + "n": "北师大版", + "v": "北师大版3年级语文" + }, + { + "n": "苏教版", + "v": "苏教版3年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "3年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版3年级英语" + }, + { + "n": "人教版", + "v": "人教版3年级英语" + }, + { + "n": "北师大版", + "v": "北师大版3年级英语" + }, + { + "n": "苏教版", + "v": "苏教版3年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "3年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版3年级数学" + }, + { + "n": "人教版", + "v": "人教版3年级数学" + }, + { + "n": "北师大版", + "v": "北师大版3年级数学" + }, + { + "n": "苏教版", + "v": "苏教版3年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "4年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版4年级语文" + }, + { + "n": "人教版", + "v": "人教版4年级语文" + }, + { + "n": "北师大版", + "v": "北师大版4年级语文" + }, + { + "n": "苏教版", + "v": "苏教版4年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "4年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版4年级英语" + }, + { + "n": "人教版", + "v": "人教版4年级英语" + }, + { + "n": "北师大版", + "v": "北师大版4年级英语" + }, + { + "n": "苏教版", + "v": "苏教版4年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "4年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版4年级数学" + }, + { + "n": "人教版", + "v": "人教版4年级数学" + }, + { + "n": "北师大版", + "v": "北师大版4年级数学" + }, + { + "n": "苏教版", + "v": "苏教版4年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "5年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版5年级语文" + }, + { + "n": "人教版", + "v": "人教版5年级语文" + }, + { + "n": "北师大版", + "v": "北师大版5年级语文" + }, + { + "n": "苏教版", + "v": "苏教版5年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "5年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版5年级英语" + }, + { + "n": "人教版", + "v": "人教版5年级英语" + }, + { + "n": "北师大版", + "v": "北师大版5年级英语" + }, + { + "n": "苏教版", + "v": "苏教版5年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "5年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版5年级数学" + }, + { + "n": "人教版", + "v": "人教版5年级数学" + }, + { + "n": "北师大版", + "v": "北师大版5年级数学" + }, + { + "n": "苏教版", + "v": "苏教版5年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "6年级语文": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版6年级语文" + }, + { + "n": "人教版", + "v": "人教版6年级语文" + }, + { + "n": "北师大版", + "v": "北师大版6年级语文" + }, + { + "n": "苏教版", + "v": "苏教版6年级语文" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "6年级英语": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版6年级英语" + }, + { + "n": "人教版", + "v": "人教版6年级英语" + }, + { + "n": "北师大版", + "v": "北师大版6年级英语" + }, + { + "n": "苏教版", + "v": "苏教版6年级英语" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ], + "6年级数学": [ + { + "key": "tid", + "name": "分类", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "沪教版", + "v": "沪教版6年级数学" + }, + { + "n": "人教版", + "v": "人教版6年级数学" + }, + { + "n": "北师大版", + "v": "北师大版6年级数学" + }, + { + "n": "苏教版", + "v": "苏教版6年级数学" + } + ] + }, + { + "key": "duration", + "name": "时长", + "value": [ + { + "n": "全部", + "v": "0" + }, + { + "n": "60分钟以上", + "v": "4" + }, + { + "n": "30~60分钟", + "v": "3" + }, + { + "n": "10~30分钟", + "v": "2" + }, + { + "n": "10分钟以下", + "v": "1" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/lrzy/db/movie_b8b5e.db b/lrzy/db/movie_b8b5e.db new file mode 100644 index 0000000..901d671 Binary files /dev/null and b/lrzy/db/movie_b8b5e.db differ diff --git a/lrzy/db/song_b4d4b.db b/lrzy/db/song_b4d4b.db new file mode 100644 index 0000000..34bf430 Binary files /dev/null and b/lrzy/db/song_b4d4b.db differ diff --git a/lrzy/jar/dongli-spider.jar b/lrzy/jar/dongli-spider.jar new file mode 100644 index 0000000..44bb8e9 Binary files /dev/null and b/lrzy/jar/dongli-spider.jar differ diff --git a/lrzy/js.json b/lrzy/js.json new file mode 100644 index 0000000..0235835 --- /dev/null +++ b/lrzy/js.json @@ -0,0 +1,114 @@ +{ + "logo": "./assets/logo2025121201.png", + "spider": "./jar/dongli-spider.jar", + "sites": [ + { + "key": "ylsp", + "name": "永乐视频", + "type": 3, + "api": "./js/永乐视频.js", + "searchable": 1, + "changeable": 1 + } + ], + "headers": [ + { + "host": "mgtv.ottiptv.cc", + "header": { + "User-Agent": "okHttp/Mod-1.4.0.0", + "Referer": "https://mgtv.ottiptv.cc/" + } + } + ], + "lives": [ + { + "name": "冰茶", + "type": 0, + "playerType": 2, + "url": "https://fy.188766.xyz/?ip=&mima=mianfeidehaimaiqian&json=true", + "ua": "bingcha/1.1(mianfeifenxiang)" + } + ], + "parses": [ + { + "name": "解析聚合", + "type": 3, + "url": "Web" + }, + { + "name": "777", + "type": 0, + "url": "https://www.huaqi.live/?url=" + }, + { + "name": "jsonplayer", + "type": 0, + "url": "https://jx.jsonplayer.com/player/?url=" + }, + { + "name": "xmflv", + "type": 0, + "url": "https://jx.xmflv.com/?url=" + } + ], + "flags": [ + "youku", + "tudou", + "qq", + "qiyi", + "iqiyi", + "leshi", + "letv", + "sohu", + "imgo", + "mgtv", + "bilibili", + "pptv", + "PPTV", + "migu" + ], + "doh": [ + { + "name": "Google", + "url": "https://dns.google/dns-query", + "ips": [ + "8.8.4.4", + "8.8.8.8" + ] + }, + { + "name": "Cloudflare", + "url": "https://cloudflare-dns.com/dns-query", + "ips": [ + "1.1.1.1", + "1.0.0.1", + "2606:4700:4700::1111", + "2606:4700:4700::1001" + ] + }, + { + "name": "AdGuard", + "url": "https://dns.adguard.com/dns-query", + "ips": [ + "94.140.14.140", + "94.140.14.141" + ] + }, + { + "name": "DNSWatch", + "url": "https://resolver2.dns.watch/dns-query", + "ips": [ + "84.200.69.80", + "84.200.70.40" + ] + }, + { + "name": "Quad9", + "url": "https://dns.quad9.net/dns-query", + "ips": [ + "9.9.9.9", + "149.112.112.112" + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/js/永乐视频.js b/lrzy/js/永乐视频.js new file mode 100644 index 0000000..5068314 --- /dev/null +++ b/lrzy/js/永乐视频.js @@ -0,0 +1,107 @@ +let host = 'https://www.ylys.tv'; +let headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "Referer": host + "/" +}; + +async function init(cfg) {} + +/** + * 通用解析:不做过滤,不做干扰 + */ +function getList(html) { + let videos = []; + let items = pdfa(html, ".module-item,.module-card-item"); + items.forEach(it => { + let idMatch = it.match(/detail\/(\d+)/); + let nameMatch = it.match(/title="(.*?)"/) || it.match(/(.*?)<\/strong>/); + let picMatch = it.match(/data-original="(.*?)"/) || it.match(/src="(.*?)"/); + + if (idMatch && nameMatch) { + let pic = picMatch ? (picMatch[1] || picMatch[2]) : ""; + videos.push({ + "vod_id": idMatch[1], + "vod_name": nameMatch[1].replace(/<.*?>/g, ""), + "vod_pic": pic.startsWith('/') ? host + pic : pic, + "vod_remarks": (it.match(/module-item-note">(.*?)<\/div>/) || ["",""])[1].replace(/<.*?>/g, "") + }); + } + }); + return videos; +} + +async function home(filter) { + return JSON.stringify({ + "class": [ + {"type_id":"1","type_name":"电影"}, + {"type_id":"2","type_name":"剧集"}, + {"type_id":"3","type_name":"综艺"}, + {"type_id":"4","type_name":"动漫"} + ], + "filters": { + "1":[{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"动作片","v":"6"},{"n":"喜剧片","v":"7"},{"n":"爱情片","v":"8"},{"n":"科幻片","v":"9"},{"n":"恐怖片","v":"11"}]}], + "2":[{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"国产剧","v":"13"},{"n":"港台剧","v":"14"},{"n":"日剧","v":"15"},{"n":"韩剧","v":"33"},{"n":"欧美剧","v":"16"}]}], + "3":[{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"内地综艺","v":"27"},{"n":"港台综艺","v":"28"},{"n":"日本综艺","v":"29"},{"n":"韩国综艺","v":"36"}]}], + "4":[{"key":"class","name":"类型","value":[{"n":"全部","v":""},{"n":"国产动漫","v":"31"},{"n":"日本动漫","v":"32"},{"n":"欧美动漫","v":"42"},{"n":"其他动漫","v":"43"}]}] + } + }); +} + +async function homeVod() { + let resp = await req(host, { headers: headers }); + return JSON.stringify({ list: getList(resp.content) }); +} + +async function category(tid, pg, filter, extend) { + let p = pg || 1; + let targetId = (extend && extend.class) ? extend.class : tid; + let url = host + "/vodtype/" + targetId + "/" + (parseInt(p) > 1 ? "page/" + p + "/" : ""); + let resp = await req(url, { headers: headers }); + return JSON.stringify({ + "list": getList(resp.content), + "page": parseInt(p) + }); +} + +async function detail(id) { + let url = host + '/voddetail/' + id + '/'; + let resp = await req(url, { headers: headers }); + let html = resp.content; + + let playFrom = pdfa(html, ".module-tab-item").map(it => (it.match(/(.*?)<\/span>/) || ["","线路"])[1]).join('$$$'); + let playUrl = pdfa(html, ".module-play-list-content").map(list => + pdfa(list, "a").map(a => { + let n = (a.match(/(.*?)<\/span>/) || ["","播放"])[1]; + let v = a.match(/href="\/play\/(.*?)\/"/); + return n + '$' + (v ? v[1] : ""); + }).join('#') + ).join('$$$'); + + return JSON.stringify({ + list: [{ + 'vod_id': id, + 'vod_name': (html.match(/

(.*?)<\/h1>/) || ["", ""])[1], + 'vod_pic': (html.match(/data-original="(.*?)"/) || ["", ""])[1], + 'vod_content': (html.match(/introduction-content">.*?

(.*?)<\/p>/s) || ["", ""])[1].replace(/<.*?>/g, ""), + 'vod_play_from': playFrom, + 'vod_play_url': playUrl + }] + }); +} + +async function search(wd, quick, pg) { + let p = pg || 1; + let url = host + "/vodsearch/" + encodeURIComponent(wd) + "-------------/" + (parseInt(p) > 1 ? "page/" + p + "/" : ""); + let resp = await req(url, { headers: headers }); + return JSON.stringify({ list: getList(resp.content) }); +} + +async function play(flag, id, flags) { + let url = host + "/play/" + id + "/"; + let resp = await req(url, { headers: headers }); + let m3u8 = resp.content.match(/"url":"([^"]+\.m3u8)"/); + if (m3u8) return JSON.stringify({ parse: 0, url: m3u8[1].replace(/\\/g, ""), header: headers }); + return JSON.stringify({ parse: 1, url: url, header: headers }); +} + +export default { init, home, homeVod, category, detail, search, play }; diff --git a/lrzy/py.json b/lrzy/py.json new file mode 100644 index 0000000..2da1839 --- /dev/null +++ b/lrzy/py.json @@ -0,0 +1,406 @@ +{ + "logo": "./assets/logo2025121201.png", + "spider": "./jar/dongli-spider.jar", + "sites": [ + { + "key": "py_fk", + "name": "飞快TV", + "type": 3, + "api": "./py/飞快TV.py", + "searchable": 1, + "quickSearch": 0, + "filterable": 0, + "changeable": 0 + }, + { + "key": "py_xiong_di_ying_shi", + "name": "兄弟影视", + "type": 3, + "api": "./py/兄弟影视.min.py", + "searchable": 1, + "quickSearch": 0, + "filterable": 0, + "changeable": 0 + }, + { + "key": "哔哩直播", + "name": "哔哩直播", + "type": 3, + "api": "./py/哔哩直播.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "4KVM", + "name": "4KVM", + "type": 3, + "api": "./py/4KVM.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "小苹果", + "name": "小苹果", + "type": 3, + "api": "./py/小苹果.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "小鸡暴走", + "name": "小鸡暴走", + "type": 3, + "api": "./py/小鸡暴走.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "hohaiemby", + "name": "hohai|EMBY", + "type": 3, + "api": "./py/emby.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 1, + "ext": { + "server": "https://emby.hohai.eu.org:443", + "username": "chuxin666", + "password": "ycc123456", + "proxy": "", + "thread": 0, + "device_name": "My Computer", + "client": "Hills Windows", + "client_version": "0.2.2", + "device_id": "a9f74849-83d5-4a28-8b85-a087af1402e3" + } + }, + { + "key": "今日看料", + "name": "今日看料", + "type": 3, + "api": "./py/今日看料.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 1 + }, + { + "key": "UVod", + "name": "🧱UVod", + "type": 3, + "api": "./py/UVod.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 1 + }, + { + "key": "努努影院", + "name": "🧱努努影院", + "type": 3, + "api": "./py/努努影院.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 1 + }, + { + "key": "饭团影视", + "name": "饭团影视", + "type": 3, + "api": "./py/饭团影视.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 1 + }, + { + "key": "金牌", + "name": "金牌", + "type": 3, + "api": "./py/金牌.py", + "searchable": 1, + "quickSearch": 1, + "filterable": 1, + "changeable": 1 + }, + { + "key": "4K影视", + "name": "4K影视", + "type": 3, + "api": "./py/4K影视.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "HMDJ", + "name": "HMDJ", + "type": 3, + "api": "./py/HMDJ.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "LSYS", + "name": "LSYS", + "type": 3, + "api": "./py/LSYS.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "YYMP3音乐网", + "name": "YYMP3音乐网", + "type": 3, + "api": "./py/YYMP3音乐网.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "云端影视", + "name": "云端影视", + "type": 3, + "api": "./py/云端影视.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "优酷视频", + "name": "优酷视频", + "type": 3, + "api": "./py/优酷视频.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "剧王短剧", + "name": "剧王短剧", + "type": 3, + "api": "./py/剧王短剧.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "奇优动漫", + "name": "奇优动漫", + "type": 3, + "api": "./py/奇优动漫.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "柯南影视", + "name": "柯南影视", + "type": 3, + "api": "./py/柯南影视.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "永乐视频", + "name": "永乐视频", + "type": 3, + "api": "./py/永乐视频.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "爱瓜影视", + "name": "🧱爱瓜影视", + "type": 3, + "api": "./py/爱瓜影视.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "猎手影视", + "name": "猎手影视", + "type": 3, + "api": "./py/猎手影视.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "甜圈短剧", + "name": "甜圈短剧", + "type": 3, + "api": "./py/甜圈短剧.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "电影猎手", + "name": "电影猎手", + "type": 3, + "api": "./py/电影猎手.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + }, + { + "key": "界影视", + "name": "界影视", + "type": 3, + "api": "./py/界影视.py", + "style": { + "type": "rect", + "ratio": 0.75 + }, + "changeable": 1 + } + ], + "headers": [ + { + "host": "mgtv.ottiptv.cc", + "header": { + "User-Agent": "okHttp/Mod-1.4.0.0", + "Referer": "https://mgtv.ottiptv.cc/" + } + } + ], + "lives": [ + { + "name": "冰茶", + "type": 0, + "playerType": 2, + "url": "https://fy.188766.xyz/?ip=&mima=mianfeidehaimaiqian&json=true", + "ua": "bingcha/1.1(mianfeifenxiang)" + } + ], + "parses": [ + { + "name": "解析聚合", + "type": 3, + "url": "Web" + }, + { + "name": "777", + "type": 0, + "url": "https://www.huaqi.live/?url=" + }, + { + "name": "jsonplayer", + "type": 0, + "url": "https://jx.jsonplayer.com/player/?url=" + }, + { + "name": "xmflv", + "type": 0, + "url": "https://jx.xmflv.com/?url=" + } + ], + "flags": [ + "youku", + "tudou", + "qq", + "qiyi", + "iqiyi", + "leshi", + "letv", + "sohu", + "imgo", + "mgtv", + "bilibili", + "pptv", + "PPTV", + "migu" + ], + "doh": [ + { + "name": "Google", + "url": "https://dns.google/dns-query", + "ips": [ + "8.8.4.4", + "8.8.8.8" + ] + }, + { + "name": "Cloudflare", + "url": "https://cloudflare-dns.com/dns-query", + "ips": [ + "1.1.1.1", + "1.0.0.1", + "2606:4700:4700::1111", + "2606:4700:4700::1001" + ] + }, + { + "name": "AdGuard", + "url": "https://dns.adguard.com/dns-query", + "ips": [ + "94.140.14.140", + "94.140.14.141" + ] + }, + { + "name": "DNSWatch", + "url": "https://resolver2.dns.watch/dns-query", + "ips": [ + "84.200.69.80", + "84.200.70.40" + ] + }, + { + "name": "Quad9", + "url": "https://dns.quad9.net/dns-query", + "ips": [ + "9.9.9.9", + "149.112.112.112" + ] + } + ] +} \ No newline at end of file diff --git a/lrzy/py/4KVM.py b/lrzy/py/4KVM.py new file mode 100644 index 0000000..1bc15ba --- /dev/null +++ b/lrzy/py/4KVM.py @@ -0,0 +1,432 @@ +# -*- coding: utf-8 -*- +# 4K影视插件 - 优化版本 +import re +import sys +import json +from pyquery import PyQuery as pq +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + pass + + def getName(self): + return "4k影视" + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host = 'https://www.4kvm.org' + + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Accept-Encoding': 'gzip, deflate', + 'Cache-Control': 'no-cache', + 'Pragma': 'no-cache', + 'Sec-Ch-Ua': '"Not/A)Brand";v="8", "Chromium";v="134", "Google Chrome";v="134"', + 'Sec-Ch-Ua-Mobile': '?0', + 'Sec-Ch-Ua-Platform': '"macOS"', + 'Sec-Fetch-Dest': 'document', + 'Sec-Fetch-Mode': 'navigate', + 'Sec-Fetch-Site': 'none', + 'Sec-Fetch-User': '?1', + 'Upgrade-Insecure-Requests': '1', + } + + # 公共方法 + def _normalize_url(self, url): + """标准化URL处理""" + if not url: + return url + if url.startswith('//'): + return f"https:{url}" + elif url.startswith('/'): + return f"{self.host}{url}" + return url + + def _extract_video_basic(self, item): + """提取视频基本信息""" + try: + link = self._normalize_url(item('a').attr('href') or item('h3 a').attr('href') or item('.data h3 a').attr('href')) + if not link: + return None + + title = (item('h3').text().strip() or item('.data h3').text().strip() or + item('img').attr('alt') or item('a').attr('title') or '未知标题') + + img = self._normalize_url(item('img').attr('src') or item('img').attr('data-src')) + + # 简化备注提取 + remarks = (item('.rating, .imdb, .vote').text().strip() or + item('.year, .date, span').text().strip() or + item('.type, .genre, .tag').text().strip()) + + return { + 'vod_id': link, + 'vod_name': title, + 'vod_pic': img or '', + 'vod_remarks': remarks, + 'vod_year': '' + } + except: + return None + + def _get_episode_count(self, season_data, page_html): + """智能检测集数""" + # 方法1: 精确容器检测 + episode_container = season_data('.jujiepisodios') + if episode_container: + episode_links = episode_container('a') + episode_numbers = [int(link.text().strip()) for link in episode_links.items() + if link.text().strip().isdigit() and 1 <= int(link.text().strip()) <= 200] + if episode_numbers: + return max(episode_numbers) + + # 方法2: JavaScript数据提取 + video_matches = re.findall(r'video.*?=.*?\[(.*?)\]', page_html, re.IGNORECASE | re.DOTALL) + for match in video_matches: + if '"name":' in match: + episode_names = re.findall(r'"name"\s*:\s*(\d+)', match) + if len(episode_names) >= 5: + episode_numbers = sorted(set(int(name) for name in episode_names)) + if episode_numbers[0] == 1 and episode_numbers[-1] - episode_numbers[0] == len(episode_numbers) - 1: + return max(episode_numbers) + + # 方法3: 文本模式匹配 + page_text = season_data.text() + for pattern in [r'共(\d+)集', r'全(\d+)集', r'更新至(\d+)集', r'第(\d+)集']: + matches = re.findall(pattern, page_text) + if matches: + return max(int(m) for m in matches if m.isdigit()) + + # 默认值 + return 24 if season_data('iframe, video, .player') else 1 + + def homeContent(self, filter): + try: + data = self.getpq(self.fetch(self.host, headers=self.headers).text) + classes = [] + + # 简化分类提取 + nav_items = data('header .head-main-nav ul.main-header > li') + for k in nav_items.items(): + main_link = k.children('a').eq(0) + link = main_link.attr('href') + name = main_link.text().strip() + + if link and name and name not in ['首页', '影片下载']: + link = self._normalize_url(link) + class_info = {'type_name': name, 'type_id': link} + if '电视剧' in name or 'tvshows' in link: + class_info['filter_type'] = 'tvshows' + classes.append(class_info) + + # 子分类 + for sub_item in k('ul li').items(): + sub_link = self._normalize_url(sub_item('a').attr('href')) + sub_name = sub_item('a').text().strip() + if sub_link and sub_name: + sub_class_info = {'type_name': f"{name}-{sub_name}", 'type_id': sub_link} + if '电视剧' in name or 'tvshows' in sub_link: + sub_class_info['filter_type'] = 'tvshows' + classes.append(sub_class_info) + + return {'class': classes, 'list': self.getHomeList(data)} + except Exception as e: + return {'class': [], 'list': []} + + def homeVideoContent(self): + pass + + def categoryContent(self, tid, pg, filter, extend): + try: + url = tid if pg == '1' else f"{tid}/page/{pg}" if '?' not in tid else f"{tid}&page={pg}" + data = self.getpq(self.fetch(url, headers=self.headers).text) + + video_list = self.getVideoList(data) + if '电视剧' in url or 'tvshows' in url: + video_list = self.filterTVShowsOnly(video_list) + + return {'list': video_list, 'page': int(pg), 'pagecount': 9999, 'limit': 30, 'total': 999999} + except Exception as e: + return {'list': [], 'page': int(pg), 'pagecount': 1, 'limit': 30, 'total': 0} + + def detailContent(self, ids): + try: + first_id = next(iter(ids)) if hasattr(ids, '__iter__') and not isinstance(ids, str) else ids + data = self.getpq(self.fetch(first_id, headers=self.headers).text) + + # 基本信息提取 + vod = { + 'vod_id': first_id, + 'vod_name': data('.sheader h1, h1').text().strip(), + 'vod_pic': self._normalize_url(data('.sheader .poster img, .poster img').attr('src')), + 'vod_content': data('.sbox .wp-content, #info .wp-content').text().strip(), + 'vod_year': '', 'vod_area': '', 'vod_remarks': '', 'vod_actor': '', 'vod_director': '' + } + + # 提取分类 + genres = data('.sgeneros a') + if genres: + vod['type_name'] = ', '.join(g.text() for g in genres.items()) + + # 播放链接处理 + play_options = data('#playeroptions ul li, .dooplay_player_option') + if play_options: + play_links = self._extract_play_options(play_options, first_id) + else: + season_links = data('.seasons-list a, .season-item a, .se-c a, .se-a a, .seasons a') + play_links = self.getSeasonEpisodes(season_links) if season_links else [f"播放${first_id}"] + + vod['vod_play_from'] = '老僧酿酒' + vod['vod_play_url'] = '#'.join(play_links) + + return {'list': [vod]} + except Exception as e: + return {'list': []} + + def _extract_play_options(self, play_options, first_id): + """提取播放选项""" + play_links = [] + for option in play_options.items(): + title = option('.title, span.title').text().strip() or '播放' + server = option('.server, span.server').text().strip() + if server: + title = f"{title}-{server}" + + data_post = option.attr('data-post') + data_nume = option.attr('data-nume') + data_type = option.attr('data-type') + + if data_post and data_nume: + play_url = f"{first_id}?post={data_post}&nume={data_nume}&type={data_type}" + play_links.append(f"{title}${play_url}") + + return play_links + + def searchContent(self, key, quick, pg="1"): + try: + search_url = f"{self.host}/xssearch?s={key}" + if pg != "1": + search_url += f"&p={pg}" + + data = self.getpq(self.fetch(search_url, headers=self.headers).text) + raw_results = self.getVideoList(data) + filtered_results = self.filterSearchResults(raw_results, key) + + return {'list': filtered_results, 'page': int(pg)} + except Exception as e: + return {'list': [], 'page': int(pg)} + + def playerContent(self, flag, id, vipFlags): + try: + # 解析播放参数 + data_post = data_nume = data_type = None + if '?' in id: + base_url, params = id.split('?', 1) + param_dict = dict(param.split('=', 1) for param in params.split('&') if '=' in param) + data_post = param_dict.get('post') + data_nume = param_dict.get('nume') + data_type = param_dict.get('type') + + # API调用 + if data_post and data_nume: + try: + api_url = f"{self.host}/wp-json/dooplayer/v1/post/{data_post}" + api_response = self.fetch(api_url, headers=self.headers, + params={'type': data_type or 'movie', 'source': data_nume}) + if api_response.status_code == 200: + api_data = api_response.json() + if 'embed_url' in api_data: + embed_url = api_data['embed_url'] + parse_flag = 0 if any(ext in embed_url.lower() for ext in ['.m3u8', '.mp4', '.flv', '.avi']) else 1 + return {'parse': parse_flag, 'url': embed_url, 'header': self.headers} + except: + pass + + # 页面解析回退 + page_url = base_url if '?' in id else id + data = self.getpq(self.fetch(page_url, headers=self.headers).text) + + # 查找播放源 + iframe = data('iframe.metaframe, .dooplay_player iframe, .player iframe').attr('src') + if iframe: + iframe = self._normalize_url(iframe) + parse_flag = 0 if any(ext in iframe.lower() for ext in ['.m3u8', '.mp4', '.flv']) else 1 + return {'parse': parse_flag, 'url': iframe, 'header': self.headers} + + video_src = self._normalize_url(data('video source, video').attr('src')) + if video_src: + return {'parse': 0, 'url': video_src, 'header': self.headers} + + return {'parse': 1, 'url': page_url, 'header': self.headers} + + except Exception as e: + return {'parse': 1, 'url': id, 'header': self.headers} + + def localProxy(self, param): + pass + + def liveContent(self, url): + pass + + def getHomeList(self, data): + """获取首页推荐列表""" + videos = [] + items = data('article, .module .content .items .item, .movies-list article') + for item in items.items(): + video_info = self._extract_video_basic(item) + if video_info: + videos.append(video_info) + return videos + + def getVideoList(self, data): + """获取视频列表""" + videos = [] + items = data('article, .items article, .content article, .search-results article') + for item in items.items(): + video_info = self._extract_video_basic(item) + if video_info: + videos.append(video_info) + return videos + + def extractVideoInfo(self, item): + """兼容性方法,已优化为_extract_video_basic""" + return self._extract_video_basic(item) + + def getpq(self, text): + """创建PyQuery对象""" + try: + return pq(text) + except: + try: + return pq(text.encode('utf-8')) + except: + return pq('') + + def filterSearchResults(self, results, search_key): + """过滤和排序搜索结果""" + if not results or not search_key: + return results + + search_key_lower = search_key.lower().strip() + search_words = search_key_lower.split() + scored_results = [] + + for result in results: + title = result.get('vod_name', '').lower() + + # 计算相关性分数 + if search_key_lower == title: + score = 100 + elif search_key_lower in title: + score = 80 + elif title.startswith(search_key_lower): + score = 70 + elif all(word in title for word in search_words): + score = 60 + else: + word_matches = sum(1 for word in search_words if word in title) + if word_matches > 0: + score = 30 + (word_matches * 10) + else: + continue + + # 内容类型加分 + if '剧' in search_key_lower and 'tvshows' in result.get('vod_id', ''): + score += 5 + elif '电影' in search_key_lower and 'movies' in result.get('vod_id', ''): + score += 5 + + scored_results.append((score, result)) + + # 排序和过滤 + scored_results.sort(key=lambda x: x[0], reverse=True) + min_score = 30 if len(search_words) > 1 else 40 + filtered = [result for score, result in scored_results if score >= min_score] + + # 如果结果太少,放宽标准 + if len(filtered) < 3 and len(scored_results) > 3: + filtered = [result for score, result in scored_results[:10]] + + return filtered + + def filterTVShowsOnly(self, video_list): + """过滤电视剧分类中的电影内容""" + if not video_list: + return video_list + + filtered_videos = [] + movie_keywords = ['/movies/', '/movie/', 'Movie', '电影'] + tvshow_keywords = ['/tvshows/', '/tvshow/', '/seasons/', 'TV', '剧', '季', '集'] + + for video in video_list: + vod_id = video.get('vod_id', '') + vod_name = video.get('vod_name', '') + vod_remarks = video.get('vod_remarks', '') + + # 检查是否是电影 + is_movie = any(keyword in vod_id for keyword in movie_keywords[:3]) + if is_movie: + continue + + # 检查是否是电视剧 + is_tvshow = (any(keyword in vod_id for keyword in tvshow_keywords[:3]) or + any(keyword in vod_name + vod_remarks for keyword in tvshow_keywords[3:])) + + if is_tvshow or not is_movie: + filtered_videos.append(video) + + return filtered_videos + + def getSeasonEpisodes(self, season_links): + """获取电视剧每个季的集数信息""" + play_links = [] + + try: + for season in season_links.items(): + season_title = season.text().strip() or '第1季' + season_url = self._normalize_url(season.attr('href')) + + if not season_url: + continue + + try: + season_resp = self.fetch(season_url, headers=self.headers) + if season_resp.status_code == 200: + season_data = self.getpq(season_resp.text) + episode_count = self._get_episode_count(season_data, season_resp.text) + + # 限制集数范围(提高上限以支持长篇动漫) + episode_count = min(max(episode_count, 1), 500) + + # 生成播放链接 + if episode_count == 1: + play_links.append(f"{season_title}${season_url}") + else: + clean_title = season_title.split('已完結')[0].split('更新')[0].strip() + for ep_num in range(1, episode_count + 1): + episode_title = f"{clean_title} 第{ep_num}集" + episode_url = f"{season_url}?ep={ep_num}" + play_links.append(f"{episode_title}${episode_url}") + else: + play_links.append(f"{season_title}${season_url}") + + except Exception: + play_links.append(f"{season_title}${season_url}") + + except Exception: + pass + + return play_links diff --git a/lrzy/py/4K影视.py b/lrzy/py/4K影视.py new file mode 100644 index 0000000..ce37aa4 --- /dev/null +++ b/lrzy/py/4K影视.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import sys +from pyquery import PyQuery as pq +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + headers = { + 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="134", "Google Chrome";v="134"', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'document', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + } + + host = "https://4k-av.com" + + def homeContent(self, filter): + data=self.getpq() + result = {} + classes = [] + for k in list(data('#category ul li').items())[:-1]: + classes.append({ + 'type_name': k.text(), + 'type_id': k('a').attr('href') + }) + result['class'] = classes + result['list'] = self.getlist(data('#MainContent_scrollul ul li'),'.poster span') + return result + + def homeVideoContent(self): + pass + + def categoryContent(self, tid, pg, filter, extend): + data=self.getpq(f"{tid}page-{pg}.html") + result = {} + result['list'] = self.getlist(data('#MainContent_newestlist .virow .NTMitem')) + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + data=self.getpq(ids[0]) + v=data('#videoinfo') + vod = { + 'type_name': v('#MainContent_tags.tags a').text(), + 'vod_year': v('#MainContent_videodetail.videodetail a').text(), + 'vod_remarks': v('#MainContent_titleh12 h2').text(), + 'vod_content': v('p.cnline').text(), + 'vod_play_from': '4KAV', + 'vod_play_url': '' + } + vlist=data('#rtlist li') + if vlist: + c=[f"{i('span').text()}${i('a').attr('href')}" for i in list(vlist.items())[1:]] + c.insert(0,f"{vlist.eq(0)('span').text()}${ids[0]}") + vod['vod_play_url'] = '#'.join(c) + else: + vod['vod_play_url'] = f"{data('#tophead h1').text()}${ids[0]}" + return {'list':[vod]} + + def searchContent(self, key, quick, pg="1"): + data=self.getpq(f"/s?k={key}") + return {'list':self.getlist(data('#MainContent_newestlist .virow.search .NTMitem.Main'))} + + def playerContent(self, flag, id, vipFlags): + try: + data=self.getpq(id) + p,url=0,data('#MainContent_videowindow source').attr('src') + if not url:raise Exception("未找到播放地址") + except Exception as e: + p,url=1,f"{self.host}{id}" + headers = { + 'origin': self.host, + 'referer': f'{self.host}/', + 'sec-ch-ua-platform': '"macOS"', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + } + return {'parse': p, 'url': url, 'header': headers} + + def localProxy(self, param): + pass + + def liveContent(self, url): + pass + + def getlist(self,data,y='.resyear label[title="分辨率"]'): + videos = [] + for i in data.items(): + ns = i('.title h2').text().split(' ') + videos.append({ + 'vod_id': i('.title a').attr('href'), + 'vod_name': ns[0], + 'vod_pic': i('.poster img').attr('src'), + 'vod_remarks': ns[-1] if len(ns) > 1 else '', + 'vod_year': i(y).text() + }) + return videos + + def getpq(self, path=''): + url=f"{self.host}{path}" + data=self.fetch(url,headers=self.headers).text + try: + return pq(data) + except Exception as e: + print(f"{str(e)}") + return pq(data.encode('utf-8')) \ No newline at end of file diff --git a/lrzy/py/DSYS.py b/lrzy/py/DSYS.py new file mode 100644 index 0000000..f71349d --- /dev/null +++ b/lrzy/py/DSYS.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import time +import uuid +from base64 import b64decode, b64encode +import json +import sys +from urllib.parse import urlparse, urlunparse +from Crypto.Cipher import AES +from Crypto.Hash import MD5 +from Crypto.Util.Padding import unpad, pad +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host = "https://api.230110.xyz" + + phost = "https://cdn.230110.xyz" + + headers = { + 'origin': host, + 'referer': f'{host}/', + 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.8 Mobile/15E148 Safari/604.1', + } + + def homeContent(self, filter): + data='9XSPkyFMrOOG34JSg//ZosMof45cyBo9hwZMZ5rvI6Yz/ZZlXWIf8/644OzwW+FNIOdJ61R/Lxjy1tqN+ZzokxtiVzb8LjYAkh6GFudwAUXFt9yS1ZjAxC3tDKrQsJQLk3nym0s00DBBzLBntRBDFz7nbba+OOBuQOZpL3CESGL42l4opdoViQLhO/dIizY1kIOk2NxxpDC9Z751gPl1ctHWuLWhuLG/QWgNWi/iHScjKrMHJKcC9GQHst/4Q3dgZ03eQIIVB6jvoV1XXoBCz6fjM/jM3BXpzSttT4Stglwy93gWuNWuZiKypHK2Q0lO10oM0ceRW2a0fPGId+rNYMRO3cR/C0ZueD4cmTAVOuxVr9ZZSP8/nhD0bHyAPONXtchIDJb0O/kdFHk2KTJfQ5q4fHOyzezczc4iQDV/R0S8cGZKM14MF+wytA/iljfj43H0UYqq5pM+MCUGRTdYEtuxCp0+A+DiOhNZwY/Km/TgBoGZQWGbpljJ2LAVnWhxX+ickLH7zuR/FeIwP/R8zOuR+8C8UlT9eHTqtvfNzaGdFxt316atHy8TNjRO7J5a177mqsHs3ziG0toDDzLDCbhRUjFgVA3ktahhXiWaaCo/ZGSJAA8TDO5DYqnJ0JDaX0ILPj8QB5zxrHYmRE8PboIr3RBAjz1sREbaHfjrUjoh29ePhlolLV00EvgoxP5knaqt5Ws/sq5IG57qKCAPgqXzblPLHToJGBtukKhLp8jbGJrkb6PVn4/jysks0NGE' + return {'class':self.aes(data,False)} + + def homeVideoContent(self): + pass + + def categoryContent(self, tid, pg, filter, extend): + data = {"q": "", "filter": [f"type_id = {tid}"], "offset": (int(pg)-1) * 24, "limit": 24, "sort": ["video_time:desc"],"lang": "zh-cn", "route": "/videos/search"} + result = {} + if 'skey_' in tid:return self.searchContent(tid.split('_')[-1], True, pg) + result['list'] = self.getl(self.getdata(data)) + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + data={"limit":1,"filter":[f"video_id = {ids[0]}"],"lang":"zh-cn","route":"/videos/search"} + res = self.getdata(data)[0] + purl=urlunparse(urlparse(self.phost)._replace(path=urlparse(res.get('video_url')).path)) + vod = { + 'vod_play_from': 'dsysav', + 'vod_play_url': f"{res.get('video_duration')}${purl}" + } + if res.get('video_tag'): + clist = [] + tags=res['video_tag'].split(',') + for k in tags: + clist.append('[a=cr:' + json.dumps({'id': f'skey_{k}', 'name': k}) + '/]' + k + '[/a]') + vod['vod_content'] = ' '.join(clist) + return {'list':[vod]} + + def searchContent(self, key, quick, pg="1"): + data={"q":key,"filter":[],"offset":(int(pg)-1) * 24,"limit":24,"sort":["video_time:desc"],"lang":"zh-cn","route":"/videos/search"} + return {'list':self.getl(self.getdata(data)),'page':pg} + + def playerContent(self, flag, id, vipFlags): + if id.endswith('.mpd'): + id=f"{self.getProxyUrl()}&url={self.e64(id)}&type=mpd" + return {'parse': 0, 'url': id, 'header':self.headers} + + def localProxy(self, param): + if param.get('type') and param['type']=='mpd': + url = self.d64(param.get('url')) + ids=url.split('/') + id=f"{ids[-3]}/{ids[-2]}/" + xpu = f"{self.getProxyUrl()}&path=".replace('&', '&') + data = self.fetch(url, headers=self.headers).text + data = data.replace('initialization="', f'initialization="{xpu}{id}').replace('media="',f'media="{xpu}{id}') + return [200,'application/octet-stream',data] + else: + hsign=self.md5(f"AjPuom638LmWfWyeM5YueKuJ9PuWLdRn/mpd/{param.get('path')}1767196800") + bytes_data = bytes.fromhex(hsign) + sign = b64encode(bytes_data).decode('utf-8').replace('=','').replace('+','-').replace('/','_') + url=f"{self.phost}/mpd/{param.get('path')}?sign={sign}&expire=1767196800" + return [302,'text/plain',None,{'Location':url}] + + def liveContent(self, url): + pass + + def aes(self, text, operation=True): + key = b'OPQT123412FRANME' + iv = b'MRDCQP12QPM13412' + cipher = AES.new(key, AES.MODE_CBC, iv) + if operation: + ct_bytes = cipher.encrypt(pad(json.dumps(text).encode("utf-8"), AES.block_size)) + ct = b64encode(ct_bytes).decode("utf-8") + return ct + else: + pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size) + return json.loads(pt.decode("utf-8")) + + def e64(self, text): + try: + text_bytes = text.encode('utf-8') + encoded_bytes = b64encode(text_bytes) + return encoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64编码错误: {str(e)}") + return "" + + def d64(self,encoded_text): + try: + encoded_bytes = encoded_text.encode('utf-8') + decoded_bytes = b64decode(encoded_bytes) + return decoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64解码错误: {str(e)}") + return "" + + def md5(self, text): + h = MD5.new() + h.update(text.encode('utf-8')) + return h.hexdigest() + + def getl(self,data): + videos = [] + for i in data: + img = i.get('video_cover') + if img and 'http' in img:img = urlunparse(urlparse(self.phost)._replace(path=urlparse(img).path)) + videos.append({ + 'vod_id': i.get('video_id'), + 'vod_name': i.get('video_title'), + 'vod_pic': img, + 'vod_remarks': i.get('video_duration'), + 'style': {"type": "rect", "ratio": 1.33} + }) + return videos + + def getdata(self,data): + uid = str(uuid.uuid4()) + t = int(time.time()) + json_data = { + 'sign': self.md5(f"{self.e64(json.dumps(data))}{uid}{t}AjPuom638LmWfWyeM5YueKuJ9PuWLdRn"), + 'nonce': uid, + 'timestamp': t, + 'data': self.aes(data), + } + res = self.post(f"{self.host}/v1", json=json_data, headers=self.headers).json() + res = self.aes(res['data'], False) + return res diff --git a/lrzy/py/HMDJ.py b/lrzy/py/HMDJ.py new file mode 100644 index 0000000..0085507 --- /dev/null +++ b/lrzy/py/HMDJ.py @@ -0,0 +1,380 @@ +# -*- coding: utf-8 -*- +import requests +import re +import json +import traceback +import sys +from urllib.parse import quote + +sys.path.append('../../') +try: + from base.spider import Spider +except ImportError: + # 定义一个基础接口类,用于本地测试 + class Spider: + def init(self, extend=""): + pass + +class Spider(Spider): + def __init__(self): + self.siteUrl = "https://www.kuaikaw.cn" + self.cateManual = { + "甜宠": "462", + "古装仙侠": "1102", + "现代言情": "1145", + "青春": "1170", + "豪门恩怨": "585", + "逆袭": "417-464", + "重生": "439-465", + "系统": "1159", + "总裁": "1147", + "职场商战": "943" + } + self.headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0", + "Referer": self.siteUrl, + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8" + } + + def getName(self): + return "河马短剧" + + def init(self, extend=""): + return + + def fetch(self, url, headers=None, retry=2): + """统一的网络请求接口""" + if headers is None: + headers = self.headers + + for i in range(retry + 1): + try: + response = requests.get(url, headers=headers, timeout=10, allow_redirects=True) + response.raise_for_status() + return response + except Exception as e: + if i == retry: + print(f"请求异常: {url}, 错误: {str(e)}") + return None + continue + + def isVideoFormat(self, url): + video_formats = ['.mp4', '.mkv', '.avi', '.wmv', '.m3u8', '.flv', '.rmvb'] + return any(format in url.lower() for format in video_formats) + + def manualVideoCheck(self): + return False + + def homeContent(self, filter): + result = {} + classes = [{'type_name': k, 'type_id': v} for k, v in self.cateManual.items()] + result['class'] = classes + + try: + result['list'] = self.homeVideoContent()['list'] + except: + result['list'] = [] + return result + + def homeVideoContent(self): + videos = [] + try: + response = self.fetch(self.siteUrl) + if not response: + return {'list': []} + + html_content = response.text + next_data_pattern = r'' + next_data_match = re.search(next_data_pattern, html_content, re.DOTALL) + if not next_data_match: + return {'list': []} + + next_data_json = json.loads(next_data_match.group(1)) + page_props = next_data_json.get("props", {}).get("pageProps", {}) + + # 处理轮播图数据 + if "bannerList" in page_props: + for banner in page_props["bannerList"]: + if banner.get("bookId"): + videos.append({ + "vod_id": f"/drama/{banner['bookId']}", + "vod_name": banner.get("bookName", ""), + "vod_pic": banner.get("coverWap", ""), + "vod_remarks": f"{banner.get('statusDesc', '')} {banner.get('totalChapterNum', '')}集".strip() + }) + + # 处理SEO分类推荐 + if "seoColumnVos" in page_props: + for column in page_props["seoColumnVos"]: + for book in column.get("bookInfos", []): + if book.get("bookId"): + videos.append({ + "vod_id": f"/drama/{book['bookId']}", + "vod_name": book.get("bookName", ""), + "vod_pic": book.get("coverWap", ""), + "vod_remarks": f"{book.get('statusDesc', '')} {book.get('totalChapterNum', '')}集".strip() + }) + + # 去重处理 + seen = set() + unique_videos = [] + for video in videos: + key = (video["vod_id"], video["vod_name"]) + if key not in seen: + seen.add(key) + unique_videos.append(video) + + except Exception as e: + print(f"获取首页推荐内容出错: {e}") + unique_videos = [] + + return {'list': unique_videos} + + def categoryContent(self, tid, pg, filter, extend): + result = {'list': [], 'page': pg, 'pagecount': 1, 'limit': 20, 'total': 0} + url = f"{self.siteUrl}/browse/{tid}/{pg}" + + response = self.fetch(url) + if not response: + return result + + html_content = response.text + next_data_match = re.search(r'', html_content, re.DOTALL) + if not next_data_match: + return result + + try: + next_data_json = json.loads(next_data_match.group(1)) + page_props = next_data_json.get("props", {}).get("pageProps", {}) + + current_page = page_props.get("page", 1) + total_pages = page_props.get("pages", 1) + book_list = page_props.get("bookList", []) + + videos = [] + for book in book_list: + if book.get("bookId"): + videos.append({ + "vod_id": f"/drama/{book['bookId']}", + "vod_name": book.get("bookName", ""), + "vod_pic": book.get("coverWap", ""), + "vod_remarks": f"{book.get('statusDesc', '')} {book.get('totalChapterNum', '')}集".strip() + }) + + result.update({ + 'list': videos, + 'page': int(current_page), + 'pagecount': total_pages, + 'limit': len(videos), + 'total': len(videos) * total_pages if videos else 0 + }) + + except Exception as e: + print(f"分类内容获取出错: {e}") + + return result + + def searchContent(self, key, quick, pg=1): + return self.searchContentPage(key, quick, pg) + + def searchContentPage(self, key, quick, pg=1): + result = {'list': [], 'page': pg, 'pagecount': 1, 'limit': 20, 'total': 0} + search_url = f"{self.siteUrl}/search?searchValue={quote(key)}&page={pg}" + + response = self.fetch(search_url) + if not response: + return result + + html_content = response.text + next_data_match = re.search(r'', html_content, re.DOTALL) + if not next_data_match: + return result + + try: + next_data_json = json.loads(next_data_match.group(1)) + page_props = next_data_json.get("props", {}).get("pageProps", {}) + + total_pages = page_props.get("pages", 1) + book_list = page_props.get("bookList", []) + + videos = [] + for book in book_list: + if book.get("bookId"): + videos.append({ + "vod_id": f"/drama/{book['bookId']}", + "vod_name": book.get("bookName", ""), + "vod_pic": book.get("coverWap", ""), + "vod_remarks": f"{book.get('statusDesc', '')} {book.get('totalChapterNum', '')}集".strip() + }) + + result.update({ + 'list': videos, + 'pagecount': total_pages, + 'total': len(videos) * total_pages if videos else 0 + }) + + except Exception as e: + print(f"搜索内容出错: {e}") + + return result + + def detailContent(self, ids): + result = {'list': []} + if not ids: + return result + + vod_id = ids[0] + if not vod_id.startswith('/drama/'): + vod_id = f'/drama/{vod_id}' + + drama_url = f"{self.siteUrl}{vod_id}" + response = self.fetch(drama_url) + if not response: + return result + + html = response.text + next_data_match = re.search(r'', html, re.DOTALL) + if not next_data_match: + return result + + try: + next_data = json.loads(next_data_match.group(1)) + page_props = next_data.get("props", {}).get("pageProps", {}) + book_info = page_props.get("bookInfoVo", {}) + chapter_list = page_props.get("chapterList", []) + + if not book_info.get("bookId"): + return result + + # 基本信息 + categories = [c.get("name", "") for c in book_info.get("categoryList", [])] + performers = [p.get("name", "") for p in book_info.get("performerList", [])] + + vod = { + "vod_id": vod_id, + "vod_name": book_info.get("title", ""), + "vod_pic": book_info.get("coverWap", ""), + "type_name": ",".join(categories), + "vod_year": "", + "vod_area": book_info.get("countryName", ""), + "vod_remarks": f"{book_info.get('statusDesc', '')} {book_info.get('totalChapterNum', '')}集".strip(), + "vod_actor": ", ".join(performers), + "vod_director": "", + "vod_content": book_info.get("introduction", "") + } + + # 处理剧集 + play_urls = self.processEpisodes(vod_id, chapter_list) + if play_urls: + vod['vod_play_from'] = '河马剧场' + vod['vod_play_url'] = '$$$'.join(play_urls) + + result['list'] = [vod] + + except Exception as e: + print(f"详情页解析出错: {e}") + traceback.print_exc() + + return result + + def processEpisodes(self, vod_id, chapter_list): + play_urls = [] + episodes = [] + + for chapter in chapter_list: + chapter_id = chapter.get("chapterId", "") + chapter_name = chapter.get("chapterName", "") + + if not chapter_id or not chapter_name: + continue + + # 尝试获取直接视频链接 + video_url = self.getDirectVideoUrl(chapter) + if video_url: + episodes.append(f"{chapter_name}${video_url}") + continue + + # 回退方案 + episodes.append(f"{chapter_name}${vod_id}${chapter_id}${chapter_name}") + + if episodes: + play_urls.append("#".join(episodes)) + + return play_urls + + def getDirectVideoUrl(self, chapter): + if "chapterVideoVo" not in chapter or not chapter["chapterVideoVo"]: + return None + + video_info = chapter["chapterVideoVo"] + for key in ["mp4", "mp4720p", "vodMp4Url"]: + if key in video_info and video_info[key] and ".mp4" in video_info[key].lower(): + return video_info[key] + return None + + def playerContent(self, flag, id, vipFlags): + result = { + "parse": 0, + "url": id, + "header": json.dumps(self.headers) + } + + # 如果已经是视频链接直接返回 + if 'http' in id and ('.mp4' in id or '.m3u8' in id): + return result + + # 解析参数 + parts = id.split('$') + if len(parts) < 2: + return result + + drama_id = parts[0].replace('/drama/', '') + chapter_id = parts[1] + + # 尝试获取视频链接 + video_url = self.getEpisodeVideoUrl(drama_id, chapter_id) + if video_url: + result["url"] = video_url + + return result + + def getEpisodeVideoUrl(self, drama_id, chapter_id): + episode_url = f"{self.siteUrl}/episode/{drama_id}/{chapter_id}" + response = self.fetch(episode_url) + if not response: + return None + + html = response.text + + # 方法1: 从NEXT_DATA提取 + next_data_match = re.search(r'', html, re.DOTALL) + if next_data_match: + try: + next_data = json.loads(next_data_match.group(1)) + page_props = next_data.get("props", {}).get("pageProps", {}) + chapter_info = page_props.get("chapterInfo", {}) + + if chapter_info and "chapterVideoVo" in chapter_info: + video_info = chapter_info["chapterVideoVo"] + for key in ["mp4", "mp4720p", "vodMp4Url"]: + if key in video_info and video_info[key] and ".mp4" in video_info[key].lower(): + return video_info[key] + except: + pass + + # 方法2: 直接从HTML提取 + mp4_matches = re.findall(r'(https?://[^"\']+\.mp4)', html) + if mp4_matches: + for url in mp4_matches: + if chapter_id in url or drama_id in url: + return url + return mp4_matches[0] + + return None + + def localProxy(self, param): + return [200, "video/MP2T", {}, param] + + def destroy(self): + pass \ No newline at end of file diff --git a/lrzy/py/LIBVIO[盘].py b/lrzy/py/LIBVIO[盘].py new file mode 100644 index 0000000..89008eb --- /dev/null +++ b/lrzy/py/LIBVIO[盘].py @@ -0,0 +1,499 @@ +# coding=utf-8 +#!/usr/bin/python +import sys +sys.path.append('..') +from base.spider import Spider +import json +import re +try: + import ujson +except ImportError: + ujson = json +try: + from pyquery import PyQuery as pq +except ImportError: + pq = None +try: + from cachetools import TTLCache +except ImportError: + class TTLCache: + def __init__(self, maxsize=100, ttl=600): + self.cache = {} + self.maxsize = maxsize + def __contains__(self, key): + return key in self.cache + def __getitem__(self, key): + return self.cache[key] + def __setitem__(self, key, value): + if len(self.cache) >= self.maxsize: + first_key = next(iter(self.cache)) + del self.cache[first_key] + self.cache[key] = value + def __len__(self): + return len(self.cache) + +class Spider(Spider): + def __init__(self): + self.cache = TTLCache(maxsize=100, ttl=600) + def getName(self): + return "Libvio" + def init(self, extend=""): + print("============{0}============".format(extend)) + if not hasattr(self, 'cache'): + self.cache = TTLCache(maxsize=100, ttl=600) + pass + def _fetch_with_cache(self, url, headers=None): + cache_key = f"{url}_{hash(str(headers))}" + if cache_key in self.cache: + return self.cache[cache_key] + try: + response = self.fetch(url, headers=headers or self.header) + except Exception as e: + print(f"Fetch failed for {url}: {e}") + response = None # Fallback to None on error + if response: + self.cache[cache_key] = response + return response + def _parse_html_fast(self, html_text): + if not html_text: + return None + if pq is not None: + try: + return pq(html_text) + except: + pass + return self.html(self.cleanText(html_text)) + def homeContent(self, filter): + result = {} + cateManual = {"电影": "1", "电视剧": "2", "动漫": "4", "日韩剧": "15", "欧美剧": "16"} + classes = [] + for k in cateManual: + classes.append({'type_name': k, 'type_id': cateManual[k]}) + result['class'] = classes + if (filter): + result['filters'] = self._generate_filters() + return result + def homeVideoContent(self): + rsp = self._fetch_with_cache("https://www.libvio.site") + if not rsp: + return {'list': []} + doc = self._parse_html_fast(rsp.text) + videos = [] + if pq is not None and hasattr(doc, '__call__'): + try: + thumb_links = doc('a.stui-vodlist__thumb.lazyload') + for i in range(thumb_links.length): + try: + thumb = thumb_links.eq(i) + href = thumb.attr('href') + if not href: continue + sid_match = re.search(r'/detail/(\d+)\.html', href) + if not sid_match: continue + sid = sid_match.group(1) + name = thumb.attr('title') + if not name: continue + pic = thumb.attr('data-original') or "" + mark = thumb.text().strip() + videos.append({"vod_id": sid, "vod_name": name.strip(), "vod_pic": pic, "vod_remarks": mark}) + except Exception as e: continue + except: pass + if not videos: + try: + thumb_links = doc.xpath("//a[@class='stui-vodlist__thumb lazyload']") + for thumb in thumb_links: + try: + href = thumb.xpath("./@href")[0] + sid_match = re.search(r'/detail/(\d+)\.html', href) + if not sid_match: continue + sid = sid_match.group(1) + name = thumb.xpath("./@title")[0].strip() + if not name: continue + pic_list = thumb.xpath("./@data-original") + pic = pic_list[0] if pic_list else "" + mark_list = thumb.xpath("./text()") + mark = mark_list[0].strip() if mark_list else "" + videos.append({"vod_id": sid, "vod_name": name, "vod_pic": pic, "vod_remarks": mark}) + except Exception as e: continue + except Exception as e: print(f"Homepage parse failed: {e}") + result = {'list': videos} + return result + def categoryContent(self, tid, pg, filter, extend): + result = {} + url = 'https://www.libvio.site/type/{0}-{1}.html'.format(tid, pg) + print(url) + rsp = self._fetch_with_cache(url) + if not rsp: + return result + doc = self._parse_html_fast(rsp.text) + videos = [] + if pq is not None and hasattr(doc, '__call__'): + try: + thumb_links = doc('a.stui-vodlist__thumb.lazyload') + for i in range(thumb_links.length): + try: + thumb = thumb_links.eq(i) + href = thumb.attr('href') + if not href: continue + sid_match = re.search(r'/detail/(\d+)\.html', href) + if not sid_match: continue + sid = sid_match.group(1) + name = thumb.attr('title') + if not name: continue + pic = thumb.attr('data-original') or "" + mark = thumb.text().strip() + videos.append({"vod_id": sid, "vod_name": name.strip(), "vod_pic": pic, "vod_remarks": mark}) + except Exception as e: continue + except: pass + if not videos: + try: + thumb_links = doc.xpath("//a[@class='stui-vodlist__thumb lazyload']") + for thumb in thumb_links: + try: + href = thumb.xpath("./@href")[0] + sid_match = re.search(r'/detail/(\d+)\.html', href) + if not sid_match: continue + sid = sid_match.group(1) + name = thumb.xpath("./@title")[0].strip() + if not name: continue + pic_list = thumb.xpath("./@data-original") + pic = pic_list[0] if pic_list else "" + mark_list = thumb.xpath("./text()") + mark = mark_list[0].strip() if mark_list else "" + videos.append({"vod_id": sid, "vod_name": name, "vod_pic": pic, "vod_remarks": mark}) + except Exception as e: continue + except Exception as e: print(f"Category parse failed: {e}") + result['list'] = videos + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + def detailContent(self, array): + tid = array[0] + url = 'https://www.libvio.site/detail/{0}.html'.format(tid) + rsp = self._fetch_with_cache(url) + if not rsp: + return {'list': []} + doc = self._parse_html_fast(rsp.text) + title = doc('h1').text().strip() or "" + pic = doc('img').attr('data-original') or doc('img').attr('src') or "" + detail = "" + try: + detail_content = doc('.detail-content').text().strip() + if detail_content: detail = detail_content + else: + detail_text = doc('*:contains("简介:")').text() + if detail_text and '简介:' in detail_text: + detail_part = detail_text.split('简介:')[1] + if '详情' in detail_part: detail_part = detail_part.replace('详情', '') + detail = detail_part.strip() + except: pass + douban = "0.0" + + score_text = doc('.detail-info *:contains("分")').text() or "" + score_match = re.search(r'(\d+\.?\d*)\s*分', score_text) + if score_match: douban = score_match.group(1) + vod = {"vod_id": tid, "vod_name": title, "vod_pic": pic, "type_name": "", "vod_year": "", "vod_area": "", "vod_remarks": "", "vod_actor": "", "vod_director": "", "vod_douban_score": douban, "vod_content": detail} + info_text = doc('p').text() + if '类型:' in info_text: + type_match = re.search(r'类型:([^/]+)', info_text) + if type_match: vod['type_name'] = type_match.group(1).strip() + if '主演:' in info_text: + actor_match = re.search(r'主演:([^/]+)', info_text) + if actor_match: vod['vod_actor'] = actor_match.group(1).strip() + if '导演:' in info_text: + director_match = re.search(r'导演:([^/]+)', info_text) + if director_match: vod['vod_director'] = director_match.group(1).strip() + + playFrom = [] + playList = [] + + # 改进的播放线路提取逻辑 + vodlist_heads = doc('.stui-vodlist__head') + for i in range(vodlist_heads.length): + head = vodlist_heads.eq(i) + h3_elem = head.find('h3') + if h3_elem.length == 0: + continue + + header_text = h3_elem.text().strip() + if not any(keyword in header_text for keyword in ['播放', '下载', 'BD5', 'UC', '夸克']): + continue + + playFrom.append(header_text) + vodItems = [] + + # 提取当前播放线路下的所有播放链接 + play_links = head.find('a[href*="/play/"]') + for j in range(play_links.length): + try: + link = play_links.eq(j) + href = link.attr('href') + name = link.text().strip() + if not href or not name: + continue + + tId_match = re.search(r'/play/([^.]+)\.html', href) + if not tId_match: + continue + + tId = tId_match.group(1) + vodItems.append(name + "$" + tId) + except: + continue + + playList.append('#'.join(vodItems) if vodItems else "") + + vod['vod_play_from'] = '$$$'.join(playFrom) if playFrom else "" + vod['vod_play_url'] = '$$$'.join(playList) if playList else "" + result = {'list': [vod]} + return result + + def searchContent(self, key, quick): + url = 'https://www.libvio.site/index.php/ajax/suggest?mid=1&wd={0}'.format(key) + rsp = self._fetch_with_cache(url, headers=self.header) + if not rsp: + return {'list': []} + try: jo = ujson.loads(rsp.text) + except: jo = json.loads(rsp.text) + result = {} + jArray = [] + if jo.get('total', 0) > 0: + for j in jo.get('list', []): + jArray.append({"vod_id": j.get('id', ''), "vod_name": j.get('name', ''), "vod_pic": j.get('pic', ''), "vod_remarks": ""}) + result = {'list': jArray} + return result + def _generate_filters(self): + + + years = [{"n": "全部", "v": ""}] + for year in range(2025, 1999, -1): + years.append({"n": str(year), "v": str(year)}) + + + movie_filters = [ + { + "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": "area", "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": "其他"} + ] + }, + {"key": "year", "name": "年份", "value": years} + ] + + + tv_filters = [ + { + "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": "其他"} + ] + }, + { + "key": "area", "name": "地区", + "value": [ + {"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": years} + ] + + + anime_filters = [ + { + "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": "其他"} + ] + }, + { + "key": "area", "name": "地区", + "value": [ + {"n": "全部", "v": ""}, {"n": "中国", "v": "中国"}, {"n": "日本", "v": "日本"}, + {"n": "欧美", "v": "欧美"}, {"n": "其他", "v": "其他"} + ] + }, + {"key": "year", "name": "年份", "value": years} + ] + + + asian_filters = [ + { + "key": "class", "name": "剧情", + "value": [ + {"n": "全部", "v": ""}, {"n": "剧情", "v": "剧情"}, {"n": "喜剧", "v": "喜剧"}, + {"n": "爱情", "v": "爱情"}, {"n": "动作", "v": "动作"}, {"n": "悬疑", "v": "悬疑"}, + {"n": "惊悚", "v": "惊悚"}, {"n": "恐怖", "v": "恐怖"}, {"n": "犯罪", "v": "犯罪"} + ] + }, + { + "key": "area", "name": "地区", + "value": [ + {"n": "全部", "v": ""}, {"n": "韩国", "v": "韩国"}, {"n": "日本", "v": "日本"}, + {"n": "泰国", "v": "泰国"} + ] + }, + {"key": "year", "name": "年份", "value": years[:25]} + ] + + + western_filters = [ + { + "key": "class", "name": "剧情", + "value": [ + {"n": "全部", "v": ""}, {"n": "剧情", "v": "剧情"}, {"n": "喜剧", "v": "喜剧"}, + {"n": "爱情", "v": "爱情"}, {"n": "动作", "v": "动作"}, {"n": "科幻", "v": "科幻"}, + {"n": "悬疑", "v": "悬疑"}, {"n": "惊悚", "v": "惊悚"}, {"n": "恐怖", "v": "恐怖"}, + {"n": "犯罪", "v": "犯罪"} + ] + }, + { + "key": "area", "name": "地区", + "value": [ + {"n": "全部", "v": ""}, {"n": "美国", "v": "美国"}, {"n": "英国", "v": "英国"}, + {"n": "加拿大", "v": "加拿大"}, {"n": "其他", "v": "其他"} + ] + }, + {"key": "year", "name": "年份", "value": years[:25]} + ] + + return { + "1": movie_filters, # 电影 + "2": tv_filters, # 电视剧 + "4": anime_filters, # 动漫 + "15": asian_filters, # 日韩剧 + "16": western_filters # 欧美剧 + } + header = {"Referer": "https://www.libvio.site", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"} + def playerContent(self, flag, id, vipFlags): + # 如果已经是push链接,直接返回 + if id.startswith('push://'): + return {"parse": 0, "playUrl": "", "url": id, "header": ""} + + result = {} + url = 'https://www.libvio.site/play/{0}.html'.format(id) + try: + rsp = self._fetch_with_cache(url, headers=self.header) + if not rsp: + return {"parse": 1, "playUrl": "", "url": url, "header": ujson.dumps(self.header)} + return self._handle_cloud_drive(url, rsp, id) + except Exception as e: + print(f"Player parse error: {e}") + return {"parse": 1, "playUrl": "", "url": url, "header": ujson.dumps(self.header)} + + def _handle_cloud_drive(self, url, rsp, id): + try: + page_text = rsp.text + + # 首先尝试从JavaScript变量中提取网盘链接 + script_pattern = r'var player_[^=]*=\s*({[^}]+})' + matches = re.findall(script_pattern, page_text) + + for match in matches: + try: + player_data = ujson.loads(match) + from_value = player_data.get('from', '') + url_value = player_data.get('url', '') + + if from_value == 'kuake' and url_value: + # 夸克网盘 + drive_url = url_value.replace('\\/', '/') + return {"parse": 0, "playUrl": "", "url": f"push://{drive_url}", "header": ""} + elif from_value == 'uc' and url_value: + # UC网盘 + drive_url = url_value.replace('\\/', '/') + return {"parse": 0, "playUrl": "", "url": f"push://{drive_url}", "header": ""} + except: + continue + except Exception as e: + print(f"Cloud drive parse error: {e}") + + # 如果所有网盘解析都失败,尝试BD5播放源 + return self._handle_bd5_player(url, rsp, id) + + def _handle_bd5_player(self, url, rsp, id): + try: + doc = self._parse_html_fast(rsp.text) + page_text = rsp.text + api_match = re.search(r'https://www\.libvio\.site/vid/plyr/vr2\.php\?url=([^&"\s]+)', page_text) + if api_match: + return {"parse": 0, "playUrl": "", "url": api_match.group(1), "header": ujson.dumps({"User-Agent": self.header["User-Agent"], "Referer": "https://www.libvio.site/"})} + iframe_src = doc('iframe').attr('src') + if iframe_src: + try: + iframe_content = self._fetch_with_cache(iframe_src, headers=self.header) + if not iframe_content: raise Exception("Iframe fetch failed") + video_match = re.search(r'https://[^"\s]+\.mp4', iframe_content.text) + if video_match: return {"parse": 0, "playUrl": "", "url": video_match.group(0), "header": ujson.dumps({"User-Agent": self.header["User-Agent"], "Referer": "https://www.libvio.site/"})} + except Exception as e: print(f"iframe视频解析失败: {e}") + script_match = re.search(r'var player_[^=]*=\s*({[^}]+})', page_text) + if script_match: + try: + jo = ujson.loads(script_match.group(1)) + if jo: + nid = str(jo.get('nid', '')) + player_from = jo.get('from', '') + if player_from: + scriptUrl = f'https://www.libvio.site/static/player/{player_from}.js' + scriptRsp = self._fetch_with_cache(scriptUrl) + if not scriptRsp: raise Exception("Script fetch failed") + parse_match = re.search(r'src="([^"]+url=)', scriptRsp.text) + if parse_match: + parseUrl = parse_match.group(1) + path = f"{jo.get('url', '')}&next={jo.get('link_next', '')}&id={jo.get('id', '')}&nid={nid}" + parseRsp = self._fetch_with_cache(parseUrl + path, headers=self.header) + if not parseRsp: raise Exception("Parse fetch failed") + url_match = re.search(r"urls\s*=\s*'([^']+)'", parseRsp.text) + if url_match: return {"parse": 0, "playUrl": "", "url": url_match.group(1), "header": ""} + except Exception as e: print(f"JavaScript播放器解析失败: {e}") + except Exception as e: print(f"BD5播放源解析错误: {e}") + return {"parse": 1, "playUrl": "", "url": url, "header": ujson.dumps(self.header)} + def isVideoFormat(self, url): + + return False + def manualVideoCheck(self): + + pass + def localProxy(self, param): + + action = b'' + try: + header_dict = json.loads(param.get('header', '{}')) if param.get('header') else {} + resp = self.fetch(param['url'], headers=header_dict) + action = resp.content + except Exception as e: + print(f"Local proxy error: {e}") + return [200, "video/MP2T", action, param.get('header', '')] diff --git a/lrzy/py/LSYS.py b/lrzy/py/LSYS.py new file mode 100644 index 0000000..1a6a4d7 --- /dev/null +++ b/lrzy/py/LSYS.py @@ -0,0 +1,279 @@ +# coding=utf-8 +# !/usr/bin/python +# by嗷呜(finally) +import sys +import os +sys.path.append("..") +import re +import hashlib +import hmac +import random +import string +from Crypto.Util.Padding import unpad +from concurrent.futures import ThreadPoolExecutor +from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_v1_5, AES +from base64 import b64encode, b64decode +import json +import time +from base.spider import Spider + +class Spider(Spider): + + def getName(self): + return "电影猎手" + + def init(self, extend=""): + self.device = self.device_id() + self.host = self.gethost() + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def action(self, action): + pass + + def destroy(self): + pass + + t = str(int(time.time())) + + def homeContent(self, filter): + result = {} + filters = {} + classes = [] + bba = self.url() + data = self.fetch(f"{self.host}/api/v1/app/config?pack={bba[0]}&signature={bba[1]}", headers=self.header()).text + data1 = self.aes(data) + dy = {"class":"类型","area":"地区","lang":"语言","year":"年份","letter":"字母","by":"排序","sort":"排序"} + data1['data']['movie_screen']['sort'].pop(0) + for item in data1['data']['movie_screen']['sort']: + item['n'] = item.pop('name') + item['v'] = item.pop('value') + for item in data1['data']['movie_screen']['filter']: + has_non_empty_field = False + classes.append({"type_name": item["name"], "type_id": str(item["id"])}) + for key in dy: + if key in item and item[key]: + has_non_empty_field = True + break + if has_non_empty_field: + filters[str(item["id"])] = [] + filters[str(item["id"])].append( + {"key": 'sort', "name": '排序', "value": data1['data']['movie_screen']['sort']}) + for dkey in item: + if dkey in dy and item[dkey]: + item[dkey].pop(0) + value_array = [ + {"n": value.strip(), "v": value.strip()} + for value in item[dkey] + if value.strip() != "" + ] + filters[str(item["id"])].append( + {"key": dkey, "name": dy[dkey], "value": value_array} + ) + result["class"] = classes + result["filters"] = filters + return result + + def homeVideoContent(self): + bba = self.url() + url = f'{self.host}/api/v1/movie/index_recommend?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json() + videos = [] + for item in data['data']: + if len(item['list']) > 0: + for it in item['list']: + try: + videos.append(self.voides(it)) + except Exception as e: + continue + result = {"list": videos} + return result + + def categoryContent(self, tid, pg, filter, extend): + body = {"type_id": tid, "sort": extend.get("sort", "by_default"), "class": extend.get("class", "类型"), + "area": extend.get("area", "地区"), "year": extend.get("year", "年份"), "page": str(pg), + "pageSize": "21"} + result = {} + list = [] + bba = self.url(body) + url = f"{self.host}/api/v1/movie/screen/list?pack={bba[0]}&signature={bba[1]}" + data = self.fetch(url, headers=self.header()).json()['data']['list'] + for item in data: + list.append(self.voides(item)) + result["list"] = list + result["page"] = pg + result["pagecount"] = 9999 + result["limit"] = 90 + result["total"] = 999999 + return result + + def detailContent(self, ids): + body = {"id": ids[0]} + bba = self.url(body) + url = f'{self.host}/api/v1/movie/detail?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json()['data'] + video = {'vod_name': data.get('name'),'type_name': data.get('type_name'),'vod_year': data.get('year'),'vod_area': data.get('area'),'vod_remarks': data.get('dynami'),'vod_content': data.get('content')} + play = [] + names = [] + tasks = [] + for itt in data["play_from"]: + name = itt["name"] + a = [] + if len(itt["list"]) > 0: + names.append(name) + play.append(self.playeach(itt['list'])) + else: + tasks.append({"movie_id": ids[0], "from_code": itt["code"]}) + names.append(name) + if tasks: + with ThreadPoolExecutor(max_workers=len(tasks)) as executor: + results = executor.map(self.playlist, tasks) + for result in results: + if result: + play.append(result) + else: + play.append("") + video["vod_play_from"] = "$$$".join(names) + video["vod_play_url"] = "$$$".join(play) + result = {"list": [video]} + return result + + def searchContent(self, key, quick, pg=1): + body = {"keyword": key, "sort": "", "type_id": "0", "page": str(pg), "pageSize": "10", + "res_type": "by_movie_name"} + bba = self.url(body) + url = f"{self.host}/api/v1/movie/search?pack={bba[0]}&signature={bba[1]}" + data = self.fetch(url, headers=self.header()).json()['data'].get('list') + videos = [] + for it in data: + try: + videos.append(self.voides(it)) + except Exception as e: + continue + result = {"list": videos, "page": pg} + return result + + def playerContent(self, flag, id, vipFlags): + url = id + if "m3u8" not in url and "mp4" not in url: + try: + add = id.split('|||') + data = {"from_code": add[0], "play_url": add[1], "episode_id": add[2], "type": "play"} + bba = self.url(data) + data2 = self.fetch(f"{self.host}/api/v1/movie_addr/parse_url?pack={bba[0]}&signature={bba[1]}", + headers=self.header()).json()['data'] + url = data2.get('play_url') or data2.get('download_url') + try: + url1 = self.fetch(url, headers=self.header(), allow_redirects=False).headers['Location'] + if url1 and "http" in url1: + url = url1 + except: + pass + except Exception as e: + pass + if '.jpg' in url or '.jpeg' in url or '.png' in url: + url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8" + result = {} + result["parse"] = 0 + result["url"] = url + result["header"] = {'user-agent': 'okhttp/4.9.2'} + return result + + def localProxy(self, param): + url = b64decode(param["url"]).decode('utf-8') + durl = url[:url.rfind('/')] + data = self.fetch(url, headers=self.header()).content.decode("utf-8") + lines = data.strip().split('\n') + for index, string in enumerate(lines): + # if 'URI="' in string and 'http' not in string: + # lines[index] = index + # 暂时预留,貌似用不到 + if '#EXT' not in string and 'http' not in string: + lines[index] = durl + ('' if string.startswith('/') else '/') + string + data = '\n'.join(lines) + return [200, "application/vnd.apple.mpegur", data] + + def device_id(self): + characters = string.ascii_lowercase + string.digits + random_string = ''.join(random.choices(characters, k=32)) + return random_string + + def gethost(self): + headers = { + 'User-Agent': 'okhttp/4.9.2', + 'Connection': 'Keep-Alive', + } + response = self.fetch('https://app-site.ecoliving168.com/domain_v5.json', headers=headers).json() + url = response['api_service'].replace('/api/', '') + return url + + def header(self): + headers = { + 'User-Agent': 'Android', + 'Accept': 'application/prs.55App.v2+json', + 'timestamp': self.t, + 'x-client-setting': '{"pure-mode":1}', + 'x-client-uuid': '{"device_id":' + self.device + '}, "type":1,"brand":"Redmi", "model":"M2012K10C", "system_version":30, "sdk_version":"3.1.0.7"}', + 'x-client-version': '3096 ' + } + return headers + + def url(self, id=None): + if not id: + id = {} + id["timestamp"] = self.t + public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02F/kPg5A2NX4qZ5JSns+bjhVMCC6JbTiTKpbgNgiXU+Kkorg6Dj76gS68gB8llhbUKCXjIdygnHPrxVHWfzmzisq9P9awmXBkCk74Skglx2LKHa/mNz9ivg6YzQ5pQFUEWS0DfomGBXVtqvBlOXMCRxp69oWaMsnfjnBV+0J7vHbXzUIkqBLdXSNfM9Ag5qdRDrJC3CqB65EJ3ARWVzZTTcXSdMW9i3qzEZPawPNPe5yPYbMZIoXLcrqvEZnRK1oak67/ihf7iwPJqdc+68ZYEmmdqwunOvRdjq89fQMVelmqcRD9RYe08v+xDxG9Co9z7hcXGTsUquMxkh29uNawIDAQAB' + encrypted_text = json.dumps(id) + public_key = RSA.import_key(b64decode(public_key)) + cipher = PKCS1_v1_5.new(public_key) + encrypted_message = cipher.encrypt(encrypted_text.encode('utf-8')) + encrypted_message_base64 = b64encode(encrypted_message).decode('utf-8') + result = encrypted_message_base64.replace('+', '-').replace('/', '_').replace('=', '') + key = '635a580fcb5dc6e60caa39c31a7bde48' + sign = hmac.new(key.encode(), result.encode(), hashlib.md5).hexdigest() + return result, sign + + def playlist(self, body): + try: + bba = self.url(body) + url = f'{self.host}/api/v1/movie_addr/list?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json()['data'] + return self.playeach(data) + except Exception: + return [] + + def playeach(self,data): + play_urls = [] + for it in data: + if re.search(r"mp4|m3u8", it["play_url"]): + play_urls.append(f"{it['episode_name']}${it['play_url']}") + else: + play_urls.append( + f"{it['episode_name']}${it['from_code']}|||{it['play_url']}|||{it['episode_id']}" + ) + return '#'.join(play_urls) + + def voides(self, item): + if item['name'] or item['title']: + voide = { + "vod_id": item.get('id') or item.get('click'), + 'vod_name': item.get('name') or item.get('title'), + 'vod_pic': item.get('cover') or item.get('image'), + 'vod_year': item.get('year') or item.get('label'), + 'vod_remarks': item.get('dynamic') or item.get('sub_title') + } + return voide + + def aes(self, text): + text = text.replace('-', '+').replace('_', '/') + '==' + key = b"e6d5de5fcc51f53d" + iv = b"2f13eef7dfc6c613" + cipher = AES.new(key, AES.MODE_CBC, iv) + pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size).decode("utf-8") + return json.loads(pt) diff --git a/lrzy/py/UVod.py b/lrzy/py/UVod.py new file mode 100644 index 0000000..50ac2b4 --- /dev/null +++ b/lrzy/py/UVod.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- +import sys,json,time,base64,random,string,hashlib +from urllib.parse import urlencode,quote +from base.spider import Spider +from Crypto.Cipher import AES,PKCS1_v1_5 +from Crypto.PublicKey import RSA +from Crypto.Util.Padding import pad,unpad + +class Spider(Spider): + def __init__(self): + super().__init__() + self.base_url = 'https://api-h5.uvod.tv'; self.web_url = 'https://m.uvod.tv'; self.token = ''; self._iv = b"abcdefghijklmnop" + self._client_private = """-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJ4FBai1Y6my4+fc +8AD5tyYzxgN8Q7M/PuFv+8i1Xje8ElXYVwzvYd1y/cNxwgW4RX0tDy9ya562V33x +6SyNr29DU6XytOeOlOkxt3gd5169K4iFaJ0l0wA4koMTcCAYVxC9B4+zzS5djYmF +MuRGfYgKYNH99vfY7BZjdAY68ty5AgMBAAECgYB1rbvHJj5wVF7Rf4Hk2BMDCi9+ +zP4F8SW88Y6KrDbcPt1QvOonIea56jb9ZCxf4hkt3W6foRBwg86oZo2FtoZcpCJ+ +rFqUM2/wyV4CuzlL0+rNNSq7bga7d7UVld4hQYOCffSMifyF5rCFNH1py/4Dvswm +pi5qljf+dPLSlxXl2QJBAMzPJ/QPAwcf5K5nngQtbZCD3nqDFpRixXH4aUAIZcDz +S1RNsHrT61mEwZ/thQC2BUJTQNpGOfgh5Ecd1MnURwsCQQDFhAFfmvK7svkygoKX +t55ARNZy9nmme0StMOfdb4Q2UdJjfw8+zQNtKFOM7VhB7ijHcfFuGsE7UeXBe20n +g/XLAkEAv9SoT2hgJaQxxUk4MCF8pgddstJlq8Z3uTA7JMa4x+kZfXTm/6TOo6I8 +2VbXZLsYYe8op0lvsoHMFvBSBljV0QJBAKhxyoYRa98dZB5qZRskciaXTlge0WJk +kA4vvh3/o757izRlQMgrKTfng1GVfIZFqKtnBiIDWTXQw2N9cnqXtH8CQAx+CD5t +l1iT0cMdjvlMg2two3SnpOjpo7gALgumIDHAmsVWhocLtcrnJI032VQSUkNnLq9z +EIfmHDz0TPTNHBQ= +-----END PRIVATE KEY----- +""" + self._client_public = """-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeBQWotWOpsuPn3PAA+bcmM8YD +fEOzPz7hb/vItV43vBJV2FcM72Hdcv3DccIFuEV9LQ8vcmuetld98eksja9vQ1Ol +8rTnjpTpMbd4HedevSuIhWidJdMAOJKDE3AgGFcQvQePs80uXY2JhTLkRn2ICmDR +/fb32OwWY3QGOvLcuQIDAQAB +-----END PUBLIC KEY----- +""" + self._server_public = """-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeBQWotWOpsuPn3PAA+bcmM8YD +fEOzPz7hb/vItV43vBJV2FcM72Hdcv3DccIFuEV9LQ8vcmuetld98eksja9vQ1Ol +8rTnjpTpMbd4HedevSuIhWidJdMAOJKDE3AgGFcQvQePs80uXY2JhTLkRn2ICmDR +/fb32OwWY3QGOvLcuQIDAQAB +-----END PUBLIC KEY----- +""" + + def getName(self): return "UVOD" + + def init(self, extend=""): + try: cfg = json.loads(extend) if isinstance(extend, str) and extend.strip().startswith('{') else extend if isinstance(extend, dict) else {} + except Exception: cfg = {} + self.base_url = cfg.get('base_url', self.base_url); self.token = cfg.get('token', self.token) + return self.homeContent(False) + + def isVideoFormat(self, url): return any(x in url.lower() for x in ['.m3u8', '.mp4']) if url else False + def manualVideoCheck(self): return False + def destroy(self): pass + + def _random_key(self, n=32): + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for _ in range(n)) + + def _encrypt(self, plain_text: str) -> str: + aes_key = self._random_key(32).encode('utf-8') + cipher = AES.new(aes_key, AES.MODE_CBC, iv=self._iv) + ct_b64 = base64.b64encode(cipher.encrypt(pad(plain_text.encode('utf-8'), AES.block_size))).decode('utf-8') + rsa_pub = RSA.import_key(self._server_public); rsa_cipher = PKCS1_v1_5.new(rsa_pub) + rsa_b64 = base64.b64encode(rsa_cipher.encrypt(aes_key)).decode('utf-8') + return f"{ct_b64}.{rsa_b64}" + + def _decrypt(self, enc_text: str) -> str: + try: + parts = enc_text.split('.'); ct_b64, rsa_b64 = parts + rsa_priv = RSA.import_key(self._client_private) + aes_key = PKCS1_v1_5.new(rsa_priv).decrypt(base64.b64decode(rsa_b64), None) + cipher = AES.new(aes_key, AES.MODE_CBC, iv=self._iv) + pt = unpad(cipher.decrypt(base64.b64decode(ct_b64)), AES.block_size) + return pt.decode('utf-8', 'ignore') + except Exception: return enc_text + + def _build_headers(self, path: str, payload: dict): + ts = str(int(time.time() * 1000)); token = self.token or '' + if path == '/video/latest': + parent_id = payload.get('parent_category_id', 101); text = f"-parent_category_id={parent_id}-{ts}" + elif path == '/video/list': + keyword = payload.get('keyword') + if keyword: keyword = quote(str(keyword), safe='').lower(); text = f"-keyword={keyword}&need_fragment=1&page=1&pagesize=42&sort_type=asc-{ts}" + else: page = payload.get('page', 1); pagesize = payload.get('pagesize', 42); parent_id = payload.get('parent_category_id', ''); text = f"-page={page}&pagesize={pagesize}&parent_category_id={parent_id}&sort_type=asc-{ts}" + elif path == '/video/info': text = f"-id={payload.get('id', '')}-{ts}" + elif path == '/video/source': quality = payload.get('quality', ''); fragment_id = payload.get('video_fragment_id', ''); video_id = payload.get('video_id', ''); text = f"-quality={quality}&video_fragment_id={fragment_id}&video_id={video_id}-{ts}" + else: filtered = {k: v for k, v in (payload or {}).items() if v not in (0, '0', '', False, None)}; query = urlencode(sorted(filtered.items()), doseq=True).lower(); text = f"{token}-{query}-{ts}" + sig = hashlib.md5(text.encode('utf-8')).hexdigest() + return {'Content-Type': 'application/json', 'X-TOKEN': token, 'X-TIMESTAMP': ts, 'X-SIGNATURE': sig, 'Origin': self.web_url, 'Referer': self.web_url + '/', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'} + + def _post_api(self, path: str, payload: dict): + url = self.base_url.rstrip('/') + path + try: + body = self._encrypt(json.dumps(payload, ensure_ascii=False)); headers = self._build_headers(path, payload) + rsp = self.post(url, data=body, headers=headers, timeout=15) + if rsp.status_code != 200 or not rsp.text: return None + txt = rsp.text.strip(); obj = None + try: dec = self._decrypt(txt); obj = json.loads(dec) + except: + try: obj = json.loads(txt) + except: pass + if isinstance(obj, dict) and obj.get('error') == 0: return obj.get('data') + return None + except Exception: return None + + def homeContent(self, filter): + data = self._post_api('/video/category', {}); lst = (data.get('list') or data.get('category') or []) if isinstance(data, dict) else (data or []); classes = [] + for it in lst: + cid = it.get('id') or it.get('category_id') or it.get('value'); name = it.get('name') or it.get('label') or it.get('title') + if cid and name: classes.append({'type_name': str(name), 'type_id': str(cid)}) + if not classes: classes = [{'type_name': '电影', 'type_id': '100'}, {'type_name': '电视剧', 'type_id': '101'}, {'type_name': '综艺', 'type_id': '102'}, {'type_name': '动漫', 'type_id': '103'}, {'type_name': '体育', 'type_id': '104'}, {'type_name': '纪录片', 'type_id': '105'}, {'type_name': '粤台专区', 'type_id': '106'}] + return {'class': classes} + + def homeVideoContent(self): + data = self._post_api('/video/latest', {'parent_category_id': 101}) + if isinstance(data, dict): lst = data.get('video_latest_list') or data.get('list') or data.get('rows') or data.get('items') or [] + elif isinstance(data, list): lst = data + else: lst = [] + videos = [] + for k in lst: + vid = k.get('id') or k.get('video_id') or k.get('videoId') + if vid: videos.append({'vod_id': str(vid), 'vod_name': k.get('title') or k.get('name') or '', 'vod_pic': k.get('poster') or k.get('cover') or k.get('pic') or '', 'vod_remarks': k.get('score') or k.get('remarks') or ''}) + return {'list': videos} + + def categoryContent(self, tid, pg, filter, extend): + page = int(pg) if str(pg).isdigit() else 1 + payload = {'parent_category_id': str(tid), 'category_id': None, 'language': None, 'year': None, 'region': None, 'state': None, 'keyword': '', 'paid': None, 'page': page, 'pagesize': 42, 'sort_field': '', 'sort_type': 'asc'} + if isinstance(extend, dict): + for k in ['category_id', 'year', 'region', 'state', 'keyword']: + if extend.get(k): payload[k] = extend[k] + data = self._post_api('/video/list', payload) + if isinstance(data, dict): lst = data.get('video_list') or data.get('list') or data.get('rows') or data.get('items') or []; total = data.get('total', 999999) + elif isinstance(data, list): lst = data; total = 999999 + else: lst, total = [], 0 + videos = [] + for k in lst: + vid = k.get('id') or k.get('video_id') or k.get('videoId') + if vid: videos.append({'vod_id': str(vid), 'vod_name': k.get('title') or k.get('name') or '', 'vod_pic': k.get('poster') or k.get('cover') or k.get('pic') or '', 'vod_remarks': k.get('score') or ''}) + return {'list': videos, 'page': page, 'pagecount': 9999, 'limit': 24, 'total': total} + + def detailContent(self, ids): + vid = ids[0]; data = self._post_api('/video/info', {'id': vid}) or {}; video_info = data.get('video', {}) if isinstance(data, dict) else {}; fragments = data.get('video_fragment_list', []) if isinstance(data, dict) else []; play_urls = [] + if fragments: + for fragment in fragments: + name = fragment.get('symbol', '播放'); fragment_id = fragment.get('id', ''); qualities = fragment.get('qualities', []) + if fragment_id and qualities: + + max_quality = max(qualities) if qualities else 4 + play_urls.append(f"{name}${vid}|{fragment_id}|[{max_quality}]") + if not play_urls: play_urls.append(f"播放${vid}") + vod = {'vod_id': str(vid), 'vod_name': video_info.get('title') or video_info.get('name') or '', 'vod_pic': video_info.get('poster') or video_info.get('cover') or video_info.get('pic') or '', 'vod_year': video_info.get('year') or '', 'vod_remarks': video_info.get('duration') or '', 'vod_content': video_info.get('description') or video_info.get('desc') or '', 'vod_play_from': '优汁🍑源', 'vod_play_url': '#'.join(play_urls) + '$$$'} + return {'list': [vod]} + + def searchContent(self, key, quick, pg="1"): + page = int(pg) if str(pg).isdigit() else 1 + payload = {'parent_category_id': None, 'category_id': None, 'language': None, 'year': None, 'region': None, 'state': None, 'keyword': key, 'paid': None, 'page': page, 'pagesize': 42, 'sort_field': '', 'sort_type': 'asc', 'need_fragment': 1} + data = self._post_api('/video/list', payload) + if isinstance(data, dict): lst = data.get('video_list') or data.get('list') or data.get('rows') or data.get('items') or [] + elif isinstance(data, list): lst = data + else: lst = [] + videos = [] + for k in lst: + vid = k.get('id') or k.get('video_id') or k.get('videoId') + if vid: videos.append({'vod_id': str(vid), 'vod_name': k.get('title') or k.get('name') or '', 'vod_pic': k.get('poster') or k.get('cover') or k.get('pic') or '', 'vod_remarks': k.get('score') or ''}) + return {'list': videos} + + def _extract_first_media(self, obj): + if not obj: return None + if isinstance(obj, str): s = obj.strip(); return s if self.isVideoFormat(s) else None + if isinstance(obj, (dict, list)): + for v in (obj.values() if isinstance(obj, dict) else obj): + r = self._extract_first_media(v) + if r: return r + return None + + def playerContent(self, flag, id, vipFlags): + parts = id.split('|'); video_id = parts[0] + if len(parts) >= 3: + fragment_id = parts[1]; qualities_str = parts[2].strip('[]').replace(' ', ''); qualities = [q.strip() for q in qualities_str.split(',') if q.strip()]; quality = qualities[0] if qualities else '4' + payload = {'video_id': video_id, 'video_fragment_id': int(fragment_id) if str(fragment_id).isdigit() else fragment_id, 'quality': int(quality) if str(quality).isdigit() else quality, 'seek': None} + else: payload = {'video_id': video_id, 'video_fragment_id': 1, 'quality': 4, 'seek': None} + data = self._post_api('/video/source', payload) or {} + url = (data.get('video', {}).get('url', '') or data.get('url') or data.get('playUrl') or data.get('play_url') or self._extract_first_media(data) or '') + if not url: return {'parse': 1, 'url': id} + headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', 'Referer': self.web_url + '/', 'Origin': self.web_url} + return {'parse': 0, 'url': url, 'header': headers} + + def localProxy(self, param): return None \ No newline at end of file diff --git a/lrzy/py/YYMP3音乐网.py b/lrzy/py/YYMP3音乐网.py new file mode 100644 index 0000000..ef71f6f --- /dev/null +++ b/lrzy/py/YYMP3音乐网.py @@ -0,0 +1,383 @@ +# coding=utf-8 +# !/usr/bin/python + +""" + +作者 丢丢喵 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容 + ====================Diudiumiao==================== + +""" + +from Crypto.Util.Padding import unpad +from Crypto.Util.Padding import pad +from urllib.parse import unquote +from Crypto.Cipher import ARC4 +from urllib.parse import quote +from base.spider import Spider +from Crypto.Cipher import AES +from datetime import datetime +from bs4 import BeautifulSoup +from base64 import b64decode +import urllib.request +import urllib.parse +import datetime +import binascii +import requests +import base64 +import json +import time +import sys +import re +import os + +sys.path.append('..') + +xurl = "https://www.yymp3.com" + +headerx = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36' + } + +class Spider(Spider): + global xurl + global headerx + + def getName(self): + return "首页" + + def init(self, extend): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''): + if pl == 3: + plx = [] + while True: + start_index = text.find(start_str) + if start_index == -1: + break + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + break + middle_text = text[start_index + len(start_str):end_index] + plx.append(middle_text) + text = text.replace(start_str + middle_text + end_str, '') + if len(plx) > 0: + purl = '' + for i in range(len(plx)): + matches = re.findall(start_index1, plx[i]) + output = "" + for match in matches: + match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1]) + if match3: + number = match3.group(1) + else: + number = 0 + if 'http' not in match[0]: + output += f"#{match[1]}${number}{xurl}{match[0]}" + else: + output += f"#{match[1]}${number}{match[0]}" + output = output[1:] + purl = purl + output + "$$$" + purl = purl[:-3] + return purl + else: + return "" + else: + start_index = text.find(start_str) + if start_index == -1: + return "" + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + return "" + + if pl == 0: + middle_text = text[start_index + len(start_str):end_index] + return middle_text.replace("\\", "") + + if pl == 1: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + jg = ' '.join(matches) + return jg + + if pl == 2: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + new_list = [f'{item}' for item in matches] + jg = '$$$'.join(new_list) + return jg + + def homeContent(self, filter): + result = {"class": []} + + detail = requests.get(url=xurl, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('div', id="nav_box") + + for soup in soups: + vods = soup.find_all('a') + + for vod in vods: + name = vod.text.strip() + skip_keywords = ["首页", "动漫"] + if any(keyword in name for keyword in skip_keywords): + continue + + id = vod['href'] + if 'http' not in id: + id = xurl + id + + result["class"].append({"type_id": id, "type_name": name}) + + return result + + def homeVideoContent(self): + pass + + def categoryContent(self, cid, pg, filter, ext): + result = {} + videos = [] + + if '@' in cid: + fenge = cid.split("@") + + detail = requests.get(url=xurl + fenge[0], headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('dl', class_="albumlist c") + + for vod in soups: + names = vod.find('a', class_="A_name") + name = names.text.strip() + + ids = vod.find('dd', class_="A_details") + id = ids.find('a')['href'] + + pic = vod.find('img')['src'] + + if 'http' not in pic: + pic = "https:" + pic + + remark = "推荐" + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": remark + } + videos.append(video) + + else: + detail = requests.get(url=cid, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + soups = doc.find_all('ul', class_="Cate_slist c") + + for soup in soups: + vods = soup.find_all('a') + + for vod in vods: + + name = vod.text.strip() + + id = vod['href'] + + pic = "https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/af3a1f95d591c34d/1755975256375.png" + + remark = "推荐" + + video = { + "vod_id": id+'@'+name, + "vod_name": name, + "vod_pic": pic, + "vod_tag": "folder", + "vod_remarks": remark + } + videos.append(video) + + result = {'list': videos} + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + did = ids[0] + result = {} + videos = [] + xianlu = '' + bofang = '' + + if 'Play' in did: + if 'http' not in did: + bofang = xurl + did + + xianlu = '搜索专线' + + videos.append({ + "vod_id": did, + "vod_play_from": xianlu, + "vod_play_url": bofang + }) + + else: + if 'http' not in did: + did = xurl + did + + res = requests.get(url=did, headers=headerx) + res.encoding = "utf-8" + res = res.text + doc = BeautifulSoup(res, "lxml") + + content = self.extract_middle_text(res,'style="height:93px;">','

', 0) + content = content.replace('
', '').replace('
', '').replace(' ', '') + + director = self.extract_middle_text(res,'公司:','',1,'href=.*?>(.*?)') + + year = self.extract_middle_text(res, '时间:', '<', 0) + + area = self.extract_middle_text(res, '语种:', '<', 0) + + soups = doc.find_all('ul', class_="A_list4") + + for item in soups: + vods = item.find_all('li') + + for sou in vods: + + ids = sou.find('div', class_="td1_l") + id = ids.find('a')['href'] + + if 'http' not in id: + id = xurl + id + + names = sou.find('div', class_="td1_l") + name = names.text.strip() + + bofang = bofang + name + '$' + id + '#' + + bofang = bofang[:-1] + + xianlu = '音乐专线' + + videos.append({ + "vod_id": did, + "vod_director": director, + "vod_actor": actor, + "vod_year": year, + "vod_area": area, + "vod_content": content, + "vod_play_from": xianlu, + "vod_play_url": bofang + }) + + result['list'] = videos + return result + + def playerContent(self, flag, id, vipFlags): + + res = requests.get(url=id, headers=headerx) + res.encoding = "utf-8" + res = res.text + + year = self.extract_middle_text(res, '$song_data[0]', ';', 0) + fenge = year.split('|') + + url = "https://ting8.yymp3.com/" + fenge[4] + url = url.replace('wma', 'mp3') + + result = {} + result["parse"] = 0 + result["playUrl"] = '' + result["url"] = url + result["header"] = headerx + return result + + def searchContentPage(self, key, quick, pg): + result = {} + videos = [] + + if pg: + page = int(pg) + else: + page = 1 + + url = f'{xurl}/search/?page={str(page)}&key={key}&tp=1' + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('ul', class_="searchResult c") + + for item in soups: + vods = item.find_all('li') + + for vod in vods[1:]: + + names = vod.find('div', class_="p3") + name1 = names.text.strip() + + name2s = vod.find('div', class_="p2") + name2 = name2s.text.strip() + + name = name1 + ' ' + name2 + + id = names.find('a')['href'] + + pic = "https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/af3a1f95d591c34d/1755975256375.png" + + remark = "推荐" + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": remark + } + videos.append(video) + + result['list'] = videos + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def searchContent(self, key, quick, pg="1"): + return self.searchContentPage(key, quick, '1') + + def localProxy(self, params): + if params['type'] == "m3u8": + return self.proxyM3u8(params) + elif params['type'] == "media": + return self.proxyMedia(params) + elif params['type'] == "ts": + return self.proxyTs(params) + return None + + + + + + + + diff --git a/lrzy/py/emby.py b/lrzy/py/emby.py new file mode 100644 index 0000000..247f34a --- /dev/null +++ b/lrzy/py/emby.py @@ -0,0 +1,564 @@ +#coding=utf-8 +#!/usr/bin/python +import sys +import json +import time +import random +import requests +import threading +from uuid import uuid4 +from urllib.parse import quote + +sys.path.append('..') +from base.spider import Spider + +class Spider(Spider): + def getName(self): + return "EMBY" + + def init(self, extend): + try: + extendDict = json.loads(extend) + self.baseUrl = extendDict['server'].strip('/') + self.username = extendDict['username'] + self.password = extendDict['password'] + self.proxy = extendDict['proxy'] + self.thread = extendDict['thread'] if 'thread' in extendDict else 0 + self.device_id = extendDict.get('device_id', str(uuid4())) + self.client = extendDict.get('client', 'Hills Windows') + self.device_name = extendDict.get('device_name', 'My Computer') + self.client_version = extendDict.get('client_version', '0.2.2') + except: + self.baseUrl = '' + self.username = '' + self.password = '' + self.proxy = '' + self.thread = 0 + self.device_id = str(uuid4()) + self.client = 'Hills Windows' + self.device_name = 'My Computer' + self.client_version = '0.2.2' + + # 初始化header + self.header = { + "User-Agent": f"{self.client}/{self.client_version}".replace(' ', '-'), # 替换空格为连字符 + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version + } + + # 初始化播放会话字典 + self.play_sessions = {} + + def destroy(self): + # 清理所有播放会话 + for session_id in list(self.play_sessions.keys()): + self._record_playback_stop(session_id) + self.play_sessions.clear() + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def homeContent(self, filter): + try: + embyInfos = self.getAccessToken() + except: + return {'msg': '获取Emby服务器信息出错'} + + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Views" + params = { + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + } + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + typeInfos = r.json()["Items"] + classList = [] + for typeInfo in typeInfos: + if "播放列表" in typeInfo['Name'] or '相机' in typeInfo['Name']: + continue + classList.append({"type_name": typeInfo['Name'], "type_id": typeInfo['Id']}) + result = {'class': classList} + return result + + def homeVideoContent(self): + return {} + + def categoryContent(self, cid, page, filter, ext): + try: + embyInfos = self.getAccessToken() + except: + return {'list': [], 'msg': '获取Emby服务器信息出错'} + + result = {} + page = int(page) + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items" + params = { + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'], + "SortBy": "DateLastContentAdded,SortName", + "IncludeItemTypes": "Movie,Series", + "SortOrder": "Descending", + "ParentId": cid, + "Recursive": "true", + "Limit": "30", + "ImageTypeLimit": 1, + "StartIndex": str((page - 1) * 30), + "EnableImageTypes": "Primary,Backdrop,Thumb,Banner", + "Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating,Status,CriticRating,EndDate,Path", + "EnableUserData": "true" + } + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + videoList = r.json()['Items'] + videos = [] + for video in videoList: + name = self.cleanText(video['Name']) + videos.append({ + "vod_id": video['Id'], + "vod_name": name, + "vod_pic": f"{self.baseUrl}/emby/Items/{video['Id']}/Images/Primary?maxWidth=400&tag={video['ImageTags']['Primary']}&quality=90" if 'Primary' in video['ImageTags'] else '', + "vod_remarks": video['ProductionYear'] if 'ProductionYear' in video else '' + }) + result['list'] = videos + result['page'] = page + result['pagecount'] = page + 1 if page * 30 < int(r.json()['TotalRecordCount']) else page + result['limit'] = len(videos) + result['total'] = int(r.json()['TotalRecordCount']) if "TotalRecordCount" in r.json() else 0 + return result + + def detailContent(self, did): + try: + embyInfos = self.getAccessToken() + except: + return {'list': [], 'msg': '获取Emby服务器信息出错'} + + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items/{did[0]}" + params = { + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + } + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + videoInfos = r.json() + vod = { + "vod_id": did[0], + "vod_name": videoInfos['Name'], + "vod_pic": f'{self.baseUrl}/emby/Items/{did[0]}/Images/Primary?maxWidth=400&tag={videoInfos["ImageTags"]["Primary"]}&quality=90' if 'Primary' in videoInfos['ImageTags'] else '', + "type_name": videoInfos['Genres'][0] if len(videoInfos['Genres']) > 0 else '', + "vod_year": videoInfos['ProductionYear'] if 'ProductionYear' in videoInfos else '', + "vod_content": videoInfos['Overview'].replace('\xa0', ' ').replace('\n\n', '\n').strip() if 'Overview' in videoInfos else '', + "vod_play_from": "EMBY" + } + playUrl = '' + if not videoInfos['IsFolder']: + playUrl += f"{videoInfos['Name'].strip()}${videoInfos['Id']}#" + else: + url = f"{self.baseUrl}/emby/Shows/{did[0]}/Seasons" + params.update( + { + "UserId": embyInfos['User']['Id'], + "EnableImages": "true", + "Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating", + "EnableUserData": "true", + "EnableTotalRecordCount": "false" + } + ) + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + if r.status_code == 200: + playInfos = r.json()['Items'] + for playInfo in playInfos: + url = f"{self.baseUrl}/emby/Shows/{playInfo['Id']}/Episodes" + params.update( + { + "SeasonId": playInfo['Id'], + "Fields": "BasicSyncInfo,CanDelete,CommunityRating,PrimaryImageAspectRatio,ProductionYear,Overview" + } + ) + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + videoList = r.json()['Items'] + for video in videoList: + playUrl += f"{playInfo['Name'].replace('#', '-').replace('$', '|').strip()}|{video['Name'].strip()}${video['Id']}#" + else: + url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items" + params = { + "ParentId": did[0], + "Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating,CriticRating", + "ImageTypeLimit": "1", + "StartIndex": "0", + "EnableUserData": "true", + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + } + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + videoList = r.json()['Items'] + for video in videoList: + playUrl += f"{video['Name'].replace('#', '-').replace('$', '|').strip()}${video['Id']}#" + vod['vod_play_url'] = playUrl.strip('#') + result = {'list': [vod]} + return result + + def searchContent(self, key, quick, pg="1"): + return self.searchContentPage(key, quick, pg) + + def searchContentPage(self, keywords, quick, page): + try: + embyInfos = self.getAccessToken() + except: + return {'list': [], 'msg': '获取Emby服务器信息出错'} + page = int(page) + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items" + params = { + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'], + "SortBy": "SortName", + "SortOrder": "Ascending", + "Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,Status,EndDate", + "StartIndex": str(((page-1)*50)), + "EnableImageTypes": "Primary,Backdrop,Thumb", + "ImageTypeLimit": "1", + "Recursive": "true", + "SearchTerm": keywords, + "IncludeItemTypes": "Movie,Series,BoxSet", + "GroupProgramsBySeries": "true", + "Limit": "50", + "EnableTotalRecordCount": "true" + } + r = requests.get(url, params=params, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + + videos = [] + vodList = r.json()['Items'] + for vod in vodList: + sid = vod['Id'] + name = self.cleanText(vod['Name']) + pic = f'{self.baseUrl}/emby/Items/{sid}/Images/Primary?maxWidth=400&tag={vod["ImageTags"]["Primary"]}&quality=90' if 'Primary' in vod["ImageTags"] else '' + videos.append({ + "vod_id": sid, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": vod['ProductionYear'] if 'ProductionYear' in vod else '' + }) + result = {'list': videos} + return result + + def playerContent(self, flag, pid, vipFlags): + try: + embyInfos = self.getAccessToken() + except: + return {'list': [], 'msg': '获取Emby服务器信息出错'} + + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + + # 获取播放信息 + url = f"{self.baseUrl}/emby/Items/{pid}/PlaybackInfo" + params = { + "UserId": embyInfos['User']['Id'], + "IsPlayback": "false", + "AutoOpenLiveStream": "false", + "StartTimeTicks": 0, + "MaxStreamingBitrate": "2147483647", + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + } + data = "{\"DeviceProfile\":{\"SubtitleProfiles\":[{\"Method\":\"Embed\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"Embed\"},{\"Format\":\"subrip\",\"Method\":\"Embed\"},{\"Format\":\"sub\",\"Method\":\"Embed\"},{\"Method\":\"Embed\",\"Format\":\"pgssub\"},{\"Format\":\"subrip\",\"Method\":\"External\"},{\"Method\":\"External\",\"Format\":\"sub\"},{\"Method\":\"External\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"External\"},{\"Method\":\"External\",\"Format\":\"vtt\"},{\"Method\":\"External\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"External\"}],\"CodecProfiles\":[{\"Codec\":\"h264\",\"Type\":\"Video\",\"ApplyConditions\":[{\"Property\":\"IsAnamorphic\",\"Value\":\"true\",\"Condition\":\"NotEquals\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"high|main|baseline|constrained baseline\",\"Condition\":\"EqualsAny\",\"Property\":\"VideoProfile\"},{\"IsRequired\":false,\"Value\":\"80\",\"Condition\":\"LessThanEqual\",\"Property\":\"VideoLevel\"},{\"IsRequired\":false,\"Value\":\"true\",\"Condition\":\"NotEquals\",\"Property\":\"IsInterlaced\"}]},{\"Codec\":\"hevc\",\"ApplyConditions\":[{\"Property\":\"IsAnamorphic\",\"Value\":\"true\",\"Condition\":\"NotEquals\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"high|main|main 10\",\"Condition\":\"EqualsAny\",\"Property\":\"VideoProfile\"},{\"Property\":\"VideoLevel\",\"Value\":\"175\",\"Condition\":\"LessThanEqual\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"true\",\"Condition\":\"NotEquals\",\"Property\":\"IsInterlaced\"}],\"Type\":\"Video\"}],\"MaxStreamingBitrate\":40000000,\"TranscodingProfiles\":[{\"Container\":\"ts\",\"AudioCodec\":\"aac,mp3,wav,ac3,eac3,flac,opus\",\"VideoCodec\":\"hevc,h264,mpeg4\",\"BreakOnNonKeyFrames\":true,\"Type\":\"Video\",\"MaxAudioChannels\":\"6\",\"Protocol\":\"hls\",\"Context\":\"Streaming\",\"MinSegments\":2}],\"DirectPlayProfiles\":[{\"Container\":\"mov,mp4,mkv,hls,webm\",\"Type\":\"Video\",\"VideoCodec\":\"h264,hevc,dvhe,dvh1,h264,hevc,hev1,mpeg4,vp9\",\"AudioCodec\":\"aac,mp3,wav,ac3,eac3,flac,truehd,dts,dca,opus,pcm,pcm_s24le\"}],\"ResponseProfiles\":[{\"MimeType\":\"video/mp4\",\"Type\":\"Video\",\"Container\":\"m4v\"}],\"ContainerProfiles\":[],\"MusicStreamingTranscodingBitrate\":40000000,\"MaxStaticBitrate\":40000000}}" + r = requests.post(url, params=params, data=data, headers=header, timeout=120, proxies={"http": self.proxy, "https": self.proxy}) + + # 获取播放URL + media_sources = r.json()['MediaSources'] + if not media_sources: + return {'list': [], 'msg': '没有可用的媒体源'} + + # 使用第一个媒体源 + media_source = media_sources[0] + direct_stream_url = media_source.get('DirectStreamUrl') + + if not direct_stream_url: + return {'list': [], 'msg': '无法获取播放URL'} + + url = self.baseUrl + direct_stream_url + + # 记录播放开始 + try: + session_id = self._record_playback_start(embyInfos, pid, media_source) + # 启动播放进度更新线程 + self._start_progress_updater(embyInfos, pid, media_source, session_id) + except Exception as e: + print(f"记录播放开始失败: {e}") + + if int(self.thread) > 0: + try: + self.fetch('http://127.0.0.1:7777', timeout=120) + except: + self.fetch('http://127.0.0.1:9978/go') + url = f'http://127.0.0.1:7777/?url={quote(url)}&thread={self.thread}' + + result = { + "url": url, + "header": self.header, + "parse": 0 + } + return result + + def _record_playback_start(self, embyInfos, item_id, media_source): + """记录播放开始""" + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + + # 添加认证头 + header.update({ + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + }) + + # 生成唯一的会话ID + session_id = f"session_{int(time.time())}_{random.randint(1000, 9999)}" + + # 构建播放开始数据 + play_data = { + "ItemId": item_id, + "MediaSourceId": media_source.get('Id'), + "CanSeek": True, + "IsPaused": False, + "IsMuted": False, + "PositionTicks": 0, + "PlayMethod": "DirectStream", + "PlaySessionId": session_id, + "LiveStreamId": None, + "AudioStreamIndex": 1, + "SubtitleStreamIndex": -1, + "VolumeLevel": 100, + "PlaybackStartTimeTicks": int(time.time() * 10000000) + } + + # 发送播放开始请求 + play_url = f"{self.baseUrl}/Sessions/Playing" + try: + response = requests.post( + play_url, + json=play_data, + headers=header, + timeout=5, + proxies={"http": self.proxy, "https": self.proxy} + ) + if response.status_code == 200 or response.status_code == 204: + print(f"播放开始记录成功: {response.status_code}") + # 保存会话信息 + self.play_sessions[session_id] = { + 'embyInfos': embyInfos, + 'item_id': item_id, + 'media_source': media_source, + 'start_time': time.time(), + 'last_update': time.time() + } + return session_id + else: + print(f"播放开始记录失败: {response.status_code}, {response.text}") + return None + except Exception as e: + print(f"播放开始记录请求异常: {e}") + return None + + def _record_playback_progress(self, embyInfos, item_id, media_source, session_id, position_seconds): + """记录播放进度""" + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + + # 添加认证头 + header.update({ + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + }) + + # 构建播放进度数据 + progress_data = { + "ItemId": item_id, + "MediaSourceId": media_source.get('Id'), + "PositionTicks": int(position_seconds * 10000000), # 转换为ticks + "IsPaused": False, + "PlaySessionId": session_id, + "EventName": "timeupdate" + } + + # 发送播放进度请求 + progress_url = f"{self.baseUrl}/Sessions/Playing/Progress" + try: + response = requests.post( + progress_url, + json=progress_data, + headers=header, + timeout=5, + proxies={"http": self.proxy, "https": self.proxy} + ) + if response.status_code == 200 or response.status_code == 204: + print(f"播放进度更新成功: {position_seconds}秒") + return True + else: + print(f"播放进度更新失败: {response.status_code}, {response.text}") + return False + except Exception as e: + print(f"播放进度更新请求异常: {e}") + return False + + def _record_playback_stop(self, session_id): + """记录播放停止""" + if session_id not in self.play_sessions: + return False + + session_info = self.play_sessions[session_id] + embyInfos = session_info['embyInfos'] + item_id = session_info['item_id'] + media_source = session_info['media_source'] + total_duration = time.time() - session_info['start_time'] + + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + + # 添加认证头 + header.update({ + "X-Emby-Client": self.client, + "X-Emby-Device-Name": self.device_name, + "X-Emby-Device-Id": self.device_id, + "X-Emby-Client-Version": self.client_version, + "X-Emby-Token": embyInfos['AccessToken'] + }) + + # 构建播放停止数据 + stop_data = { + "ItemId": item_id, + "MediaSourceId": media_source.get('Id'), + "PositionTicks": int(total_duration * 10000000), # 转换为ticks + "PlaySessionId": session_id + } + + # 发送播放停止请求 + stop_url = f"{self.baseUrl}/Sessions/Playing/Stopped" + try: + response = requests.post( + stop_url, + json=stop_data, + headers=header, + timeout=5, + proxies={"http": self.proxy, "https": self.proxy} + ) + if response.status_code == 200 or response.status_code == 204: + print(f"播放停止记录成功: 总时长 {total_duration:.1f}秒") + # 移除会话信息 + if session_id in self.play_sessions: + del self.play_sessions[session_id] + return True + else: + print(f"播放停止记录失败: {response.status_code}, {response.text}") + return False + except Exception as e: + print(f"播放停止记录请求异常: {e}") + return False + + def _start_progress_updater(self, embyInfos, item_id, media_source, session_id): + """启动播放进度更新线程""" + if not session_id: + return + + def progress_updater(): + try: + start_time = time.time() + last_update = start_time + + # 每30秒更新一次播放进度 + while session_id in self.play_sessions: + current_time = time.time() + elapsed = current_time - start_time + + # 每30秒更新一次进度 + if current_time - last_update >= 30: + self._record_playback_progress( + embyInfos, item_id, media_source, session_id, elapsed + ) + last_update = current_time + + # 检查是否超过最大持续时间(2小时) + if elapsed >= 7200: # 2小时 + break + + time.sleep(5) # 每5秒检查一次 + + # 播放结束,记录停止 + if session_id in self.play_sessions: + self._record_playback_stop(session_id) + + except Exception as e: + print(f"播放进度更新线程异常: {e}") + # 确保在异常情况下也尝试记录播放停止 + if session_id in self.play_sessions: + self._record_playback_stop(session_id) + + # 启动线程 + thread = threading.Thread(target=progress_updater, daemon=True) + thread.start() + + def localProxy(self, params): + pass + + def getAccessToken(self): + key = f"emby_{self.baseUrl}_{self.username}_{self.password}" + embyInfos = self.getCache(key) + if embyInfos: + return embyInfos + + header = self.header.copy() + header['Content-Type'] = "application/json; charset=UTF-8" + + auth_data = { + "Username": self.username, + "Pw": self.password + } + + r = requests.post( + f"{self.baseUrl}/emby/Users/AuthenticateByName", + json=auth_data, + headers=header, + timeout=120, + proxies={"http": self.proxy, "https": self.proxy} + ) + embyInfos = r.json() + self.setCache(key, embyInfos) + return embyInfos + + def cleanText(self, text): + # 清理文本中的特殊字符 + if not text: + return "" + return text.replace("\n", " ").replace("\r", " ").replace("\t", " ").strip() \ No newline at end of file diff --git a/lrzy/py/两个BT.py b/lrzy/py/两个BT.py new file mode 100644 index 0000000..1d76f12 --- /dev/null +++ b/lrzy/py/两个BT.py @@ -0,0 +1,599 @@ +# coding=utf-8 +# !/usr/bin/python +import sys +sys.path.append('..') +from base.spider import Spider +import json +import time +import urllib.parse +import re +import base64 + +class Spider(Spider): + + def getName(self): + return "两个BT" + + def init(self, extend=""): + self.host = "https://www.bttwoo.com" + self.headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Connection': 'keep-alive', + 'Referer': self.host + } + self.log(f"两个BT爬虫初始化完成,主站: {self.host}") + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def homeContent(self, filter): + """首页内容 - TVBox标准实现""" + result = {} + + # 1. 定义分类 - 基于实际网站结构 + classes = [ + {'type_id': 'movie_bt_tags/xiju', 'type_name': '喜剧'}, + {'type_id': 'movie_bt_tags/aiqing', 'type_name': '爱情'}, + {'type_id': 'movie_bt_tags/adt', 'type_name': '冒险'}, + {'type_id': 'movie_bt_tags/at', 'type_name': '动作'}, + {'type_id': 'movie_bt_tags/donghua', 'type_name': '动画'}, + {'type_id': 'movie_bt_tags/qihuan', 'type_name': '奇幻'}, + {'type_id': 'movie_bt_tags/xuanni', 'type_name': '悬疑'}, + {'type_id': 'movie_bt_tags/kehuan', 'type_name': '科幻'}, + {'type_id': 'movie_bt_tags/juqing', 'type_name': '剧情'}, + {'type_id': 'movie_bt_tags/kongbu', 'type_name': '恐怖'}, + {'type_id': 'meiju', 'type_name': '美剧'}, + {'type_id': 'gf', 'type_name': '高分电影'} + ] + result['class'] = classes + + # 2. 添加筛选配置 + result['filters'] = self._get_filters() + + # 3. 获取首页推荐内容 + try: + rsp = self.fetch(self.host, headers=self.headers) + doc = self.html(rsp.text) + videos = self._get_videos(doc, limit=50) + result['list'] = videos + except Exception as e: + self.log(f"首页获取出错: {str(e)}") + result['list'] = [] + + return result + + def homeVideoContent(self): + """兼容性方法 - 提供分类定义""" + return { + 'class': [ + {'type_id': 'movie_bt_tags/xiju', 'type_name': '喜剧'}, + {'type_id': 'movie_bt_tags/aiqing', 'type_name': '爱情'}, + {'type_id': 'movie_bt_tags/adt', 'type_name': '冒险'}, + {'type_id': 'movie_bt_tags/at', 'type_name': '动作'}, + {'type_id': 'movie_bt_tags/donghua', 'type_name': '动画'}, + {'type_id': 'movie_bt_tags/qihuan', 'type_name': '奇幻'}, + {'type_id': 'movie_bt_tags/xuanni', 'type_name': '悬疑'}, + {'type_id': 'movie_bt_tags/kehuan', 'type_name': '科幻'}, + {'type_id': 'movie_bt_tags/juqing', 'type_name': '剧情'}, + {'type_id': 'movie_bt_tags/kongbu', 'type_name': '恐怖'}, + {'type_id': 'meiju', 'type_name': '美剧'}, + {'type_id': 'gf', 'type_name': '高分电影'} + ], + 'filters': self._get_filters() + } + + def categoryContent(self, tid, pg, filter, extend): + """分类内容 - 支持筛选功能""" + try: + # 合并filter和extend参数 + if filter and isinstance(filter, dict): + if not extend: + extend = {} + extend.update(filter) + + self.log(f"分类请求: tid={tid}, pg={pg}, extend={extend}") + + url = self._build_url(tid, pg, extend) + if not url: + return {'list': []} + + rsp = self.fetch(url, headers=self.headers) + doc = self.html(rsp.text) + videos = self._get_videos(doc, limit=20) + + return { + 'list': videos, + 'page': int(pg), + 'pagecount': 999, + 'limit': 20, + 'total': 19980 + } + except Exception as e: + self.log(f"分类内容获取出错: {str(e)}") + return {'list': []} + + def searchContent(self, key, quick, pg="1"): + """搜索功能 - 智能过滤""" + try: + search_url = f"{self.host}/xssssearch?q={urllib.parse.quote(key)}" + if pg and pg != "1": + search_url += f"&p={pg}" + + self.log(f"搜索URL: {search_url}") + rsp = self.fetch(search_url, headers=self.headers) + doc = self.html(rsp.text) + + videos = [] + seen_ids = set() + + # 搜索结果选择器 + elements = doc.xpath('//li[contains(@class,"") and .//a[contains(@href,"/movie/")]]') + self.log(f"找到 {len(elements)} 个搜索结果元素") + + for elem in elements: + video = self._extract_video_info(elem, is_search=True) + if video and video['vod_id'] not in seen_ids: + # 添加相关性检查 + if self._is_relevant_search_result(video['vod_name'], key): + videos.append(video) + seen_ids.add(video['vod_id']) + self.log(f"✅ 相关视频: {video['vod_name']} (ID: {video['vod_id']})") + else: + self.log(f"❌ 过滤无关: {video['vod_name']} (搜索: {key})") + + self.log(f"最终搜索结果: {len(videos)} 个视频") + return {'list': videos} + except Exception as e: + self.log(f"搜索出错: {str(e)}") + return {'list': []} + + def detailContent(self, ids): + """详情页面""" + try: + vid = ids[0] + detail_url = f"{self.host}/movie/{vid}.html" + rsp = self.fetch(detail_url, headers=self.headers) + doc = self.html(rsp.text) + + video_info = self._get_detail(doc, vid) + return {'list': [video_info]} if video_info else {'list': []} + except Exception as e: + self.log(f"详情获取出错: {str(e)}") + return {'list': []} + + def playerContent(self, flag, id, vipFlags): + """播放链接""" + try: + self.log(f"获取播放链接: flag={flag}, id={id}") + + # 解码Base64播放ID + try: + decoded_id = base64.b64decode(id).decode('utf-8') + self.log(f"解码播放ID: {decoded_id}") + except: + decoded_id = id + + play_url = f"{self.host}/v_play/{id}.html" + + # 返回播放页面URL,让播放器处理 + return {'parse': 1, 'playUrl': '', 'url': play_url} + except Exception as e: + self.log(f"播放链接获取出错: {str(e)}") + return {'parse': 1, 'playUrl': '', 'url': f"{self.host}/v_play/{id}.html"} + + # ========== 辅助方法 ========== + + def _get_filters(self): + """获取筛选配置 - TVBox兼容版""" + base_filters = [ + { + 'key': 'area', + 'name': '地区', + 'value': [ + {'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'} + ] + } + ] + + # 为每个分类提供筛选配置 + filters = {} + category_ids = [ + 'movie_bt_tags/xiju', 'movie_bt_tags/aiqing', 'movie_bt_tags/adt', + 'movie_bt_tags/at', 'movie_bt_tags/donghua', 'movie_bt_tags/qihuan', + 'movie_bt_tags/xuanni', 'movie_bt_tags/kehuan', 'movie_bt_tags/juqing', + 'movie_bt_tags/kongbu', 'meiju', 'gf' + ] + + for category_id in category_ids: + filters[category_id] = base_filters + + return filters + + def _build_url(self, tid, pg, extend): + """构建URL - 支持筛选""" + try: + # 基础分类URL映射 + if tid.startswith('movie_bt_tags/'): + url = f"{self.host}/{tid}" + elif tid == 'meiju': + url = f"{self.host}/meiju" + elif tid == 'gf': + url = f"{self.host}/gf" + else: + url = f"{self.host}/{tid}" + + # 添加分页 + if pg and pg != '1': + if '?' in url: + url += f"&paged={pg}" + else: + url += f"?paged={pg}" + + return url + except Exception as e: + self.log(f"构建URL出错: {str(e)}") + return f"{self.host}/movie_bt_tags/xiju" + + def _get_videos(self, doc, limit=None): + """获取视频列表""" + try: + videos = [] + seen_ids = set() + + # 尝试多种选择器 + selectors = [ + '//li[.//a[contains(@href,"/movie/")]]', + '//div[contains(@class,"item")]//li[.//a[contains(@href,"/movie/")]]' + ] + + for selector in selectors: + elements = doc.xpath(selector) + if elements: + for elem in elements: + video = self._extract_video_info(elem) + if video and video['vod_id'] not in seen_ids: + videos.append(video) + seen_ids.add(video['vod_id']) + break + + return videos[:limit] if limit and videos else videos + except Exception as e: + self.log(f"获取视频列表出错: {str(e)}") + return [] + + def _extract_video_info(self, element, is_search=False): + """提取视频信息""" + try: + # 提取链接 + links = element.xpath('.//a[contains(@href,"/movie/")]/@href') + if not links: + return None + + link = links[0] + if link.startswith('/'): + link = self.host + link + + vod_id = self.regStr(r'/movie/(\d+)\.html', link) + if not vod_id: + return None + + # 提取标题 + title_selectors = [ + './/h3/a/text()', + './/h3/text()', + './/a/@title', + './/a/text()' + ] + title = '' + for selector in title_selectors: + titles = element.xpath(selector) + for t in titles: + if t and t.strip() and len(t.strip()) > 1: + title = t.strip() + break + if title: + break + + if not title: + return None + + # 提取图片 + pic = self._extract_image(element, is_search, vod_id) + + # 提取备注 + remarks = self._extract_remarks(element) + + return { + 'vod_id': vod_id, + 'vod_name': title, + 'vod_pic': pic, + 'vod_remarks': remarks, + 'vod_year': '' + } + except Exception as e: + self.log(f"提取视频信息出错: {str(e)}") + return None + + def _extract_image(self, element, is_search=False, vod_id=None): + """图片提取 - 处理懒加载""" + pic_selectors = [ + './/img/@data-original', + './/img/@data-src', + './/img/@src' + ] + + for selector in pic_selectors: + pics = element.xpath(selector) + for p in pics: + # 跳过懒加载占位符 + if (p and not p.endswith('blank.gif') and + not p.startswith('data:image/') and 'base64' not in p): + if p.startswith('//'): + return 'https:' + p + elif p.startswith('/'): + return self.host + p + elif p.startswith('http'): + return p + + # 搜索页面特殊处理:从详情页面获取 + if is_search and vod_id: + return self._get_image_from_detail(vod_id) + + return '' + + def _extract_remarks(self, element): + """提取备注信息""" + remarks_selectors = [ + './/span[contains(@class,"rating")]/text()', + './/div[contains(@class,"rating")]/text()', + './/span[contains(@class,"status")]/text()', + './/div[contains(@class,"status")]/text()', + './/span[contains(text(),"集")]/text()', + './/span[contains(text(),"1080p")]/text()', + './/span[contains(text(),"HD")]/text()' + ] + + for selector in remarks_selectors: + remarks_list = element.xpath(selector) + for r in remarks_list: + if r and r.strip(): + return r.strip() + + return '' + + def _get_image_from_detail(self, vod_id): + """从详情页面获取图片""" + try: + detail_url = f"{self.host}/movie/{vod_id}.html" + rsp = self.fetch(detail_url, headers=self.headers) + doc = self.html(rsp.text) + + # 详情页图片选择器 + pic_selectors = [ + '//img[contains(@class,"poster")]/@src', + '//div[contains(@class,"poster")]//img/@src', + '//img[contains(@alt,"")]/@src' + ] + + for selector in pic_selectors: + pics = doc.xpath(selector) + for p in pics: + if p and not p.endswith('blank.gif'): + if p.startswith('//'): + return 'https:' + p + elif p.startswith('/'): + return self.host + p + elif p.startswith('http'): + return p + except: + pass + + return '' + + def _is_relevant_search_result(self, title, search_key): + """检查搜索结果是否与搜索关键词相关""" + if not title or not search_key: + return False + + title_lower = title.lower() + search_key_lower = search_key.lower() + + # 直接包含搜索关键词的肯定相关 + if search_key_lower in title_lower: + return True + + # 字符匹配 + search_chars = set(search_key_lower.replace(' ', '')) + title_chars = set(title_lower.replace(' ', '')) + + if len(search_chars) > 0: + match_ratio = len(search_chars & title_chars) / len(search_chars) + if match_ratio >= 0.6: + return True + + # 短搜索词要求严格匹配 + if len(search_key_lower) <= 2: + return search_key_lower in title_lower + + return False + + def _get_detail(self, doc, vod_id): + """获取详情信息""" + try: + # 提取标题 + title_selectors = [ + '//h1/text()', + '//h2/text()', + '//title/text()' + ] + title = '' + for selector in title_selectors: + titles = doc.xpath(selector) + for t in titles: + if t and t.strip(): + title = t.strip() + break + if title: + break + + # 提取图片 + pic_selectors = [ + '//img[contains(@class,"poster")]/@src', + '//div[contains(@class,"poster")]//img/@src', + '//img/@src' + ] + pic = '' + for selector in pic_selectors: + pics = doc.xpath(selector) + for p in pics: + if p and not p.endswith('blank.gif'): + if p.startswith('//'): + pic = 'https:' + p + elif p.startswith('/'): + pic = self.host + p + elif p.startswith('http'): + pic = p + break + if pic: + break + + # 提取描述 + desc_selectors = [ + '//div[contains(@class,"intro")]//text()', + '//div[contains(@class,"description")]//text()', + '//p[contains(@class,"desc")]//text()' + ] + desc = '' + for selector in desc_selectors: + descs = doc.xpath(selector) + desc_parts = [] + for d in descs: + if d and d.strip(): + desc_parts.append(d.strip()) + if desc_parts: + desc = ' '.join(desc_parts) + break + + # 提取演员 + actor_selectors = [ + '//li[contains(text(),"主演")]/text()', + '//span[contains(text(),"主演")]/following-sibling::text()', + '//div[contains(@class,"actor")]//text()' + ] + actor = '' + for selector in actor_selectors: + actors = doc.xpath(selector) + for a in actors: + if a and a.strip() and '主演' in a: + actor = a.strip().replace('主演:', '').replace('主演', '') + break + if actor: + break + + # 提取导演 + director_selectors = [ + '//li[contains(text(),"导演")]/text()', + '//span[contains(text(),"导演")]/following-sibling::text()', + '//div[contains(@class,"director")]//text()' + ] + director = '' + for selector in director_selectors: + directors = doc.xpath(selector) + for d in directors: + if d and d.strip() and '导演' in d: + director = d.strip().replace('导演:', '').replace('导演', '') + break + if director: + break + + # 提取播放源 + play_sources = self._parse_play_sources(doc, vod_id) + + return { + 'vod_id': vod_id, + 'vod_name': title, + 'vod_pic': pic, + 'type_name': '', + 'vod_year': '', + 'vod_area': '', + 'vod_remarks': '', + 'vod_actor': actor, + 'vod_director': director, + 'vod_content': desc, + 'vod_play_from': '$$$'.join([source['name'] for source in play_sources]), + 'vod_play_url': '$$$'.join([source['episodes'] for source in play_sources]) + } + except Exception as e: + self.log(f"获取详情出错: {str(e)}") + return None + + def _parse_play_sources(self, doc, vod_id): + """解析播放源""" + try: + play_sources = [] + + # 查找播放链接 + episode_selectors = [ + '//a[contains(@href,"/v_play/")]', + '//div[contains(@class,"play")]//a' + ] + + episodes = [] + for selector in episode_selectors: + episode_elements = doc.xpath(selector) + if episode_elements: + for ep in episode_elements: + ep_title = ep.xpath('./text()')[0] if ep.xpath('./text()') else '' + ep_url = ep.xpath('./@href')[0] if ep.xpath('./@href') else '' + + if ep_title and ep_url: + # 提取播放ID + play_id = self.regStr(r'/v_play/([^.]+)\.html', ep_url) + if play_id: + episodes.append(f"{ep_title.strip()}${play_id}") + break + + if episodes: + play_sources.append({ + 'name': '默认播放', + 'episodes': '#'.join(episodes) + }) + else: + # 默认播放源 + play_sources.append({ + 'name': '默认播放', + 'episodes': f'第1集$bXZfMTM0NTY4LW5tXzE=' + }) + + return play_sources + except Exception as e: + self.log(f"解析播放源出错: {str(e)}") + return [{'name': '默认播放', 'episodes': f'第1集$bXZfMTM0NTY4LW5tXzE='}] diff --git a/lrzy/py/云端影视.py b/lrzy/py/云端影视.py new file mode 100644 index 0000000..596a860 --- /dev/null +++ b/lrzy/py/云端影视.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import re +import sys +import threading +import requests +from Crypto.Hash import MD5 +sys.path.append("..") +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad, unpad +from urllib.parse import quote, urlparse +from base64 import b64encode, b64decode +import json +import time +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + self.host = self.gethost() + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def action(self, action): + pass + + def destroy(self): + pass + + def homeContent(self, filter): + data = self.getdata("/api.php/getappapi.index/initV119") + dy = {"class": "类型", "area": "地区", "lang": "语言", "year": "年份", "letter": "字母", "by": "排序", + "sort": "排序"} + filters = {} + classes = [] + json_data = data["type_list"] + homedata = data["banner_list"][8:] + for item in json_data: + if item["type_name"] == "全部": + continue + has_non_empty_field = False + jsontype_extend = json.loads(item["type_extend"]) + homedata.extend(item["recommend_list"]) + jsontype_extend["sort"] = "最新,最热,最赞" + classes.append({"type_name": item["type_name"], "type_id": item["type_id"]}) + for key in dy: + if key in jsontype_extend and jsontype_extend[key].strip() != "": + has_non_empty_field = True + break + if has_non_empty_field: + filters[str(item["type_id"])] = [] + for dkey in jsontype_extend: + if dkey in dy and jsontype_extend[dkey].strip() != "": + values = jsontype_extend[dkey].split(",") + value_array = [{"n": value.strip(), "v": value.strip()} for value in values if + value.strip() != ""] + filters[str(item["type_id"])].append({"key": dkey, "name": dy[dkey], "value": value_array}) + result = {} + result["class"] = classes + result["filters"] = filters + result["list"] = homedata[1:] + return result + + def homeVideoContent(self): + pass + + def categoryContent(self, tid, pg, filter, extend): + body = {"area": extend.get('area', '全部'), "year": extend.get('year', '全部'), "type_id": tid, "page": pg, + "sort": extend.get('sort', '最新'), "lang": extend.get('lang', '全部'), + "class": extend.get('class', '全部')} + result = {} + data = self.getdata("/api.php/getappapi.index/typeFilterVodList", body) + result["list"] = data["recommend_list"] + result["page"] = pg + result["pagecount"] = 9999 + result["limit"] = 90 + result["total"] = 999999 + return result + + def detailContent(self, ids): + body = f"vod_id={ids[0]}" + data = self.getdata("/api.php/getappapi.index/vodDetail", body) + vod = data["vod"] + play = [] + names = [] + for itt in data["vod_play_list"]: + a = [] + names.append(itt["player_info"]["show"]) + for it in itt['urls']: + it['user_agent'] = itt["player_info"].get("user_agent") + it["parse"] = itt["player_info"].get("parse") + a.append(f"{it['name']}${self.e64(json.dumps(it))}") + play.append("#".join(a)) + vod["vod_play_from"] = "$$$".join(names) + vod["vod_play_url"] = "$$$".join(play) + result = {"list": [vod]} + return result + + def searchContent(self, key, quick, pg="1"): + body = f"keywords={key}&type_id=0&page={pg}" + data = self.getdata("/api.php/getappapi.index/searchList", body) + result = {"list": data["search_list"], "page": pg} + return result + + def playerContent(self, flag, id, vipFlags): + ids = json.loads(self.d64(id)) + h = {"User-Agent": (ids['user_agent'] or "okhttp/3.14.9")} + try: + if re.search(r'url=', ids['parse_api_url']): + data = self.fetch(ids['parse_api_url'], headers=h, timeout=10).json() + url = data.get('url') or data['data'].get('url') + else: + body = f"parse_api={ids.get('parse') or ids['parse_api_url'].replace(ids['url'], '')}&url={quote(self.aes(ids['url'], True))}&token={ids.get('token')}" + b = self.getdata("/api.php/getappapi.index/vodParse", body)['json'] + url = json.loads(b)['url'] + if 'error' in url: raise ValueError(f"解析失败: {url}") + p = 0 + except Exception as e: + print('错误信息:', e) + url, p = ids['url'], 1 + + if re.search(r'\.jpg|\.png|\.jpeg', url): + url = self.Mproxy(url) + result = {} + result["parse"] = p + result["url"] = url + result["header"] = h + return result + + def localProxy(self, param): + return self.Mlocal(param) + + def gethost(self): + headers = { + 'User-Agent': 'okhttp/3.14.9' + } + response = self.fetch('https://ydysdynamicdomainname.68.gy:10678/c9m2js298x82h6/l9m8bx23j2o2p9q/dynamicdomainname.txt', + headers=headers).text + return self.host_late(response.split('\n')) + + def host_late(self, url_list): + if isinstance(url_list, str): + urls = [u.strip() for u in url_list.split(',')] + else: + urls = url_list + + if len(urls) <= 1: + return urls[0] if urls else '' + + results = {} + threads = [] + + def test_host(url): + try: + start_time = time.time() + response = requests.head(url,timeout=1.0, allow_redirects=False) + delay = (time.time() - start_time) * 1000 + results[url] = delay + except Exception as e: + results[url] = float('inf') + + for url in urls: + t = threading.Thread(target=test_host, args=(url,)) + threads.append(t) + t.start() + + for t in threads: + t.join() + + return min(results.items(), key=lambda x: x[1])[0] + + def aes(self, text, b=None): + key = b"k9o3p2c8b7m3z0o8" + cipher = AES.new(key, AES.MODE_CBC, key) + if b: + ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size)) + ct = b64encode(ct_bytes).decode("utf-8") + return ct + else: + pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size) + return pt.decode("utf-8") + + def header(self): + t = str(int(time.time())) + header = {"Referer": self.host, + "User-Agent": "okhttp/3.14.9", "app-version-code": "140", "app-ui-mode": "light", + "app-api-verify-time": t, "app-user-device-id": self.md5(t), + "app-api-verify-sign": self.aes(t, True), + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"} + return header + + def getdata(self, path, data=None): + vdata = self.post(f"{self.host}{path}", headers=self.header(), data=data, timeout=10).json()['data'] + data1 = self.aes(vdata) + return json.loads(data1) + + def Mproxy(self, url): + return f"{self.getProxyUrl()}&url={self.e64(url)}&type=m3u8" + + def Mlocal(self, param, header=None): + url = self.d64(param["url"]) + ydata = self.fetch(url, headers=header, allow_redirects=False) + data = ydata.content.decode('utf-8') + if ydata.headers.get('Location'): + url = ydata.headers['Location'] + data = self.fetch(url, headers=header).content.decode('utf-8') + parsed_url = urlparse(url) + durl = parsed_url.scheme + "://" + parsed_url.netloc + lines = data.strip().split('\n') + for index, string in enumerate(lines): + if '#EXT' not in string and 'http' not in string: + last_slash_index = string.rfind('/') + lpath = string[:last_slash_index + 1] + lines[index] = durl + ('' if lpath.startswith('/') else '/') + lpath + data = '\n'.join(lines) + return [200, "application/vnd.apple.mpegur", data] + + def e64(self, text): + try: + text_bytes = text.encode('utf-8') + encoded_bytes = b64encode(text_bytes) + return encoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64编码错误: {str(e)}") + return "" + + def d64(self, encoded_text): + try: + encoded_bytes = encoded_text.encode('utf-8') + decoded_bytes = b64decode(encoded_bytes) + return decoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64解码错误: {str(e)}") + return "" + + def md5(self, text): + h = MD5.new() + h.update(text.encode('utf-8')) + return h.hexdigest() diff --git a/lrzy/py/今日看料.py b/lrzy/py/今日看料.py new file mode 100644 index 0000000..be0c262 --- /dev/null +++ b/lrzy/py/今日看料.py @@ -0,0 +1,716 @@ +# -*- coding: utf-8 -*- +# 🌈 Love +import json +import random +import re +import sys +import threading +import time +from base64 import b64decode, b64encode +from urllib.parse import urlparse, quote + +import requests +from pyquery import PyQuery as pq +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + try:self.proxies = json.loads(extend) + except:self.proxies = {} + self.headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9', + 'Connection': 'keep-alive', + 'Cache-Control': 'no-cache', + } + # Use working dynamic URLs directly + self.host = self.get_working_host() + self.headers.update({'Origin': self.host, 'Referer': f"{self.host}/"}) + self.log(f"使用站点: {self.host}") + print(f"使用站点: {self.host}") + pass + + def getName(self): + return "🌈 今日看料" + + def isVideoFormat(self, url): + # Treat direct media formats as playable without parsing + return any(ext in (url or '') for ext in ['.m3u8', '.mp4', '.ts']) + + def manualVideoCheck(self): + return False + + def destroy(self): + pass + + def homeContent(self, filter): + try: + response = requests.get(self.host, headers=self.headers, proxies=self.proxies, timeout=15) + if response.status_code != 200: + return {'class': [], 'list': []} + + data = self.getpq(response.text) + result = {} + classes = [] + + # 优先从导航栏获取分类 + nav_selectors = [ + '#navbarCollapse .navbar-nav .nav-item .nav-link', + '.navbar-nav .nav-item .nav-link', + '#nav .menu-item a', + '.menu .menu-item a' + ] + + found_categories = False + for selector in nav_selectors: + for item in data(selector).items(): + href = item.attr('href') or '' + name = item.text().strip() + + # 过滤掉非分类链接 + if (not href or not name or + href == '#' or + href.startswith('http') or + 'about' in href.lower() or + 'contact' in href.lower() or + 'tags' in href.lower() or + 'top' in href.lower() or + 'start' in href.lower() or + 'time' in href.lower()): + continue + + # 确保是分类链接(包含category或明确的分类路径) + if '/category/' in href or any(cat in href for cat in ['/dy/', '/ks/', '/douyu/', '/hy/', '/hj/', '/tt/', '/wh/', '/asmr/', '/xb/', '/xsp/', '/rdgz/']): + # 处理相对路径 + if href.startswith('/'): + type_id = href + else: + type_id = f'/{href}' + + classes.append({ + 'type_name': name, + 'type_id': type_id + }) + found_categories = True + + # 如果导航栏没找到,尝试从分类下拉菜单获取 + if not found_categories: + category_selectors = [ + '.category-list a', + '.slide-toggle + .category-list a', + '.menu .category-list a' + ] + for selector in category_selectors: + for item in data(selector).items(): + href = item.attr('href') or '' + name = item.text().strip() + + if href and name and href != '#': + if href.startswith('/'): + type_id = href + else: + type_id = f'/{href}' + + classes.append({ + 'type_name': name, + 'type_id': type_id + }) + found_categories = True + + # 去重 + unique_classes = [] + seen_ids = set() + for cls in classes: + if cls['type_id'] not in seen_ids: + unique_classes.append(cls) + seen_ids.add(cls['type_id']) + + # 如果没有找到分类,创建默认分类 + if not unique_classes: + unique_classes = [ + {'type_name': '热点关注', 'type_id': '/category/rdgz/'}, + {'type_name': '抖音', 'type_id': '/category/dy/'}, + {'type_name': '快手', 'type_id': '/category/ks/'}, + {'type_name': '斗鱼', 'type_id': '/category/douyu/'}, + {'type_name': '虎牙', 'type_id': '/category/hy/'}, + {'type_name': '花椒', 'type_id': '/category/hj/'}, + {'type_name': '推特', 'type_id': '/category/tt/'}, + {'type_name': '网红', 'type_id': '/category/wh/'}, + {'type_name': 'ASMR', 'type_id': '/category/asmr/'}, + {'type_name': 'X播', 'type_id': '/category/xb/'}, + {'type_name': '小视频', 'type_id': '/category/xsp/'} + ] + + result['class'] = unique_classes + result['list'] = self.getlist(data('#index article a, #archive article a')) + return result + + except Exception as e: + print(f"homeContent error: {e}") + return {'class': [], 'list': []} + + def homeVideoContent(self): + try: + response = requests.get(self.host, headers=self.headers, proxies=self.proxies, timeout=15) + if response.status_code != 200: + return {'list': []} + data = self.getpq(response.text) + return {'list': self.getlist(data('#index article a, #archive article a'))} + except Exception as e: + print(f"homeVideoContent error: {e}") + return {'list': []} + + def categoryContent(self, tid, pg, filter, extend): + try: + # 修复URL构建 - 去除多余的斜杠 + base_url = tid.lstrip('/').rstrip('/') + if pg and pg != '1': + url = f"{self.host}{base_url}/{pg}/" + else: + url = f"{self.host}{base_url}/" + + print(f"分类页面URL: {url}") + + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15) + if response.status_code != 200: + print(f"分类页面请求失败: {response.status_code}") + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0} + + data = self.getpq(response.text) + videos = self.getlist(data('#archive article a, #index article a, .post-card'), tid) + + # 如果没有找到视频,尝试其他选择器 + if not videos: + videos = self.getlist(data('article a, .post a, .entry-title a'), tid) + + print(f"找到 {len(videos)} 个视频") + + # 改进的页数检测逻辑 + pagecount = self.detect_page_count(data, pg) + + result = {} + result['list'] = videos + result['page'] = pg + result['pagecount'] = pagecount + result['limit'] = 90 + result['total'] = 999999 + return result + + except Exception as e: + print(f"categoryContent error: {e}") + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0} + + def tagContent(self, tid, pg, filter, extend): + """标签页面内容""" + try: + # 修复URL构建 - 去除多余的斜杠 + base_url = tid.lstrip('/').rstrip('/') + if pg and pg != '1': + url = f"{self.host}{base_url}/{pg}/" + else: + url = f"{self.host}{base_url}/" + + print(f"标签页面URL: {url}") + + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15) + if response.status_code != 200: + print(f"标签页面请求失败: {response.status_code}") + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0} + + data = self.getpq(response.text) + videos = self.getlist(data('#archive article a, #index article a, .post-card'), tid) + + # 如果没有找到视频,尝试其他选择器 + if not videos: + videos = self.getlist(data('article a, .post a, .entry-title a'), tid) + + print(f"找到 {len(videos)} 个标签相关视频") + + # 页数检测 + pagecount = self.detect_page_count(data, pg) + + result = {} + result['list'] = videos + result['page'] = pg + result['pagecount'] = pagecount + result['limit'] = 90 + result['total'] = 999999 + return result + + except Exception as e: + print(f"tagContent error: {e}") + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0} + + def detect_page_count(self, data, current_page): + """改进的页数检测方法""" + pagecount = 99999 # 默认大数字,允许无限翻页 + + # 方法1: 检查分页器中的所有页码链接 + page_numbers = [] + + # 查找所有可能的页码链接 + page_selectors = [ + '.page-navigator a', + '.pagination a', + '.pages a', + '.page-numbers a' + ] + + for selector in page_selectors: + for page_link in data(selector).items(): + href = page_link.attr('href') or '' + text = page_link.text().strip() + + # 从href中提取页码 + if href: + # 匹配 /category/dy/2/ 这种格式 + match = re.search(r'/(\d+)/?$', href.rstrip('/')) + if match: + page_num = int(match.group(1)) + if page_num not in page_numbers: + page_numbers.append(page_num) + + # 从文本中提取数字页码 + if text and text.isdigit(): + page_num = int(text) + if page_num not in page_numbers: + page_numbers.append(page_num) + + # 如果有找到页码,取最大值 + if page_numbers: + max_page = max(page_numbers) + print(f"从分页器检测到最大页码: {max_page}") + return max_page + + # 方法2: 检查是否存在"下一页"按钮 + next_selectors = [ + '.page-navigator .next', + '.pagination .next', + '.next-page', + 'a:contains("下一页")' + ] + + for selector in next_selectors: + if data(selector): + print("检测到下一页按钮,允许继续翻页") + return 99999 + + # 方法3: 如果当前页视频数量很少,可能没有下一页 + if len(data('#archive article, #index article, .post-card')) < 5: + print("当前页内容较少,可能没有下一页") + return int(current_page) + + print("使用默认页数: 99999") + return 99999 + + def detailContent(self, ids): + try: + url = f"{self.host}{ids[0]}" if not ids[0].startswith('http') else ids[0] + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15) + + if response.status_code != 200: + return {'list': [{'vod_play_from': '今日看料', 'vod_play_url': f'页面加载失败${url}'}]} + + data = self.getpq(response.text) + vod = {'vod_play_from': '今日看料'} + + # 获取标题 + title_selectors = ['.post-title', 'h1.entry-title', 'h1', '.post-card-title'] + for selector in title_selectors: + title_elem = data(selector) + if title_elem: + vod['vod_name'] = title_elem.text().strip() + break + + if 'vod_name' not in vod: + vod['vod_name'] = '今日看料视频' + + # 获取内容/描述 + try: + clist = [] + if data('.tags .keywords a'): + for k in data('.tags .keywords a').items(): + title = k.text() + href = k.attr('href') + if title and href: + # 使href相对路径 + if href.startswith(self.host): + href = href.replace(self.host, '') + clist.append('[a=cr:' + json.dumps({'id': href, 'name': title}) + '/]' + title + '[/a]') + vod['vod_content'] = ' '.join(clist) if clist else data('.post-content').text() or vod['vod_name'] + except: + vod['vod_content'] = vod['vod_name'] + + # 获取视频URLs + try: + plist = [] + used_names = set() + + # 查找DPlayer视频 + if data('.dplayer'): + for c, k in enumerate(data('.dplayer').items(), start=1): + config_attr = k.attr('data-config') + if config_attr: + try: + config = json.loads(config_attr) + video_url = config.get('video', {}).get('url', '') + if video_url: + name = f"视频{c}" + count = 2 + while name in used_names: + name = f"视频{c}_{count}" + count += 1 + used_names.add(name) + self.log(f"解析到视频: {name} -> {video_url}") + print(f"解析到视频: {name} -> {video_url}") + plist.append(f"{name}${video_url}") + except: + continue + + # 查找视频标签 + if not plist: + video_selectors = ['video source', 'video', 'iframe[src*="video"]', 'a[href*=".m3u8"]', 'a[href*=".mp4"]'] + for selector in video_selectors: + for c, elem in enumerate(data(selector).items(), start=1): + src = elem.attr('src') or elem.attr('href') or '' + if src and any(ext in src for ext in ['.m3u8', '.mp4', 'video']): + name = f"视频{c}" + count = 2 + while name in used_names: + name = f"视频{c}_{count}" + count += 1 + used_names.add(name) + plist.append(f"{name}${src}") + + if plist: + self.log(f"拼装播放列表,共{len(plist)}个") + print(f"拼装播放列表,共{len(plist)}个") + vod['vod_play_url'] = '#'.join(plist) + else: + vod['vod_play_url'] = f"正片${url}" + + except Exception as e: + print(f"视频解析错误: {e}") + vod['vod_play_url'] = f"正片${url}" + + return {'list': [vod]} + + except Exception as e: + print(f"detailContent error: {e}") + return {'list': [{'vod_play_from': '今日看料', 'vod_play_url': f'详情页加载失败${ids[0] if ids else ""}'}]} + + def searchContent(self, key, quick, pg="1"): + try: + # 优先使用标签搜索 + encoded_key = quote(key) + url = f"{self.host}/tag/{encoded_key}/{pg}" if pg != "1" else f"{self.host}/tag/{encoded_key}/" + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15) + + if response.status_code != 200: + # 尝试搜索页面 + url = f"{self.host}/search/{encoded_key}/{pg}" if pg != "1" else f"{self.host}/search/{encoded_key}/" + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15) + + if response.status_code != 200: + return {'list': [], 'page': pg} + + data = self.getpq(response.text) + videos = self.getlist(data('#archive article a, #index article a, .post-card')) + + # 使用改进的页数检测方法 + pagecount = self.detect_page_count(data, pg) + + return {'list': videos, 'page': pg, 'pagecount': pagecount} + + except Exception as e: + print(f"searchContent error: {e}") + return {'list': [], 'page': pg} + + def getTagsContent(self, pg="1"): + """获取标签页面内容""" + try: + url = f"{self.host}/tags.html" + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=15) + + if response.status_code != 200: + return {'list': [], 'page': pg} + + data = self.getpq(response.text) + tags = [] + + # 从标签页面提取所有标签 - 使用更宽松的选择器 + for tag_elem in data('a[href*="/tag/"]').items(): + tag_name = tag_elem.text().strip() + tag_href = tag_elem.attr('href') or '' + + if tag_name and tag_href and '/tag/' in tag_href and tag_name != '全部标签': # 排除标题链接 + # 处理为相对路径 + tag_id = tag_href.replace(self.host, '') + if not tag_id.startswith('/'): + tag_id = '/' + tag_id + + tags.append({ + 'vod_id': tag_id, + 'vod_name': f"🏷️ {tag_name}", + 'vod_pic': '', + 'vod_remarks': '标签', + 'vod_tag': 'tag', + 'style': {"type": "rect", "ratio": 1.33} + }) + + print(f"找到 {len(tags)} 个标签") + + # 分页处理 - 标签页面通常不需要分页 + result = {} + result['list'] = tags + result['page'] = pg + result['pagecount'] = 1 # 标签页面通常只有一页 + result['limit'] = 999 + result['total'] = len(tags) + return result + + except Exception as e: + print(f"getTagsContent error: {e}") + return {'list': [], 'page': pg} + + def playerContent(self, flag, id, vipFlags): + url = id + p = 1 + if self.isVideoFormat(url): + if '.m3u8' in url: + url = self.proxy(url) + p = 0 + self.log(f"播放请求: parse={p}, url={url}") + print(f"播放请求: parse={p}, url={url}") + return {'parse': p, 'url': url, 'header': self.headers} + + def localProxy(self, param): + try: + if param.get('type') == 'img': + img_url = self.d64(param['url']) + if not img_url.startswith(('http://', 'https://')): + if img_url.startswith('/'): + img_url = f"{self.host}{img_url}" + else: + img_url = f"{self.host}/{img_url}" + + res = requests.get(img_url, headers=self.headers, proxies=self.proxies, timeout=10) + return [200, res.headers.get('Content-Type', 'image/jpeg'), res.content] + elif param.get('type') == 'm3u8': + return self.m3Proxy(param['url']) + else: + return self.tsProxy(param['url']) + except Exception as e: + print(f"localProxy error: {e}") + return [500, "text/plain", f"Proxy error: {str(e)}".encode()] + + def proxy(self, data, type='m3u8'): + if data and len(self.proxies): + return f"{self.getProxyUrl()}&url={self.e64(data)}&type={type}" + else: + return data + + def m3Proxy(self, url): + try: + url = self.d64(url) + ydata = requests.get(url, headers=self.headers, proxies=self.proxies, allow_redirects=False) + data = ydata.content.decode('utf-8') + if ydata.headers.get('Location'): + url = ydata.headers['Location'] + data = requests.get(url, headers=self.headers, proxies=self.proxies).content.decode('utf-8') + lines = data.strip().split('\n') + last_r = url[:url.rfind('/')] + parsed_url = urlparse(url) + durl = parsed_url.scheme + "://" + parsed_url.netloc + iskey = True + for index, string in enumerate(lines): + if iskey and 'URI' in string: + pattern = r'URI="([^"]*)"' + match = re.search(pattern, string) + if match: + lines[index] = re.sub(pattern, f'URI="{self.proxy(match.group(1), "mkey")}"', string) + iskey = False + continue + if '#EXT' not in string: + if 'http' not in string: + domain = last_r if string.count('/') < 2 else durl + string = domain + ('' if string.startswith('/') else '/') + string + lines[index] = self.proxy(string, string.split('.')[-1].split('?')[0]) + data = '\n'.join(lines) + return [200, "application/vnd.apple.mpegur", data] + except Exception as e: + print(f"m3Proxy error: {e}") + return [500, "text/plain", f"m3u8 proxy error: {str(e)}".encode()] + + def tsProxy(self, url): + try: + url = self.d64(url) + data = requests.get(url, headers=self.headers, proxies=self.proxies, stream=True) + return [200, data.headers.get('Content-Type', 'video/mp2t'), data.content] + except Exception as e: + print(f"tsProxy error: {e}") + return [500, "text/plain", f"ts proxy error: {str(e)}".encode()] + + def e64(self, text): + try: + text_bytes = text.encode('utf-8') + encoded_bytes = b64encode(text_bytes) + return encoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64编码错误: {str(e)}") + return "" + + def d64(self, encoded_text): + try: + encoded_bytes = encoded_text.encode('utf-8') + decoded_bytes = b64decode(encoded_bytes) + return decoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64解码错误: {str(e)}") + return "" + + def get_working_host(self): + """Get working host from known dynamic URLs""" + dynamic_urls = [ + 'https://kanliao25.com//', + 'https://kanliao7.org/', + 'https://kanliao7.net/', + 'https://kanliao14.com/' + ] + + for url in dynamic_urls: + try: + response = requests.get(url, headers=self.headers, proxies=self.proxies, timeout=10) + if response.status_code == 200: + data = self.getpq(response.text) + articles = data('#index article a, #archive article a') + if len(articles) > 0: + self.log(f"选用可用站点: {url}") + print(f"选用可用站点: {url}") + return url + except Exception as e: + continue + + self.log(f"未检测到可用站点,回退: {dynamic_urls[0]}") + print(f"未检测到可用站点,回退: {dynamic_urls[0]}") + return dynamic_urls[0] + + def getlist(self, data, tid=''): + videos = [] + for k in data.items(): + a = k.attr('href') + b = k('h2').text() or k('.post-card-title').text() or k('.entry-title').text() or k.text() + c = k('span[itemprop="datePublished"]').text() or k('.post-meta, .entry-meta, time, .post-card-info').text() + + # 过滤广告:检查是否包含"热搜HOT"标志 + if self.is_advertisement(k): + print(f"过滤广告: {b}") + continue + + if a and b and b.strip(): + # 处理相对路径 + if not a.startswith('http'): + if a.startswith('/'): + vod_id = a + else: + vod_id = f'/{a}' + else: + vod_id = a + + videos.append({ + 'vod_id': vod_id, + 'vod_name': b.replace('\n', ' ').strip(), + 'vod_pic': self.get_article_img(k), + 'vod_remarks': c.strip() if c else '', + 'vod_tag': '', + 'style': {"type": "rect", "ratio": 1.33} + }) + return videos + + def is_advertisement(self, article_elem): + """判断是否为广告(包含热搜HOT标志)""" + # 检查.wraps元素是否包含"热搜HOT"文本 + hot_elements = article_elem.find('.wraps') + for elem in hot_elements.items(): + if '热搜HOT' in elem.text(): + return True + + # 检查标题是否包含广告关键词 + title = article_elem('h2').text() or article_elem('.post-card-title').text() or '' + ad_keywords = ['热搜HOT', '手机链接', 'DNS设置', '修改DNS', 'WIFI设置'] + if any(keyword in title for keyword in ad_keywords): + return True + + # 检查背景颜色是否为广告特有的渐变背景 + style = article_elem.attr('style') or '' + if 'background:' in style and any(gradient in style for gradient in ['-webkit-linear-gradient', 'linear-gradient']): + # 进一步检查是否包含特定的广告颜色组合 + ad_gradients = ['#ec008c,#fc6767', '#ffe259,#ffa751'] + if any(gradient in style for gradient in ad_gradients): + return True + + return False + + def get_article_img(self, article_elem): + """从文章元素中提取图片,多种方式尝试""" + # 方式1: 从script标签中提取loadBannerDirect + script_text = article_elem('script').text() + if script_text: + match = re.search(r"loadBannerDirect\('([^']+)'", script_text) + if match: + url = match.group(1) + if not url.startswith(('http://', 'https://')): + if url.startswith('/'): + url = f"{self.host}{url}" + else: + url = f"{self.host}/{url}" + return f"{self.getProxyUrl()}&url={self.e64(url)}&type=img" + + # 方式2: 从背景图片中提取 + bg_elem = article_elem.find('.blog-background') + if bg_elem: + style = bg_elem.attr('style') or '' + bg_match = re.search(r'background-image:\s*url\(["\']?([^"\'\)]+)["\']?\)', style) + if bg_match: + img_url = bg_match.group(1) + if img_url and not img_url.startswith('data:'): + if not img_url.startswith(('http://', 'https://')): + if img_url.startswith('/'): + img_url = f"{self.host}{img_url}" + else: + img_url = f"{self.host}/{img_url}" + return f"{self.getProxyUrl()}&url={self.e64(img_url)}&type=img" + + # 方式3: 从图片标签中提取 + img_elem = article_elem.find('img') + if img_elem: + data_src = img_elem.attr('data-src') + if data_src: + if not data_src.startswith(('http://', 'https://')): + if data_src.startswith('/'): + data_src = f"{self.host}{data_src}" + else: + data_src = f"{self.host}/{data_src}" + return f"{self.getProxyUrl()}&url={self.e64(data_src)}&type=img" + + src = img_elem.attr('src') + if src: + if not src.startswith(('http://', 'https://')): + if src.startswith('/'): + src = f"{self.host}{src}" + else: + src = f"{self.host}/{src}" + return f"{self.getProxyUrl()}&url={self.e64(src)}&type=img" + + return '' + + def getpq(self, data): + try: + return pq(data) + except Exception as e: + print(f"{str(e)}") + return pq(data.encode('utf-8')) \ No newline at end of file diff --git a/lrzy/py/优酷视频.py b/lrzy/py/优酷视频.py new file mode 100644 index 0000000..399d0db --- /dev/null +++ b/lrzy/py/优酷视频.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import json +import sys +import time +from concurrent.futures import ThreadPoolExecutor, as_completed +from urllib.parse import quote +from Crypto.Hash import MD5 +import requests +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + self.session = requests.Session() + self.session.headers.update(self.headers) + self.session.cookies.update(self.cookie) + self.get_ctoken() + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host='https://www.youku.com' + + shost='https://search.youku.com' + + h5host='https://acs.youku.com' + + ihost='https://v.youku.com' + + headers = { + 'User-Agent': 'Mozilla/5.0 (; Windows 10.0.26100.3194_64 ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Electron/14.2.0 Safari/537.36 Node/14.17.0 YoukuDesktop/9.2.60 UOSYouku (2.0.1)-Electron(UTDID ZYmGMAAAACkDAMU8hbiMmYdd;CHANNEL official;ZREAL 0;BTYPE TM2013;BRAND TIMI;BUILDVER 9.2.60.1001)', + 'Referer': f'{host}/' + } + + cookie={ + "__ysuid": "17416134165380iB", + "__aysid": "1741613416541WbD", + "xlly_s": "1", + "isI18n": "false", + "cna": "bNdVIKmmsHgCAXW9W6yrQ1/s", + "__ayft": "1741672162330", + "__arpvid": "1741672162331FBKgrn-1741672162342", + "__ayscnt": "1", + "__aypstp": "1", + "__ayspstp": "3", + "tfstk": "gZbiib4JpG-6DqW-B98_2rwPuFrd1fTXQt3vHEp4YpJIBA3OgrWcwOi90RTOo9XVQ5tAM5NcK_CP6Ep97K2ce1XDc59v3KXAgGFLyzC11ET2n8U8yoyib67M3xL25e8gS8pbyzC1_ET4e8URWTsSnHv2uh8VTeJBgEuN3d-ELQAWuKWV36PHGpJ2uEWVTxvicLX1ewyUXYSekxMf-CxMEqpnoqVvshvP_pABOwvXjL5wKqeulm52np_zpkfCDGW9Ot4uKFIRwZtP7vP9_gfAr3KEpDWXSIfWRay-DHIc_Z-hAzkD1i5Ooi5LZ0O5YO_1mUc476YMI3R6xzucUnRlNe_zemKdm172xMwr2L7CTgIkbvndhFAVh3_YFV9Ng__52U4SQKIdZZjc4diE4EUxlFrfKmiXbBOHeP72v7sAahuTtWm78hRB1yV3tmg9bBOEhWVnq5KwOBL5." + } + + def homeContent(self, filter): + result = {} + categories = ["电视剧", "电影", "综艺", "动漫", "少儿", "纪录片", "文化", "亲子", "教育", "搞笑", "生活", + "体育", "音乐", "游戏"] + classes = [{'type_name': category, 'type_id': category} for category in categories] + filters = {} + self.typeid = {} + with ThreadPoolExecutor(max_workers=len(categories)) as executor: + tasks = { + executor.submit(self.cf, {'type': category}, True): category + for category in categories + } + + for future in as_completed(tasks): + try: + category = tasks[future] + session, ft = future.result() + filters[category] = ft + self.typeid[category] = session + except Exception as e: + print(f"处理分类 {tasks[future]} 时出错: {str(e)}") + + result['class'] = classes + result['filters'] = filters + return result + + def homeVideoContent(self): + try: + vlist = [] + params={"ms_codes":"2019061000","params":"{\"debug\":0,\"gray\":0,\"pageNo\":1,\"utdid\":\"ZYmGMAAAACkDAMU8hbiMmYdd\",\"userId\":\"\",\"bizKey\":\"YOUKU_WEB\",\"appPackageKey\":\"com.youku.YouKu\",\"showNodeList\":0,\"reqSubNode\":0,\"nodeKey\":\"WEBHOME\",\"bizContext\":\"{\\\"spmA\\\":\\\"a2hja\\\"}\"}","system_info":"{\"device\":\"pcweb\",\"os\":\"pcweb\",\"ver\":\"1.0.0.0\",\"userAgent\":\"Mozilla/5.0 (; Windows 10.0.26100.3194_64 ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Electron/14.2.0 Safari/537.36 Node/14.17.0 YoukuDesktop/9.2.60 UOSYouku (2.0.1)-Electron(UTDID ZYmGMAAAACkDAMU8hbiMmYdd;CHANNEL official;ZREAL 0;BTYPE TM2013;BRAND TIMI;BUILDVER 9.2.60.1001)\",\"guid\":\"1590141704165YXe\",\"appPackageKey\":\"com.youku.pcweb\",\"young\":0,\"brand\":\"\",\"network\":\"\",\"ouid\":\"\",\"idfa\":\"\",\"scale\":\"\",\"operator\":\"\",\"resolution\":\"\",\"pid\":\"\",\"childGender\":0,\"zx\":0}"} + data=self.getdata(f'{self.h5host}/h5/mtop.youku.columbus.home.query/1.0/',params) + okey=list(data['data'].keys())[0] + for i in data['data'][okey]['data']['nodes'][0]['nodes'][-1]['nodes'][0]['nodes']: + if i.get('nodes') and i['nodes'][0].get('data'): + i=i['nodes'][0]['data'] + if i.get('assignId'): + vlist.append({ + 'vod_id': i['assignId'], + 'vod_name': i.get('title'), + 'vod_pic': i.get('vImg') or i.get('img'), + 'vod_year': i.get('mark',{}).get('data',{}).get('text'), + 'vod_remarks': i.get('summary') + }) + return {'list': vlist} + except Exception as e: + print(f"处理主页视频数据时出错: {str(e)}") + return {'list': []} + + def categoryContent(self, tid, pg, filter, extend): + result = {} + vlist = [] + result['page'] = pg + result['limit'] = 90 + result['total'] = 999999 + pagecount = 9999 + params = {'type': tid} + id = self.typeid[tid] + params.update(extend) + if pg == '1': + id=self.cf(params) + data=self.session.get(f'{self.host}/category/data?session={id}¶ms={quote(json.dumps(params))}&pageNo={pg}').json() + try: + data=data['data']['filterData'] + for i in data['listData']: + if i.get('videoLink') and 's=' in i['videoLink']: + vlist.append({ + 'vod_id': i.get('videoLink').split('s=')[-1], + 'vod_name': i.get('title'), + 'vod_pic': i.get('img'), + 'vod_year': i.get('rightTagText'), + 'vod_remarks': i.get('summary') + }) + self.typeid[tid]=quote(json.dumps(data['session'])) + except: + pagecount=pg + result['list'] = vlist + result['pagecount'] = pagecount + return result + + def detailContent(self, ids): + try: + data=self.session.get(f'{self.ihost}/v_getvideo_info/?showId={ids[0]}').json() + v=data['data'] + vod = { + 'type_name': v.get('showVideotype'), + 'vod_year': v.get('lastUpdate'), + 'vod_remarks': v.get('rc_title'), + 'vod_actor': v.get('_personNameStr'), + 'vod_content': v.get('showdesc'), + 'vod_play_from': '优酷', + 'vod_play_url': '' + } + params={"biz":"new_detail_web2","videoId":v.get('vid'),"scene":"web_page","componentVersion":"3","ip":data.get('ip'),"debug":0,"utdid":"ZYmGMAAAACkDAMU8hbiMmYdd","userId":0,"platform":"pc","nextSession":"","gray":0,"source":"pcNoPrev","showId":ids[0]} + sdata,index=self.getinfo(params) + pdata=sdata['nodes'] + if index > len(pdata): + batch_size = len(pdata) + total_batches = ((index + batch_size - 1) // batch_size) - 1 + ssj = json.loads(sdata['data']['session']) + with ThreadPoolExecutor(max_workers=total_batches) as executor: + futures = [] + for batch in range(total_batches): + start = batch_size + 1 + (batch * batch_size) + end = start + batch_size - 1 + next_session = ssj.copy() + next_session.update({ + "itemStartStage": start, + "itemEndStage": min(end, index) + }) + current_params = params.copy() + current_params['nextSession'] = json.dumps(next_session) + futures.append((start, executor.submit(self.getvinfo, current_params))) + futures.sort(key=lambda x: x[0]) + + for _, future in futures: + try: + result = future.result() + pdata.extend(result['nodes']) + except Exception as e: + print(f"Error fetching data: {str(e)}") + vod['vod_play_url'] = '#'.join([f"{i['data'].get('title')}${i['data']['action'].get('value')}" for i in pdata]) + return {'list': [vod]} + except Exception as e: + print(e) + return {'list': [{'vod_play_from': '哎呀翻车啦', 'vod_play_url': f'呜呜呜${self.host}'}]} + + def searchContent(self, key, quick, pg="1"): + data=self.session.get(f'{self.shost}/api/search?pg={pg}&keyword={key}').json() + vlist = [] + for i in data['pageComponentList']: + if i.get('commonData') and (i['commonData'].get('showId') or i['commonData'].get('realShowId')): + i=i['commonData'] + vlist.append({ + 'vod_id': i.get('showId') or i.get('realShowId'), + 'vod_name': i['titleDTO'].get('displayName'), + 'vod_pic': i['posterDTO'].get('vThumbUrl'), + 'vod_year': i.get('feature'), + 'vod_remarks': i.get('updateNotice') + }) + return {'list': vlist, 'page': pg} + + def playerContent(self, flag, id, vipFlags): + return {'jx':1,'parse': 1, 'url': f"{self.ihost}/video?vid={id}", 'header': ''} + + def localProxy(self, param): + pass + + def cf(self,params,b=False): + response = self.session.get(f'{self.host}/category/data?params={quote(json.dumps(params))}&optionRefresh=1&pageNo=1').json() + data=response['data']['filterData'] + session=quote(json.dumps(data['session'])) + if b: + return session,self.get_filter_data(data['filter']['filterData'][1:]) + return session + + def process_key(self, key): + if '_' not in key: + return key + parts = key.split('_') + result = parts[0] + for part in parts[1:]: + if part: + result += part[0].upper() + part[1:] + return result + + def get_filter_data(self, data): + result = [] + try: + for item in data: + if not item.get('subFilter'): + continue + first_sub = item['subFilter'][0] + if not first_sub.get('filterType'): + continue + filter_item = { + 'key': self.process_key(first_sub['filterType']), + 'name': first_sub['title'], + 'value': [] + } + for sub in item['subFilter']: + if 'value' in sub: + filter_item['value'].append({ + 'n': sub['title'], + 'v': sub['value'] + }) + if filter_item['value']: + result.append(filter_item) + + except Exception as e: + print(f"处理筛选数据时出错: {str(e)}") + + return result + + def get_ctoken(self): + data=self.session.get(f'{self.h5host}/h5/mtop.ykrec.recommendservice.recommend/1.0/?jsv=2.6.1&appKey=24679788') + + def md5(self,t,text): + h = MD5.new() + token=self.session.cookies.get('_m_h5_tk').split('_')[0] + data=f"{token}&{t}&24679788&{text}" + h.update(data.encode('utf-8')) + return h.hexdigest() + + def getdata(self, url, params, recursion_count=0, max_recursion=3): + data = json.dumps(params) + t = int(time.time() * 1000) + jsdata = { + 'appKey': '24679788', + 't': t, + 'sign': self.md5(t, data), + 'data': data + } + response = self.session.get(url, params=jsdata) + if '令牌过期' in response.text: + if recursion_count >= max_recursion: + raise Exception("达到最大递归次数,无法继续请求") + self.get_ctoken() + return self.getdata(url, params, recursion_count + 1, max_recursion) + else: + return response.json() + + def getvinfo(self,params): + body = { + "ms_codes": "2019030100", + "params": json.dumps(params), + "system_info": "{\"os\":\"iku\",\"device\":\"iku\",\"ver\":\"9.2.9\",\"appPackageKey\":\"com.youku.iku\",\"appPackageId\":\"pcweb\"}" + } + data = self.getdata(f'{self.h5host}/h5/mtop.youku.columbus.gateway.new.execute/1.0/', body) + okey = list(data['data'].keys())[0] + i = data['data'][okey]['data'] + return i + + def getinfo(self,params): + i = self.getvinfo(params) + jdata=i['nodes'][0]['nodes'][3] + info=i['data']['extra']['episodeTotal'] + if i['data']['extra']['showCategory'] in ['电影','游戏']: + jdata = i['nodes'][0]['nodes'][4] + return jdata,info + diff --git a/lrzy/py/兄弟影视.min.py b/lrzy/py/兄弟影视.min.py new file mode 100644 index 0000000..26d5d81 --- /dev/null +++ b/lrzy/py/兄弟影视.min.py @@ -0,0 +1,62 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# @Author : Doubebly +# @Time : 2025/11/16 22:12 +# @file : 兄弟影视.min.py +#!/usr/bin/python3 + +R='vod_pic' +Q='span.public-list-prb.hide.ft2' +P='data-src' +O=print +L='vod_remarks' +K='vod_name' +J='vod_id' +I='href' +G='a' +F='jx' +E='parse' +D='type_name' +B='list' +A='' +import hashlib as Z,json,re,sys,time as M,requests as C +from urllib import parse as N +from pyquery import PyQuery as H +sys.path.append('..') +from base.spider import Spider as S +class Spider(S): + def __init__(A):super().__init__();A.debug=False;A.name='兄弟影视';A.error_play_url='https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4';A.home_url='https://www.brovods.top';A.headers={'User-Agent':'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36'} + def getName(A):return A.name + def init(A,extend='{}'):A.extend=extend + def getDependence(A):return[] + def isVideoFormat(A,url):0 + def manualVideoCheck(A):0 + def liveContent(B,url):return A + def homeContent(G,filter):A='type_id';C={'class':[{A:'Movies',D:'电影'},{A:'TV',D:'剧集'},{A:'Shows',D:'综艺'},{A:'Anime',D:'动漫'},{A:'Snaps',D:'短剧'},{A:'Documentaries',D:'纪录片'}],'filters':{},B:[],E:0,F:0};return C + def homeVideoContent(C):A={B:[],E:0,F:0};return A + def categoryContent(D,cid,page,filter,ext): + M={B:[],E:0,F:0};N=D.home_url+f"/show/{cid}--------{page}---/";O=C.get(N,headers=D.headers);S=H(O.text.encode());T=S('div.public-list-box.public-pic-b div.public-list-div.public-list-bj') + for A in T.items():U=A(G).attr(I);V=A(G).attr('title');W=A('img').attr(P);X=A(Q).text();M[B].append({J:U,K:V,R:W,L:X}) + return M + def detailContent(N,did): + U='$$$';O={B:[],E:0,F:0};P=did[0];M=N.home_url+P;V=C.get(M,headers=N.headers);Q=H(V.text.encode());W=[A.text()for A in Q('div.anthology-tab div.swiper-wrapper a').items()];X=Q('ul.anthology-list-play');R=[] + for Y in X.items(): + S=[] + for T in Y('li').items():Z=T(G).text();M=T(G).attr(I);S.append(f"{Z}${M}") + R.append('#'.join(S)) + O[B].append({D:A,J:P,K:A,L:A,'vod_year':A,'vod_area':A,'vod_actor':A,'vod_director':A,'vod_content':A,'vod_play_from':U.join(W),'vod_play_url':U.join(R)});return O + def searchContent(D,key,quick,page='1'): + M='div.thumb-content div.thumb-txt.cor4.hide a';G={B:[],E:0,F:0};N=D.home_url+f"/ss/{key}----------{page}---/";O=C.get(N,headers=D.headers);S=H(O.text.encode());T=S('div.public-list-box.search-box') + for A in T.items():U=A(M).attr(I);V=A(M).text();W=A('img.gen-movie-img').attr(P);X=A(Q).text();G[B].append({J:U,K:V,R:W,L:X}) + return G + def playerContent(B,flag,pid,vipFlags): + Y='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36';X='https://play.brovods.top';W='user-agent';V='origin';U='header';G='url';D={G:B.error_play_url,E:0,F:0,U:{}};a=B.home_url+pid;H=C.get(a,headers=B.headers);J=re.search('var player_aaaa=(.*?)',H.text) + if J: + K=json.loads(J.group(1));b=N.quote(K[G]);c=B.home_url+K['link_next'];d='https://play.brovods.top?url='+b+'&next='+N.quote(c,safe=A);I=C.get(d,headers=B.headers);L=re.search('"url":"(.*?)",',I.text);P=re.search('"pbgjz":"(.*?)",',I.text);Q=re.search('"dmkey":"(.*?)",',I.text) + if L and P and Q: + e=L.group(1);f=P.group(1);g=Q.group(1);h={'accept':'application/json, text/javascript, */*; q=0.01','accept-language':'zh-CN,zh;q=0.9','content-type':'application/x-www-form-urlencoded; charset=UTF-8',V:X,W:Y};R=M.time();S=M.localtime(R);i=S.tm_min*60+S.tm_sec;j=int(R-i);k=f"{j}cnmdhb";l={G:e,'pbgjz':f,'dmkey':g,'key':Z.sha256(k.encode('utf-8')).hexdigest()};H=C.post('https://play.brovods.top/JX',headers=h,json=l);T=H.json() + if T['code']==200:D[G]=T['cnmdhb'];m={W:Y,V:X};D[U]=m + O(D);return D + def localProxy(A,params):0 + def destroy(A):return'正在Destroy' +if __name__=='__main__':0 diff --git a/lrzy/py/剧王短剧.py b/lrzy/py/剧王短剧.py new file mode 100644 index 0000000..c32dffc --- /dev/null +++ b/lrzy/py/剧王短剧.py @@ -0,0 +1,329 @@ +# coding=utf-8 +# !/usr/bin/python + +""" + +作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容 + ====================Diudiumiao==================== + +""" + +from Crypto.Util.Padding import unpad +from Crypto.Util.Padding import pad +from urllib.parse import unquote +from Crypto.Cipher import ARC4 +from urllib.parse import quote +from base.spider import Spider +from Crypto.Cipher import AES +from datetime import datetime +from bs4 import BeautifulSoup +from base64 import b64decode +import urllib.request +import urllib.parse +import datetime +import binascii +import requests +import base64 +import json +import time +import sys +import re +import os + +sys.path.append('..') + +xurl = "https://djw1.com" + +headerx = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36' + } + +class Spider(Spider): + global xurl + global headerx + + def getName(self): + return "首页" + + def init(self, extend): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''): + if pl == 3: + plx = [] + while True: + start_index = text.find(start_str) + if start_index == -1: + break + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + break + middle_text = text[start_index + len(start_str):end_index] + plx.append(middle_text) + text = text.replace(start_str + middle_text + end_str, '') + if len(plx) > 0: + purl = '' + for i in range(len(plx)): + matches = re.findall(start_index1, plx[i]) + output = "" + for match in matches: + match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1]) + if match3: + number = match3.group(1) + else: + number = 0 + if 'http' not in match[0]: + output += f"#{match[1]}${number}{xurl}{match[0]}" + else: + output += f"#{match[1]}${number}{match[0]}" + output = output[1:] + purl = purl + output + "$$$" + purl = purl[:-3] + return purl + else: + return "" + else: + start_index = text.find(start_str) + if start_index == -1: + return "" + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + return "" + + if pl == 0: + middle_text = text[start_index + len(start_str):end_index] + return middle_text.replace("\\", "") + + if pl == 1: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + jg = ' '.join(matches) + return jg + + if pl == 2: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + new_list = [f'{item}' for item in matches] + jg = '$$$'.join(new_list) + return jg + + def homeContent(self, filter): + result = {"class": []} + + detail = requests.get(url=xurl + "/all/", headers=headerx) + detail.encoding = "utf-8" + res = detail.text + + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('section', class_="container items") + + for soup in soups: + vods = soup.find_all('li') + + for vod in vods: + + id = vod.find('a')['href'] + + name = vod.text.strip() + + result["class"].append({"type_id": id, "type_name": "" + name}) + + return result + + def homeVideoContent(self): + pass + + def categoryContent(self, cid, pg, filter, ext): + result = {} + videos = [] + + if pg: + page = int(pg) + else: + page = 1 + + url = f'{cid}page/{str(page)}/' + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('section', class_="container items") + + for soup in soups: + vods = soup.find_all('li') + + for vod in vods: + + name = vod.find('img')['alt'] + + ids = vod.find('a', class_="image-line") + id = ids['href'] + + pic = vod.find('img')['src'] + + remark = self.extract_middle_text(str(vod), 'class="remarks light">', '<', 0) + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": '▶️' + remark + } + videos.append(video) + + result = {'list': videos} + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + did = ids[0] + result = {} + videos = [] + xianlu = '' + bofang = '' + + if 'http' not in did: + did = xurl + did + + res = requests.get(url=did, headers=headerx) + res.encoding = "utf-8" + res = res.text + doc = BeautifulSoup(res, "lxml") + + url = 'https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1732707176882/jiduo.txt' + response = requests.get(url) + response.encoding = 'utf-8' + code = response.text + name = self.extract_middle_text(code, "s1='", "'", 0) + Jumps = self.extract_middle_text(code, "s2='", "'", 0) + + content = '集多为您介绍剧情📢' + self.extract_middle_text(res,'class="info-detail">','<', 0) + + remarks = self.extract_middle_text(res, 'class="info-mark">', '<', 0) + + year = self.extract_middle_text(res, 'class="info-addtime">', '<', 0) + + if name not in content: + bofang = Jumps + xianlu = '1' + else: + soups = doc.find('div', class_="ep-list-items") + + soup = soups.find_all('a') + + for sou in soup: + + id = sou['href'] + + name = sou.text.strip() + + bofang = bofang + name + '$' + id + '#' + + bofang = bofang[:-1] + + xianlu = '专线' + + videos.append({ + "vod_id": did, + "vod_remarks": remarks, + "vod_year": year, + "vod_content": content, + "vod_play_from": xianlu, + "vod_play_url": bofang + }) + + result['list'] = videos + return result + + def playerContent(self, flag, id, vipFlags): + + res = requests.get(url=id, headers=headerx) + res.encoding = "utf-8" + res = res.text + + url = self.extract_middle_text(res, '"wwm3u8":"', '"', 0).replace('\\', '') + + result = {} + result["parse"] = 0 + result["playUrl"] = '' + result["url"] = url + result["header"] = headerx + return result + + def searchContentPage(self, key, quick, pg): + result = {} + videos = [] + + if pg: + page = int(pg) + else: + page = 1 + + url = f'{xurl}/search/{key}/page/{str(page)}/' + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('section', class_="container items") + + for soup in soups: + vods = soup.find_all('li') + + for vod in vods: + + name = vod.find('img')['alt'] + + ids = vod.find('a', class_="image-line") + id = ids['href'] + + pic = vod.find('img')['src'] + + remark = self.extract_middle_text(str(vod), 'class="remarks light">', '<', 0) + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": '▶️' + remark + } + videos.append(video) + + result['list'] = videos + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def searchContent(self, key, quick, pg="1"): + return self.searchContentPage(key, quick, '1') + + def localProxy(self, params): + if params['type'] == "m3u8": + return self.proxyM3u8(params) + elif params['type'] == "media": + return self.proxyMedia(params) + elif params['type'] == "ts": + return self.proxyTs(params) + return None + + + + + + + diff --git a/lrzy/py/剧透社[盘].py b/lrzy/py/剧透社[盘].py new file mode 100644 index 0000000..a2cda27 --- /dev/null +++ b/lrzy/py/剧透社[盘].py @@ -0,0 +1,184 @@ +import sys +import json +import re +sys.path.append('..') +from base.spider import Spider +class Spider(Spider): + def __init__(self): + self.name = "剧透社" + self.host = "https://1.star2.cn" + self.timeout = 5000 + self.limit = 20 + self.headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" + } + self.default_image = "https://images.gamedog.cn/gamedog/imgfile/20241205/05105843u5j9.png" + + def getName(self): + return self.name + + def init(self, extend=""): + print(f"============{extend}============") + + def homeContent(self, filter): + return { + 'class': [ + {"type_name": "国剧", "type_id": "ju"}, + {"type_name": "电影", "type_id": "mv"}, + {"type_name": "动漫", "type_id": "dm"}, + {"type_name": "短剧", "type_id": "dj"}, + {"type_name": "综艺", "type_id": "zy"}, + {"type_name": "韩日", "type_id": "rh"}, + {"type_name": "英美", "type_id": "ym"}, + {"type_name": "外剧", "type_id": "wj"} + ] + } + + def categoryContent(self, tid, pg, filter, extend): + result = {} + url = f"{self.host}/{tid}/" if pg == 1 else f"{self.host}/{tid}/?page={pg}" + + try: + rsp = self.fetch(url, headers=self.headers, timeout=self.timeout) + if rsp: + videos = self._parse_video_list(rsp.text) + result.update({ + 'list': videos, + 'page': pg, + 'pagecount': 9999, + 'limit': self.limit, + 'total': 999999 + }) + except Exception as e: + print(f"Category parse error: {e}") + + return result + + def _parse_video_list(self, html_text): + videos = [] + + def build_full_url(href): + if href.startswith("http"): + return href + return f"{self.host}{href}" if href.startswith("/") else f"{self.host}/{href}" + + try: + pattern = r']*>.*?]*href="([^"]*)"[^>]*class="main"[^>]*>(.*?).*?' + for match in re.finditer(pattern, html_text, re.S): + href = match.group(1) + name = match.group(2).strip() + + if href and name and href.startswith("/"): + cleaned_name = re.sub(r'^【[^】]*】', '', name).strip() + final_name = cleaned_name if cleaned_name else name + videos.append({ + "vod_id": build_full_url(href), + "vod_name": final_name, + "vod_pic": self.default_image, + "vod_remarks": "", + "vod_content": final_name + }) + except Exception as e: + print(f"Parse video list error: {e}") + + return videos + + def detailContent(self, array): + result = {'list': []} + if array: + try: + vod_id = array[0] + detail_url = vod_id if vod_id.startswith("http") else f"{self.host}{vod_id}" + rsp = self.fetch(detail_url, headers=self.headers, timeout=self.timeout) + if rsp: + vod = self._parse_detail_page(rsp.text, detail_url) + if vod: + result['list'] = [vod] + except Exception as e: + print(f"Detail parse error: {e}") + return result + + def _parse_detail_page(self, html_text, detail_url): + try: + title_match = re.search(r']*>(.*?)

', html_text, re.S) + title = title_match.group(1).strip() if title_match else "未知标题" + title = re.sub(r'^【[^】]+】', '', title).strip() or "未知标题" + baidu_links = [] + quark_links = [] + + link_pattern = r']*href="([^"]*)"[^>]*>.*?' + for match in re.finditer(link_pattern, html_text, re.S): + href = match.group(1) + if href: + if "pan.baidu.com" in href: + baidu_links.append(href) + elif "pan.quark.cn" in href: + quark_links.append(href) + + play_links = baidu_links + quark_links + play_from = "剧透社" if play_links else "无资源" + + play_url_parts = [] + for link in play_links: + if "pan.baidu.com" in link: + play_url_parts.append(f"百度${link}") + else: + play_url_parts.append(f"夸克${link}") + + play_url = "#".join(play_url_parts) or "暂无资源$#" + + return { + "vod_id": detail_url, + "vod_name": title, + "vod_pic": self.default_image, + "vod_content": title, + "vod_remarks": "", + "vod_play_from": play_from, + "vod_play_url": play_url + } + except Exception as e: + print(f"Parse detail page error: {e}") + return { + "vod_id": detail_url, + "vod_name": "未知标题", + "vod_pic": self.default_image, + "vod_content": f"加载详情页失败:{str(e)}", + "vod_remarks": "", + "vod_play_from": "无资源", + "vod_play_url": "暂无资源$#" + } + + def searchContent(self, key, quick, pg): + result = {'list': []} + try: + url = f"{self.host}/search/?keyword={key}" + rsp = self.fetch(url, headers=self.headers, timeout=self.timeout) + if rsp: + result['list'] = self._parse_video_list(rsp.text) + except Exception as e: + print(f"Search error: {e}") + return result + + def playerContent(self, flag, id, vipFlags): + if id.startswith("push://"): + return {"parse": 0, "playUrl": "", "url": id, "header": ""} + return { + "parse": 0, + "playUrl": "", + "url": f"push://{id}", + "header": json.dumps(self.headers) + } + + def homeVideoContent(self): + return {"list": []} + + def isVideoFormat(self, url): + return False + + def localProxy(self, url, param): + return {"parse": 0, "playUrl": "", "url": url} + + def manualVideoCheck(self, url): + return {"parse": 0, "playUrl": "", "url": url} + + diff --git a/lrzy/py/努努影院.py b/lrzy/py/努努影院.py new file mode 100644 index 0000000..401c02e --- /dev/null +++ b/lrzy/py/努努影院.py @@ -0,0 +1,414 @@ +# coding=utf-8 +# !/usr/bin/python + +""" + +作者 丢丢喵 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容 + ====================Diudiumiao==================== + +""" + +from Crypto.Util.Padding import unpad +from Crypto.Util.Padding import pad +from urllib.parse import unquote +from Crypto.Cipher import ARC4 +from urllib.parse import quote +from base.spider import Spider +from Crypto.Cipher import AES +from datetime import datetime +from bs4 import BeautifulSoup +from base64 import b64decode +import urllib.request +import urllib.parse +import datetime +import binascii +import requests +import base64 +import json +import time +import sys +import re +import os + +sys.path.append('..') + +xurl = "https://nnyy.la" + +headerx = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36' + } + +class Spider(Spider): + global xurl + global headerx + + def getName(self): + return "首页" + + def init(self, extend): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def split_id_by_at(self, id): + return id.split("@") + + def split_first_part_by_comma(self, first_part): + return first_part.split(",") + + def parse_url_dictionary(self, response_text): + pattern = r'urlDictionary\[(\d+)\]\[(\d+)\]\s*=\s*"([^"]+)"' + matches = re.findall(pattern, response_text) + url_dictionary = {} + for key1, key2, value in matches: + key1_int = int(key1) + key2_int = int(key2) + if key1_int not in url_dictionary: + url_dictionary[key1_int] = {} + url_dictionary[key1_int][key2_int] = value + return url_dictionary + + def get_url_from_dictionary(self, url_dictionary, indices): + primary_index = int(indices[0].strip()) + secondary_index = int(indices[1].strip()) + return url_dictionary[primary_index][secondary_index] + + def decrypt_url(self, encrypted_hex, key="i_love_you"): + encrypted_bytes = bytes.fromhex(encrypted_hex) + s = list(range(256)) + j = 0 + key_bytes = key.encode('utf-8') + key_length = len(key_bytes) + for i in range(256): + j = (j + s[i] + key_bytes[i % key_length]) % 256 + s[i], s[j] = s[j], s[i] + i = 0 + j = 0 + decrypted_bytes = bytearray(len(encrypted_bytes)) + for k in range(len(encrypted_bytes)): + i = (i + 1) % 256 + j = (j + s[i]) % 256 + s[i], s[j] = s[j], s[i] + keystream_byte = s[(s[i] + s[j]) % 256] + decrypted_bytes[k] = encrypted_bytes[k] ^ keystream_byte + return decrypted_bytes.decode('utf-8') + + def _extract_play_sources(self, soups): + xianlu = '' + for item in soups: + vods = item.find_all('dt') + for sou in vods: + name = sou.text.strip() + xianlu = xianlu + name + '$$$' + xianlu = xianlu[:-3] + return xianlu + + def _extract_play_urls(self, soups1, did): + bofang = '' + for item in soups1: + vods1 = item.find_all('a') + for sou1 in vods1: + id1 = sou1['onclick'] + numbers = re.findall(r'\((.*?)\)', id1)[0] if re.findall(r'\((.*?)\)', id1) else "" + id = f"{numbers}@{did}" + name = sou1.text.strip() + bofang = bofang + name + '$' + id + '#' + bofang = bofang[:-1] + '$$$' + bofang = bofang[:-3] + return bofang + + def _extract_content(self, res): + content_raw = self.extract_middle_text(res, '剧情简介:', '<', 0).replace('\n', '') + return '😸丢丢为您介绍剧情📢' + (content_raw if content_raw is not None else "暂无剧情介绍") + + def _extract_director(self, res): + director_raw = self.extract_middle_text(res, '导演:', '', 1, 'href=".*?">(.*?)') + return director_raw if director_raw is not None and director_raw.strip() != "" else "暂无导演介绍" + + def _extract_actor(self, res): + actor_raw = self.extract_middle_text(res, '主演:', '', 1, 'href=".*?">(.*?)') + return actor_raw if actor_raw is not None and actor_raw.strip() != "" else "暂无主演介绍" + + def _extract_remarks(self, res): + remarks_raw = self.extract_middle_text(res, '类型:', '', 1, 'href=".*?">(.*?)') + return remarks_raw if remarks_raw is not None and remarks_raw.strip() != "" else "暂无类型介绍" + + def _extract_area(self, res): + area_raw = self.extract_middle_text(res, '制片国家/地区:', '', 1, 'href=".*?">(.*?)') + return area_raw if area_raw is not None and area_raw.strip() != "" else "暂无国家/地区介绍" + + def _extract_year(self, doc): + years = doc.find('h1', class_="product-title") + year = years.text.strip() if years else '暂无年份介绍' + return year.replace('\n', '打分:') + + def _extract_video_items(self, vods): + videos = [] + for vod in vods: + name = vod.find('img')['alt'] + ids = vod.find('a', class_="thumbnail") + id = ids['href'] + pic = vod.find('img')['data-src'] + remarks = vod.find('div', class_="note") + remark = remarks.text.strip() + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": remark + } + videos.append(video) + return videos + + def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''): + if pl == 3: + plx = [] + while True: + start_index = text.find(start_str) + if start_index == -1: + break + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + break + middle_text = text[start_index + len(start_str):end_index] + plx.append(middle_text) + text = text.replace(start_str + middle_text + end_str, '') + if len(plx) > 0: + purl = '' + for i in range(len(plx)): + matches = re.findall(start_index1, plx[i]) + output = "" + for match in matches: + match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1]) + if match3: + number = match3.group(1) + else: + number = 0 + if 'http' not in match[0]: + output += f"#{match[1]}${number}{xurl}{match[0]}" + else: + output += f"#{match[1]}${number}{match[0]}" + output = output[1:] + purl = purl + output + "$$$" + purl = purl[:-3] + return purl + else: + return "" + else: + start_index = text.find(start_str) + if start_index == -1: + return "" + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + return "" + + if pl == 0: + middle_text = text[start_index + len(start_str):end_index] + return middle_text.replace("\\", "") + + if pl == 1: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + jg = ' '.join(matches) + return jg + + if pl == 2: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + new_list = [f'{item}' for item in matches] + jg = '$$$'.join(new_list) + return jg + + def homeContent(self, filter): + result = {"class": []} + + detail = requests.get(url=xurl, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('div', class_="nav") + + for soup in soups: + vods = soup.find_all('a') + + for vod in vods: + + name = vod.text.strip() + + skip_names = ["首页"] + if name in skip_names: + continue + + id = vod['href'].replace('/', '') + + result["class"].append({"type_id": id, "type_name": name}) + + result["class"].append({"type_id": "duanju", "type_name": "短剧"}) + + return result + + def homeVideoContent(self): + videos = [] + + detail = requests.get(url=xurl, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find('div', class_="bd") + + vods = soups.find_all('li') + + videos = self._extract_video_items(vods) + + result = {'list': videos} + return result + + def categoryContent(self, cid, pg, filter, ext): + result = {} + videos = [] + + if pg: + page = int(pg) + else: + page = 1 + + url = f'{xurl}/{cid}/?page={str(page)}' + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('div', class_="lists-content") + + for soup in soups: + vods = soup.find_all('li') + + videos = self._extract_video_items(vods) + + result = {'list': videos} + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + did = ids[0] + result = {} + videos = [] + + if 'http' not in did: + did = xurl + did + + detail = requests.get(url=did, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + content = self._extract_content(res) + + director = self._extract_director(res) + + actor = self._extract_actor(res) + + remarks = self._extract_remarks(res) + + area = self._extract_area(res) + + year = self._extract_year(doc) + + soups = doc.find_all('div', class_="playlists") + xianlu = self._extract_play_sources(soups) + + soups1 = doc.find_all('ul', class_="sort-list") + bofang = self._extract_play_urls(soups1, did) + + videos.append({ + "vod_id": did, + "vod_director": director, + "vod_actor": actor, + "vod_remarks": remarks, + "vod_year": year, + "vod_area": area, + "vod_content": content, + "vod_play_from": xianlu, + "vod_play_url": bofang + }) + + result['list'] = videos + return result + + def playerContent(self, flag, id, vipFlags): + + fenge = self.split_id_by_at(id) + + fenge1 = self.split_first_part_by_comma(fenge[0]) + + detail = requests.get(url=fenge[1], headers=headerx) + detail.encoding = "utf-8" + res = detail.text + + url_dictionary = self.parse_url_dictionary(res) + + result = self.get_url_from_dictionary(url_dictionary, fenge1) + + url = self.decrypt_url(result) + + result = {} + result["parse"] = 0 + result["playUrl"] = '' + result["url"] = url + result["header"] = headerx + return result + + def searchContentPage(self, key, quick, pg): + result = {} + videos = [] + + url = f'{xurl}/search?wd={key}' + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('div', class_="lists-content") + + for item in soups: + vods = item.find_all('li') + + videos = self._extract_video_items(vods) + + result['list'] = videos + result['page'] = pg + result['pagecount'] = 1 + result['limit'] = 90 + result['total'] = 999999 + return result + + def searchContent(self, key, quick, pg="1"): + return self.searchContentPage(key, quick, '1') + + def localProxy(self, params): + if params['type'] == "m3u8": + return self.proxyM3u8(params) + elif params['type'] == "media": + return self.proxyMedia(params) + elif params['type'] == "ts": + return self.proxyTs(params) + return None + + + + + + + + diff --git a/lrzy/py/奇优动漫.py b/lrzy/py/奇优动漫.py new file mode 100644 index 0000000..71b09cb --- /dev/null +++ b/lrzy/py/奇优动漫.py @@ -0,0 +1,379 @@ +# coding=utf-8 +#!/usr/bin/python +import sys +sys.path.append('..') +from base.spider import Spider +import json +import urllib.parse +import re +from lxml import etree +from urllib.parse import urljoin + +class Spider(Spider): + + def getName(self): + return "奇优影院" + + def init(self, extend): + pass + + def homeContent(self, filter): + result = {} + cateManual = { + "电影": "1", + "电视剧": "2", + "动漫": "3", + "综艺": "4", + "午夜": "6" + } + classes = [{'type_name': k, 'type_id': v} for k, v in cateManual.items()] + result['class'] = classes + + filters = { + "1": [{"key": "by", "name": "排序", "value": [{"n": "按时间", "v": "time"}, {"n": "按人气", "v": "hit"}]}], + "2": [{"key": "by", "name": "排序", "value": [{"n": "按时间", "v": "time"}, {"n": "按人气", "v": "hit"}]}], + "3": [{"key": "by", "name": "排序", "value": [{"n": "按时间", "v": "time"}, {"n": "按人气", "v": "hit"}]}], + "4": [{"key": "by", "name": "排序", "value": [{"n": "按时间", "v": "time"}, {"n": "按人气", "v": "hit"}]}], + "6": [{"key": "by", "name": "排序", "value": [{"n": "按时间", "v": "time"}, {"n": "按人气", "v": "hit"}]}] + } + result['filters'] = filters + return result + + def homeVideoContent(self): + try: + rsp = self.fetch("http://qiyoudy5.com/") + root = self.parse_html(rsp.content) + if not root: + return {'list': []} + + videos = [] + # 轮播图 + for a in root.xpath("//div[contains(@class,'carousel')]//a[contains(@class,'stui-vodlist__thumb')]"): + try: + name = a.xpath(".//span[@class='pic-text text-center']/text()")[0].strip() if a.xpath(".//span[@class='pic-text text-center']/text()") else a.xpath("./@title")[0] if a.xpath("./@title") else "未知" + style = a.xpath("./@style")[0] if a.xpath("./@style") else "" + pic = re.search(r"background:\s*url\((.*?)\)", style).group(1) if re.search(r"background:\s*url\((.*?)\)", style) else "" + sid = a.xpath("./@href")[0] if a.xpath("./@href") else "" + videos.append({"vod_id": sid, "vod_name": name, "vod_pic": pic, "vod_remarks": "推荐"}) + except: + continue + + # 视频列表 + for a in root.xpath("//ul[contains(@class,'stui-vodlist')]//a[contains(@class,'stui-vodlist__thumb')]"): + try: + name = a.xpath("./@title")[0] if a.xpath("./@title") else "未知" + pic = a.xpath("./@data-original")[0] if a.xpath("./@data-original") else "" + sid = a.xpath("./@href")[0] if a.xpath("./@href") else "" + remark = a.xpath(".//span[@class='pic-text text-right']/text()")[0] if a.xpath(".//span[@class='pic-text text-right']/text()") else "" + videos.append({"vod_id": sid, "vod_name": name, "vod_pic": pic, "vod_remarks": remark}) + except: + continue + + return {'list': videos} + except: + return {'list': []} + + def categoryContent(self, tid, pg, filter, extend): + result = {} + try: + order = extend.get('by', 'time') if extend else 'time' + url = f'http://qiyoudy5.com/list/{tid}_{pg}.html?order={order}' + rsp = self.fetch(url) + root = self.parse_html(rsp.content) + + if not root: + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0} + + videos = [] + for a in root.xpath("//a[contains(@class,'stui-vodlist__thumb')]"): + try: + name = a.xpath("./@title")[0] if a.xpath("./@title") else "未知" + pic = a.xpath("./@data-original")[0] if a.xpath("./@data-original") else "" + sid = a.xpath("./@href")[0] if a.xpath("./@href") else "" + remark = a.xpath(".//span[@class='pic-text text-right']/text()")[0] if a.xpath(".//span[@class='pic-text text-right']/text()") else "" + videos.append({"vod_id": sid, "vod_name": name, "vod_pic": pic, "vod_remarks": remark}) + except: + continue + + current_page = int(root.xpath("//ul[contains(@class,'stui-page')]//a[@class='active']/text()")[0]) if root.xpath("//ul[contains(@class,'stui-page')]//a[@class='active']/text()") else pg + + page_numbers = [] + for link in root.xpath("//ul[contains(@class,'stui-page')]//a[contains(@href,'list')]/@href"): + match = re.search(r'list/\d+_(\d+)\.html', link) + if match: + page_numbers.append(int(match.group(1))) + total_page = max(page_numbers) if page_numbers else 1 + + return { + 'list': videos, + 'page': current_page, + 'pagecount': total_page if total_page > 0 else 9999, + 'limit': 90, + 'total': 999999 + } + except: + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 90, 'total': 0} + + def detailContent(self, array): + try: + tid = array[0] + url = f'http://qiyoudy5.com{tid}' + rsp = self.fetch(url) + root = self.parse_html(rsp.content) + + if not root: + return {'list': []} + + # 基本信息 + detail_node = root.xpath("//div[contains(@class,'stui-content__detail')]") or root.xpath("//div[@class='stui-player__detail']") + pic = title = area = director = actor = year = desc = "" + + if detail_node: + detail_node = detail_node[0] + pic = self.get_first(root.xpath("//meta[@property='og:image']/@content") or detail_node.xpath(".//img/@data-original")) + title = self.get_first(detail_node.xpath(".//h1//text()")) + if not title: + page_title = self.get_first(root.xpath("//title/text()")) + title = re.search(r"《(.*?)》", page_title).group(1) if page_title and re.search(r"《(.*?)》", page_title) else "" + + area = self.get_first(root.xpath("//meta[@property='og:video:area']/@content")) + director = self.get_first(root.xpath("//meta[@property='og:video:director']/@content")) + actor = self.get_first(root.xpath("//meta[@property='og:video:actor']/@content")) + year_info = self.get_first(root.xpath("//p[@class='data']//text()[contains(.,'年份:')]")) + year = re.search(r"年份:(\d{4})", year_info).group(1) if year_info and re.search(r"年份:(\d{4})", year_info) else "" + desc = self.get_first(root.xpath("//meta[@property='og:description']/@content")) + + # 播放列表 + playFrom, playUrl = [], [] + for tab in root.xpath("//ul[contains(@class,'nav-tabs')]/li"): + tab_name = self.get_first(tab.xpath(".//a/text()")) + tab_id = self.get_first(tab.xpath(".//a/@href")).replace("#", "") if tab.xpath(".//a/@href") else "" + + if tab_name and tab_id: + play_list = root.xpath(f"//div[@id='{tab_id}']//ul[contains(@class,'stui-content__playlist')]//a") + if play_list: + playFrom.append(tab_name) + episodes = [] + for episode in play_list: + ep_name = self.get_first(episode.xpath("./text()")) or "播放" + ep_url = self.get_first(episode.xpath("./@href")) + if ep_url: + episodes.append(f"{ep_name}${ep_url}") + if episodes: + playUrl.append("#".join(episodes)) + + vod = { + "vod_id": tid, + "vod_name": title, + "vod_pic": pic, + "vod_year": year, + "vod_area": area, + "vod_actor": actor, + "vod_director": director, + "vod_content": desc + } + + if playFrom and playUrl: + vod['vod_play_from'] = "$$$".join(playFrom) + vod['vod_play_url'] = "$$$".join(playUrl) + + return {'list': [vod]} + except: + return {'list': []} + + def searchContent(self, key, quick, page='1'): + try: + url = "http://qiyoudy5.com/search.php" + # 修复:使用正确的参数名和变量 + post_data = { + 'searchword': key, # 改为变量key,而不是字符串'key' + } + + headers = { + "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "Referer": "http://qiyoudy5.com/", + "Origin": "http://qiyoudy5.com" + } + + # 修复:只发送一次POST请求,删除重复的请求 + rsp = self.post(url, data=post_data, headers=headers) + + root = self.parse_html(rsp.content) + + if not root: + return {'list': []} + + videos = [] + + # 多种选择器尝试获取搜索结果 + selectors = [ + "//ul[contains(@class,'stui-vodlist__media')]//li", + "//ul[contains(@class,'stui-vodlist')]//li", + "//a[contains(@class,'stui-vodlist__thumb')]" + ] + + result_items = [] + for selector in selectors: + result_items = root.xpath(selector) + if result_items: + break + + for item in result_items: + try: + if item.tag == 'a': # 直接是a标签 + href = self.get_first(item.xpath("./@href")) + title = self.get_first(item.xpath("./@title")) + pic = self.get_first(item.xpath("./@data-original")) + remark = self.get_first(item.xpath(".//span[contains(@class,'pic-text')]/text()")) + else: # li标签 + link = item.xpath(".//a[contains(@class,'stui-vodlist__thumb')]") or item.xpath(".//a") + if not link: + continue + link = link[0] + href = self.get_first(link.xpath("./@href")) + title = self.get_first(link.xpath("./@title")) + pic = self.get_first(link.xpath("./@data-original")) + if not pic: + style = self.get_first(link.xpath("./@style")) + if style and "background-image" in style: + pic_match = re.search(r"background-image:\s*url\(['\"]?(.*?)['\"]?\)", style) + if pic_match: + pic = pic_match.group(1) + remark = self.get_first(item.xpath(".//span[contains(@class,'pic-text')]/text()")) + + if href and title: + videos.append({ + "vod_id": href, + "vod_name": title.strip(), + "vod_pic": pic, + "vod_remarks": remark or "" + }) + except Exception as e: + continue + + # 备用解析方案 + if not videos: + for a in root.xpath("//a[contains(@href,'/vod/')]"): + try: + href = self.get_first(a.xpath("./@href")) + title = self.get_first(a.xpath("./@title")) or self.get_first(a.xpath(".//text()")) + pic = self.get_first(a.xpath("./@data-original")) + remark = self.get_first(a.xpath(".//span[contains(@class,'pic-text')]/text()")) + + if href and title: + videos.append({ + "vod_id": href, + "vod_name": title.strip(), + "vod_pic": pic, + "vod_remarks": remark or "" + }) + except: + continue + + # 去重 + seen = set() + unique_videos = [] + for video in videos: + identifier = (video["vod_id"], video["vod_name"]) + if identifier not in seen: + seen.add(identifier) + unique_videos.append(video) + + return {'list': unique_videos} + + except Exception as e: + return {'list': []} + + def playerContent(self, flag, id, vipFlags): + try: + url = f"http://qiyoudy5.com{id}" + rsp = self.fetch(url) + _, html_content = self.parse_html(rsp.content, return_content=True) + + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "Referer": url, + } + + # 多种方式查找播放地址 + # 1. API链接 + for pattern in [r"http://api\.yongfan99\.com:81/content\.php\?[^'\"]+", r"content\.php\?vid=[^&]+&type=[^'\"]+"]: + match = re.search(pattern, html_content) + if match: + api_url = match.group(0) + if not api_url.startswith('http'): + api_url = "http://api.yongfan99.com:81/" + api_url + try: + api_rsp = self.fetch(api_url, headers=headers) + m3u8_match = re.search(r'http[s]?://[^\s"\']+\.m3u8[^\s"\']*', api_rsp.text) + if m3u8_match: + return {"parse": 0, "playUrl": "", "url": m3u8_match.group(0), "header": headers} + except: + pass + + # 2. iframe中的播放器 + for pattern in [r']*src=[\'"]([^\'"]+)[\'"][^>]*>', r'src\s*=\s*[\'"]((?:http[^\'"]*)?/play/[^\'"]*)[\'"]']: + for iframe_src in re.findall(pattern, html_content): + if not iframe_src.startswith('http'): + iframe_src = urljoin(url, iframe_src) + try: + iframe_rsp = self.fetch(iframe_src, headers=headers) + m3u8_match = re.search(r'http[s]?://[^\s"\']+\.m3u8[^\s"\']*', iframe_rsp.text) + if m3u8_match: + return {"parse": 0, "playUrl": "", "url": m3u8_match.group(0), "header": headers} + except: + continue + + # 3. 直接搜索m3u8链接 + m3u8_match = re.search(r'http[s]?://[^\s"\']+\.m3u8[^\s"\']*', html_content) + if m3u8_match: + return {"parse": 0, "playUrl": "", "url": m3u8_match.group(0), "header": headers} + + # 4. 返回原始URL进行外部解析 + return {"parse": 1, "playUrl": "", "url": url, "header": headers} + + except: + return {"parse": 1, "playUrl": "", "url": f"http://qiyoudy5.com{id}", "header": { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + "Referer": "http://qiyoudy5.com/", + }} + + # 辅助函数 + def parse_html(self, content, return_content=False): + encodings = ['utf-8', 'gbk', 'gb2312', 'iso-8859-1'] + html_content = None + for encoding in encodings: + try: + html_content = content.decode(encoding) + break + except UnicodeDecodeError: + continue + if html_content is None: + html_content = content.decode('utf-8', errors='replace') + + html_content = self.clean_html(html_content) + root = etree.HTML(html_content) + + if return_content: + return root, html_content + return root + + def get_first(self, array, default=""): + return array[0] if array else default + + def clean_html(self, html_content): + html_content = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', html_content) + replacements = {' ': ' ', '&': '&', '<': '<', '>': '>', '"': '"'} + for old, new in replacements.items(): + html_content = html_content.replace(old, new) + return html_content + + def isVideoFormat(self, url): + return any(fmt in url for fmt in ['.m3u8', '.mp4', '.avi', '.mkv', '.flv', '.webm']) + + def manualVideoCheck(self): + return True + + def localProxy(self, param): + return {} \ No newline at end of file diff --git a/lrzy/py/小苹果.py b/lrzy/py/小苹果.py new file mode 100644 index 0000000..38776b4 --- /dev/null +++ b/lrzy/py/小苹果.py @@ -0,0 +1,202 @@ +""" +@header({ + searchable: 1, + filterable: 1, + quickSearch: 1, + title: '小苹果', + lang: 'hipy' +}) +""" + +# -*- coding: utf-8 -*- +# by @嗷呜 +import sys +sys.path.append('..') +from base.spider import Spider +import re + +class Spider(Spider): + + def init(self, extend=""): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host = 'http://asp.xpgtv.com' + + headers = { + "User-Agent": "okhttp/3.12.11" + } + + def homeContent(self, filter): + data = self.fetch(f"{self.host}/api.php/v2.vod/androidtypes", headers=self.headers).json() + dy = { + "classes": "类型", + "areas": "地区", + "years": "年份", + "sortby": "排序", + } + filters = {} + classes = [] + for item in data['data']: + # 简化字段检查逻辑 + has_non_empty_field = any(key in item and len(item[key]) > 1 for key in dy) + item['soryby'] = ['updatetime', 'hits', 'score'] + demos = ['时间', '人气', '评分'] + classes.append({"type_name": item["type_name"], "type_id": str(item["type_id"])}) + + if has_non_empty_field: + filters[str(item["type_id"])] = [] + for dkey in item: + if dkey in dy and len(item[dkey]) > 1: + values = item[dkey] + value_array = [ + {"n": demos[idx] if dkey == "sortby" else value.strip(), "v": value.strip()} + for idx, value in enumerate(values) if value.strip() + ] + filters[str(item["type_id"])].append( + {"key": dkey, "name": dy[dkey], "value": value_array} + ) + + return { + "class": classes, + "filters": filters + } + + def homeVideoContent(self): + rsp = self.fetch(f"{self.host}/api.php/v2.main/androidhome", headers=self.headers).json() + videos = [] + for i in rsp['data']['list']: + videos.extend(self.getlist(i['list'])) + return {'list': videos} + + def categoryContent(self, tid, pg, filter, extend): + params = { + "page": pg, + "type": tid, + "area": extend.get('areaes', ''), + "year": extend.get('yeares', ''), + "sortby": extend.get('sortby', ''), + "class": extend.get('classes', '') + } + # 简化参数过滤 + params = {k: v for k, v in params.items() if v} + rsp = self.fetch(f'{self.host}/api.php/v2.vod/androidfilter10086', headers=self.headers, params=params).json() + + return { + 'list': self.getlist(rsp['data']), + 'page': pg, + 'pagecount': 9999, + 'limit': 90, + 'total': 999999 + } + + def detailContent(self, ids): + rsp = self.fetch(f'{self.host}/api.php/v3.vod/androiddetail2?vod_id={ids[0]}', headers=self.headers).json() + v = rsp.get('data', {}) or {} + urls = v.get('urls') or [] + play_items = [] + + # 预编译正则表达式提高性能 + patterns = [ + (r'^\d+$', None), # 纯数字 + (r'^\d+-\d+$', None), # 数字范围 + (r'^第\d+[集期话节]$', None), # 第X集/期/话/节 + (r'^第\d+季$', None), # 第X季 + (r'^[集期话]?\d+$', None), # 集X/期X/话X + (r'^E[P]?\d+$', re.IGNORECASE), # EP1/E01 + (r'^\d+[PpKk]$', None), # 分辨率 + (r'^[Hh][Dd]$', None), # HD + (r'^[Ff][Hh][Dd]$', None), # FHD + (r'^[Uu][Hh][Dd]$', None) # UHD + ] + + allowed_chinese_keywords = { + '蓝光', '超清', '高清', '标清', '枪版', '全清', + '全集', '全', '完整版', '正片', '预告', '花絮' + } + + for i in urls: + key = (i.get('key') or i.get('name') or "").strip() + url = (i.get('url') or "").strip() + + if key and url: + if key in allowed_chinese_keywords: + play_items.append(f"{key}${url}") + else: + # 使用预编译的正则表达式检查 + matched = False + for pattern, flags in patterns: + if flags: + if re.match(pattern, key, flags): + matched = True + break + else: + if re.match(pattern, key): + matched = True + break + + if matched: + play_items.append(f"{key}${url}") + + play_url = "#".join(play_items) + + vod = { + 'vod_id': v.get('id'), + 'vod_name': v.get('name'), + 'vod_pic': v.get('pic'), + 'vod_year': v.get('year'), + 'vod_area': v.get('area'), + 'vod_lang': v.get('lang'), + 'type_name': v.get('className'), + 'vod_actor': v.get('actor'), + 'vod_director': v.get('director'), + 'vod_content': v.get('content'), + 'vod_play_from': '小苹果', + 'vod_play_url': play_url + } + + return {'list': [vod]} + + def searchContent(self, key, quick, pg='1'): + rsp = self.fetch(f'{self.host}/api.php/v2.vod/androidsearch10086?page={pg}&wd={key}', headers=self.headers).json() + return {'list': self.getlist(rsp['data']), 'page': pg} + + def playerContent(self, flag, id, vipFlags): + header = { + 'user_id': 'XPGBOX', + 'token2': 'SnAXiSW8vScXE0Z9aDOnK5xffbO75w1+uPom3WjnYfVEA1oWtUdi2Ihy1N8=', + 'version': 'XPGBOX com.phoenix.tv1.5.7', + 'hash': 'd78a', + 'screenx': '2345', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', + 'token': 'ElEDlwCVgXcFHFhddiq2JKteHofExRBUrfNlmHrWetU3VVkxnzJAodl52N9EUFS+Dig2A/fBa/V9RuoOZRBjYvI+GW8kx3+xMlRecaZuECdb/3AdGkYpkjW3wCnpMQxf8vVeCz5zQLDr8l8bUChJiLLJLGsI+yiNskiJTZz9HiGBZhZuWh1mV1QgYah5CLTbSz8=', + 'timestamp': '1743060300', + 'screeny': '1065', + } + if 'http' not in id: + id = f"http://c.xpgtv.net/m3u8/{id}.m3u8" + return {"parse": 0, "url": id, "header": header} + + def localProxy(self, param): + pass + + def getlist(self, data): + videos = [] + for vod in data: + # 简化备注生成逻辑 + remarks = f"更新至{vod.get('updateInfo')}" if vod.get('updateInfo') else vod.get('score', '') + videos.append({ + "vod_id": vod['id'], + "vod_name": vod['name'], + "vod_pic": vod['pic'], + "vod_remarks": remarks + }) + return videos \ No newline at end of file diff --git a/lrzy/py/小鸡暴走.py b/lrzy/py/小鸡暴走.py new file mode 100644 index 0000000..8dbfe15 --- /dev/null +++ b/lrzy/py/小鸡暴走.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import json +import sys +from base64 import b64decode, b64encode +from pyquery import PyQuery as pq +from requests import Session +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + self.host = self.gethost() + self.headers['referer'] = f'{self.host}/' + self.session = Session() + self.session.headers.update(self.headers) + + def getName(self): + return "minijj" + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-full-version': '"133.0.6943.98"', + 'sec-ch-ua-arch': '"x86"', + 'sec-ch-ua-platform': '"Windows"', + 'sec-ch-ua-platform-version': '"19.0.0"', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-full-version-list': '"Not(A:Brand";v="99.0.0.0", "Google Chrome";v="133.0.6943.98", "Chromium";v="133.0.6943.98"', + 'dnt': '1', + 'upgrade-insecure-requests': '1', + 'sec-fetch-site': 'none', + 'sec-fetch-mode': 'navigate', + 'sec-fetch-user': '?1', + 'sec-fetch-dest': 'document', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'priority': 'u=0, i' + } + + def homeContent(self, filter): + result = {} + cateManual = { + "電影": "1", + "電視劇": "2", + "經典動漫": "3", + "綜藝娛樂": "4", + } + classes = [] + filters = {} + + for k in cateManual: + classes.append({ + 'type_name': k, + 'type_id': cateManual[k] + }) + + filters = { + '1': [{'key': 'type', 'name': '類型', 'value': [{'n': '全部', 'v': '1'}, {'n': '動作片', 'v': '8'}, {'n': '喜劇片', 'v': '9'}, {'n': '愛情片', 'v': '10'}, {'n': '科幻片', 'v': '11'}, {'n': '恐怖片', 'v': '12'}, {'n': '戰爭片', 'v': '13'}, {'n': '劇情片', 'v': '14'}]}, + {'key': 'area', 'name': '地區', 'value': [{'n': '全部', 'v': ''}, {'n': '大陸', 'v': 'dalu'}, {'n': '美國', 'v': 'meiguo'}, {'n': '香港', 'v': 'xianggang'}, {'n': '台灣', 'v': 'taiwan'}, {'n': '韓國', 'v': 'hanguo'}, {'n': '日本', 'v': 'riben'}, {'n': '泰國', 'v': 'taiguo'}, {'n': '新加坡', 'v': 'xinjiapo'}, {'n': '馬來西亞', 'v': 'malaixiya'}, {'n': '印度', 'v': 'yindu'}, {'n': '英國', 'v': 'yingguo'}, {'n': '法國', 'v': 'faguo'}, {'n': '加拿大', 'v': 'jianada'}]}, + {'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': '90後', 'v': '1990,1999'}, {'n': '80後', 'v': '1980,1989'}, {'n': '更早', 'v': '1900,1980'}]}], + '2': [{'key': 'type', 'name': '類型', 'value': [{'n': '全部', 'v': '2'}, {'n': '大陸劇', 'v': '15'}, {'n': '香港劇', 'v': '16'}, {'n': '台灣劇', 'v': '918'}, {'n': '日劇', 'v': '18'}, {'n': '韓劇', 'v': '915'}, {'n': '美劇', 'v': '916'}, {'n': '英劇', 'v': '923'}, {'n': '歐美劇', 'v': '17'}, {'n': '泰劇', 'v': '922'}, {'n': '亞洲劇', 'v': '19'}]}, + {'key': 'area', 'name': '地區', 'value': [{'n': '全部', 'v': ''}, {'n': '大陸', 'v': 'dalu'}, {'n': '美國', 'v': 'meiguo'}, {'n': '香港', 'v': 'xianggang'}, {'n': '台灣', 'v': 'taiwan'}, {'n': '韓國', 'v': 'hanguo'}, {'n': '日本', 'v': 'riben'}, {'n': '泰國', 'v': 'taiguo'}, {'n': '新加坡', 'v': 'xinjiapo'}, {'n': '馬來西亞', 'v': 'malaixiya'}, {'n': '印度', 'v': 'yindu'}, {'n': '英國', 'v': 'yingguo'}, {'n': '法國', 'v': 'faguo'}, {'n': '加拿大', 'v': 'jianada'}]}, + {'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': '90後', 'v': '1990,1999'}, {'n': '80後', 'v': '1980,1989'}, {'n': '更早', 'v': '1900,1980'}]}], + '3': [{'key': 'type', 'name': '類型', 'value': [{'n': '全部', 'v': '3'}, {'n': '國漫', 'v': '906'}, {'n': '日漫', 'v': '904'}, {'n': '美漫', 'v': '905'}, {'n': '其他動漫', 'v': '903'}]}, + {'key': 'area', 'name': '地區', 'value': [{'n': '全部', 'v': ''}, {'n': '大陸', 'v': 'dalu'}, {'n': '美國', 'v': 'meiguo'}, {'n': '日本', 'v': 'riben'}]}, + {'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': '90後', 'v': '1990,1999'}, {'n': '80後', 'v': '1980,1989'}, {'n': '更早', 'v': '1900,1980'}]}], + '4': [{'key': 'type', 'name': '類型', 'value': [{'n': '全部', 'v': '4'}, {'n': '大陸綜藝', 'v': '911'}, {'n': '港台綜藝', 'v': '907'}, {'n': '韓綜', 'v': '908'}, {'n': '日綜', 'v': '912'}, {'n': '泰綜', 'v': '913'}, {'n': '歐美綜藝', 'v': '909'}]}, + {'key': 'area', 'name': '地區', 'value': [{'n': '全部', 'v': ''}, {'n': '大陸', 'v': 'dalu'}, {'n': '美國', 'v': 'meiguo'}, {'n': '香港', 'v': 'xianggang'}, {'n': '台灣', 'v': 'taiwan'}, {'n': '韓國', 'v': 'hanguo'}, {'n': '日本', 'v': 'riben'}, {'n': '泰國', 'v': 'taiguo'}]}, + {'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': '90後', 'v': '1990,1999'}, {'n': '80後', 'v': '1980,1989'}, {'n': '更早', 'v': '1900,1980'}]}] + } + + result['class'] = classes + result['filters'] = filters + return result + + def homeVideoContent(self): + data = self.getpq() + return {'list': self.getlist(data(".update_area_lists .i_list"))} + + def categoryContent(self, tid, pg, filter, extend): + result = {} + _type = extend.get('type', tid) + _area = extend.get('area', '') + _year = extend.get('year', '') + + # 構建篩選 URL,根據網站實際格式 + # 基礎格式:/lm/{type}/sx---{year}-----{page}.html + # 如果有地區:/lm/{type}/sx------{area}--{page}.html + # 如果年份和地區同時存在:/lm/{type}/sx---{year}---{area}--{page}.html + if _year and _area: + url = f'{self.host}/lm/{_type}/sx---{_year}---{_area}--{pg}.html' + elif _year: + url = f'{self.host}/lm/{_type}/sx---{_year}-----{pg}.html' + elif _area: + url = f'{self.host}/lm/{_type}/sx------{_area}--{pg}.html' + else: + url = f'{self.host}/lm/{_type}/sx--------{pg}.html' + + print(f"篩選 URL: {url}") # 調試用,確認 URL 是否正確 + + data = self.getpq(url) + vdata = self.getlist(data(".update_area_lists .i_list")) + pagecount = 9999 + try: + pagination = data('.pagination .page-numbers') + last_page = pagination[-2].text if len(pagination) > 1 else '1' + pagecount = int(last_page) if last_page.isdigit() else 9999 + except: + pass + result['list'] = vdata + result['page'] = pg + result['pagecount'] = pagecount + result['limit'] = 24 + result['total'] = pagecount * 24 if pagecount != 9999 else 999999 + return result + + def detailContent(self, ids): + data = self.getpq(ids[0]) + full_title = data('title').text().split(' - ')[0] + vn = full_title.split('線上觀看')[0].split('手機播放')[0].rstrip(',') + + vod = { + 'vod_id': ids[0], + 'vod_name': vn, + 'vod_pic': data('.vod-pic').attr('data-original') or '', + 'vod_remarks': data('.meta-post').eq(0).text().replace('', '').replace('', '').strip() or '', + 'vod_play_from': '', + 'vod_play_url': '' + } + + play_from_list = [] + play_url_list = [] + + tabs = data('#sea-tab li a') + for tab in tabs.items(): + play_from = tab.text().strip().replace('\n', '').split('')[-1] + play_from_list.append(play_from) + + tab_contents = data('#sea-tab-content .tab-pane') + for i, content in enumerate(tab_contents.items()): + episodes = [] + play_links = content('.play-list a') + for link in play_links.items(): + ep_name = link.text() or f"第 {len(episodes) + 1} 集" + ep_url = f"{self.host}{link.attr('href')}" + episodes.append(f"{ep_name}${ep_url}") + episodes.reverse() + play_url_list.append('#'.join(episodes)) + + vod['vod_play_from'] = '$$$'.join(play_from_list) + vod['vod_play_url'] = '$$$'.join(play_url_list) + + return {'list': [vod]} + + def searchContent(self, key, quick, pg="1"): + data = self.getpq(f'/ss.html?wd={key}&page={pg}') + return {'list': self.getlist(data(".update_area_lists .i_list")), 'page': pg} + + def playerContent(self, flag, id, vipFlags): + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5410.0 Safari/537.36', + 'Referer': f'{self.host}/', + 'Origin': self.host, + } + + data = self.getpq(id) + + iframe_url = data('iframe').attr('src') + if iframe_url: + if not iframe_url.startswith('http'): + iframe_url = f"{self.host}{iframe_url}" + if iframe_url.endswith('.m3u8') or iframe_url.endswith('.mp4'): + return {'parse': 0, 'url': iframe_url, 'header': headers} + return {'parse': 1, 'url': iframe_url, 'header': headers} + + video_url = data('video source').attr('src') + if video_url: + if not video_url.startswith('http'): + video_url = f"{self.host}{video_url}" + return {'parse': 0, 'url': video_url, 'header': headers} + + scripts = data('script') + for script in scripts.items(): + script_text = script.text() + if 'var player_data' in script_text or '.m3u8' in script_text or '.mp4' in script_text: + import re + urls = re.findall(r'(https?://[^\s\'"]+\.(m3u8|mp4))', script_text) + if urls: + return {'parse': 0, 'url': urls[0][0], 'header': headers} + + return {'parse': 1, 'url': id, 'header': headers} + + def localProxy(self, param): + pass + + def gethost(self): + try: + response = self.fetch('https://www.minijj.com', headers=self.headers, allow_redirects=False) + return response.headers.get('Location', 'https://www.minijj.com') + except Exception as e: + print(f"獲取主頁失敗: {str(e)}") + return "https://www.minijj.com" + + def e64(self, text): + try: + text_bytes = text.encode('utf-8') + encoded_bytes = b64encode(text_bytes) + return encoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64編碼錯誤: {str(e)}") + return "" + + def d64(self, encoded_text): + try: + encoded_bytes = encoded_text.encode('utf-8') + decoded_bytes = b64decode(encoded_bytes) + return decoded_bytes.decode('utf-8') + except Exception as e: + print(f"Base64解碼錯誤: {str(e)}") + return "" + + def getlist(self, data): + vlist = [] + for i in data.items(): + vlist.append({ + 'vod_id': i('a').attr('href'), + 'vod_name': i('.meta-title').text(), + 'vod_pic': i('img').attr('data-original'), + 'vod_remarks': i('.meta-post').text().replace('', '').replace('', '').strip(), + }) + return vlist + + def getpq(self, path=''): + h = '' if path.startswith('http') else self.host + response = self.session.get(f'{h}{path}') + response.encoding = 'utf-8' + text = response.text + try: + return pq(text) + except Exception as e: + print(f"解析 HTML 失敗: {str(e)}") + return pq(text.encode('utf-8')) \ No newline at end of file diff --git a/lrzy/py/有声小说.py b/lrzy/py/有声小说.py new file mode 100644 index 0000000..b3dc618 --- /dev/null +++ b/lrzy/py/有声小说.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +#author恰逢 +import json,re,sys,base64,requests +from Crypto.Cipher import AES +from pyquery import PyQuery as pq +sys.path.append('..') +from base.spider import Spider + +class Spider(Spider): + SELECTORS=['.video-item','.video-list .item','.list-item','.post-item'] + def getName(self):return"黑料不打烊" + def init(self,extend=""):pass + def homeContent(self,filter): + cateManual={"最新黑料":"hlcg","今日热瓜":"jrrs","每日TOP10":"mrrb","周报精选":"zbjx","月榜热瓜":"ybrg","反差女友":"fczq","校园黑料":"xycg","网红黑料":"whhl","明星丑闻":"mxcw","原创社区":"ycsq","推特社区":"ttsq","社会新闻":"shxw","官场爆料":"gchl","影视短剧":"ysdj","全球奇闻":"qqqw","黑料课堂":"hlkt","每日大赛":"mrds","激情小说":"jqxs","桃图杂志":"ttzz","深夜综艺":"syzy","独家爆料":"djbl"} + return{'class':[{'type_name':k,'type_id':v}for k,v in cateManual.items()]} + def homeVideoContent(self):return{} + def categoryContent(self,tid,pg,filter,extend): + url=f'https://heiliao.com/{tid}/'if int(pg)==1 else f'https://heiliao.com/{tid}/page/{pg}/' + videos=self.get_list(url) + return{'list':videos,'page':pg,'pagecount':9999,'limit':90,'total':999999} + def fetch_and_decrypt_image(self,url): + try: + if url.startswith('//'):url='https:'+url + elif url.startswith('/'):url='https://heiliao.com'+url + r=requests.get(url,headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.96 Safari/537.36','Referer':'https://heiliao.com/'},timeout=15,verify=False) + if r.status_code!=200:return b'' + return AES.new(b'f5d965df75336270',AES.MODE_CBC,b'97b60394abc2fbe1').decrypt(r.content) + except: return b'' + def _extract_img_from_onload(self,node): + try: + m=re.search(r"load(?:Share)?Img\s*\([^,]+,\s*['\"]([^'\"]+)['\"]",(node.attr('onload')or'')) + return m.group(1)if m else'' + except:return'' + def _should_decrypt(self,url:str)->bool: + u=(url or'').lower();return any(x in u for x in['pic.gylhaa.cn','new.slfpld.cn','/upload_01/','/upload/']) + def _abs(self,u:str)->str: + if not u:return'' + if u.startswith('//'):return'https:'+u + if u.startswith('/'):return'https://heiliao.com'+u + return u + def e64(self,s:str)->str: + try:return base64.b64encode((s or'').encode()).decode() + except:return'' + def d64(self,s:str)->str: + try:return base64.b64decode((s or'').encode()).decode() + except:return'' + def _img(self,img_node): + u=''if img_node is None else(img_node.attr('src')or img_node.attr('data-src')or'') + enc=''if img_node is None else self._extract_img_from_onload(img_node) + t=enc or u + return f"{self.getProxyUrl()}&url={self.e64(t)}&type=hlimg"if t and(enc or self._should_decrypt(t))else self._abs(t) + def _parse_items(self,root): + vids=[] + for sel in self.SELECTORS: + for it in root(sel).items(): + title=it.find('.title, h3, h4, .video-title').text() + if not title:continue + link=it.find('a').attr('href') + if not link:continue + vids.append({'vod_id':self._abs(link),'vod_name':title,'vod_pic':self._img(it.find('img')),'vod_remarks':it.find('.date, .time, .remarks, .duration').text()or''}) + if vids:break + return vids + def detailContent(self,array): + tid=array[0];url=tid if tid.startswith('http')else f'https://heiliao.com{tid}' + rsp=self.fetch(url) + if not rsp:return{'list':[]} + rsp.encoding='utf-8';html_text=rsp.text + try:root_text=pq(html_text) + except:root_text=None + try:root_content=pq(rsp.content) + except:root_content=None + title=(root_text('title').text()if root_text else'')or'' + if' - 黑料网'in title:title=title.replace(' - 黑料网','') + pic='' + if root_text: + og=root_text('meta[property="og:image"]').attr('content') + if og and(og.endswith('.png')or og.endswith('.jpg')or og.endswith('.jpeg')):pic=og + else:pic=self._img(root_text('.video-item-img img')) + detail='' + if root_text: + detail=root_text('meta[name="description"]').attr('content')or'' + if not detail:detail=root_text('.content').text()[:200] + play_from,play_url=[],[] + if root_content: + for i,p in enumerate(root_content('.dplayer').items()): + c=p.attr('config') + if not c:continue + try:s=(c.replace('"','"').replace('"','"').replace('&','&').replace('&','&').replace('<','<').replace('<','<').replace('>','>').replace('>','>'));u=(json.loads(s).get('video',{})or{}).get('url','') + except:m=re.search(r'"url"\s*:\s*"([^"]+)"',c);u=m.group(1)if m else'' + if u: + u=u.replace('\\/','/');u=self._abs(u) + play_from.append(f'视频{i+1}');play_url.append(u) + if not play_url: + for pat in[r'https://hls\.[^"\']+\.m3u8[^"\']*',r'https://[^"\']+\.m3u8\?auth_key=[^"\']+',r'//hls\.[^"\']+\.m3u8[^"\']*']: + for u in re.findall(pat,html_text): + u=self._abs(u);play_from.append(f'视频{len(play_from)+1}');play_url.append(u) + if len(play_url)>=3:break + if play_url:break + if not play_url: + js_patterns=[r'video[\s\S]{0,500}?url[\s"\'`:=]+([^"\'`\s]+)',r'videoUrl[\s"\'`:=]+([^"\'`\s]+)',r'src[\s"\'`:=]+([^"\'`\s]+\.m3u8[^"\'`\s]*)'] + for pattern in js_patterns: + js_urls=re.findall(pattern,html_text) + for js_url in js_urls: + if'.m3u8'in js_url: + if js_url.startswith('//'):js_url='https:'+js_url + elif js_url.startswith('/'):js_url='https://heiliao.com'+js_url + elif not js_url.startswith('http'):js_url='https://'+js_url + play_from.append(f'视频{len(play_from)+1}');play_url.append(js_url) + if len(play_url)>=3:break + if play_url:break + if not play_url: + play_from.append('示例视频');play_url.append("https://hls.obmoti.cn/videos5/b9699667fbbffcd464f8874395b91c81/b9699667fbbffcd464f8874395b91c81.m3u8?auth_key=1760372539-68ed273b94e7a-0-3a53bc0df110c5f149b7d374122ef1ed&v=2") + return{'list':[{'vod_id':tid,'vod_name':title,'vod_pic':pic,'vod_content':detail,'vod_play_from':'$$$'.join(play_from),'vod_play_url':'$$$'.join(play_url)}]} + def searchContent(self,key,quick,pg="1"): + rsp=self.fetch(f'https://heiliao.com/index/search?word={key}') + if not rsp:return{'list':[]} + return{'list':self._parse_items(pq(rsp.text))} + def playerContent(self,flag,id,vipFlags): + return{"parse":0,"playUrl":"","url":id,"header":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.96 Safari/537.36","Referer":"https://heiliao.com/"}} + def get_list(self,url): + rsp=self.fetch(url) + return[]if not rsp else self._parse_items(pq(rsp.text)) + def fetch(self,url,params=None,cookies=None,headers=None,timeout=5,verify=True,stream=False,allow_redirects=True): + h=headers or{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.96 Safari/537.36","Referer":"https://heiliao.com/"} + return super().fetch(url,params=params,cookies=cookies,headers=h,timeout=timeout,verify=verify,stream=stream,allow_redirects=allow_redirects) + def localProxy(self,param): + try: + if param.get('type')=='hlimg': + url=self.d64(param.get('url')) + if url.startswith('//'):url='https:'+url + elif url.startswith('/'):url='https://heiliao.com'+url + r=requests.get(url,headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.96 Safari/537.36","Referer":"https://heiliao.com/"},timeout=15,verify=False) + if r.status_code!=200:return[404,'text/plain',''] + b=AES.new(b'f5d965df75336270',AES.MODE_CBC,b'97b60394abc2fbe1').decrypt(r.content) + ct='image/jpeg' + if b.startswith(b'\x89PNG'):ct='image/png' + elif b.startswith(b'GIF8'):ct='image/gif' + return[200,ct,b] + except:pass + return[404,'text/plain',''] \ No newline at end of file diff --git a/lrzy/py/柯南影视.py b/lrzy/py/柯南影视.py new file mode 100644 index 0000000..5313945 --- /dev/null +++ b/lrzy/py/柯南影视.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import re +import sys +from urllib.parse import quote, urlparse +from Crypto.Hash import SHA256 +sys.path.append("..") +import json +import time +from pyquery import PyQuery as pq +from base.spider import Spider + +class Spider(Spider): + + def init(self, extend=""): + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def action(self, action): + pass + + def destroy(self): + pass + + host='https://www.knvod.com' + + headers = { + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Sec-Fetch-Dest': 'document', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="134", "Google Chrome";v="134"', + 'sec-ch-ua-platform': '"macOS"', + 'Origin': host, + 'Referer': f"{host}/", + 'Cookie':'X-Robots-Tag=CDN-VERIFY' + } + + def homeContent(self, filter): + data=self.getpq(self.fetch(self.host,headers=self.headers).text) + result = {} + classes = [] + for k in data('.head-more.box a').items(): + i=k.attr('href') + if i and '/show' in i: + classes.append({ + 'type_name': k.text(), + 'type_id': re.findall(r'\d+', i)[0] + }) + result['class'] = classes + result['list']=self.getlist(data('.border-box.public-r .public-list-div')) + return result + + def homeVideoContent(self): + pass + + def categoryContent(self, tid, pg, filter, extend): + data=self.getpq(self.fetch(f"{self.host}/show/{tid}--------{pg}---/",headers=self.headers).text) + result = {} + result['list'] = self.getlist(data('.border-box.public-r .public-list-div')) + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + data = self.getpq(self.fetch(f"{self.host}/list/{ids[0]}/", headers=self.headers).text) + v=data('.detail-info.lightSpeedIn .slide-info') + vod = { + 'vod_year': v.eq(-1).text().split(':',1)[-1], + 'vod_remarks': v.eq(0), + 'vod_actor': v.eq(3).text().split(':',1)[-1], + 'vod_director': v.eq(2).text().split(':',1)[-1], + 'vod_content': data('.switch-box #height_limit').text() + } + np=data('.anthology.wow.fadeInUp') + ndata=np('.anthology-tab .swiper-wrapper .swiper-slide') + pdata=np('.anthology-list .anthology-list-box ul') + play,names=[],[] + for i in range(len(ndata)): + n=ndata.eq(i)('a') + n('span').remove() + names.append(n.text()) + vs=[] + for v in pdata.eq(i)('li').items(): + vs.append(f"{v.text()}${v('a').attr('href')}") + play.append('#'.join(vs)) + vod["vod_play_from"] = "$$$".join(names) + vod["vod_play_url"] = "$$$".join(play) + result = {"list": [vod]} + return result + + def searchContent(self, key, quick, pg="1"): + data = self.fetch(f"{self.host}/index.php/ajax/suggest?mid=1&wd={key}&limit=9999×tamp={int(time.time()*1000)}", headers=self.headers).json() + videos=[] + for i in data['list']: + videos.append({ + 'vod_id': i['id'], + 'vod_name': i['name'], + 'vod_pic': i['pic'] + }) + return {'list':videos,'page':pg} + + def playerContent(self, flag, id, vipFlags): + h={ + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.8 Mobile/15E148 Safari/604.1', + 'Origin': self.host + } + data = self.getpq(self.fetch(f"{self.host}{id}", headers=self.headers).text) + try: + jstr = data('.player-box .player-left script').eq(1).text() + jsdata = json.loads(jstr.split('=',1)[-1]) + url = jsdata.get('url') + if not re.search(r'\.m3u8|\.mp4',jsdata['url']): + jxd=self.fetch(f"{self.host}/static/player/{jsdata['from']}.js", headers=self.headers).text + jx=re.search(r'http.*?url=', jxd) + if not jx:raise Exception('未找到jx') + parsed_url = urlparse(jx.group()) + jxhost = parsed_url.scheme + "://" + parsed_url.netloc + title=data('head title').eq(0).text().split('-')[0] + next=f"{self.host.split('//')[-1]}{jsdata['link_next']}" if jsdata.get('link_next') else '' + cd=self.fetch(f"{jx.group()}{jsdata['url']}&next=//{next}&title={quote(title)}", headers=self.headers).text + match = re.search(r'var\s+config\s*=\s*(\{[\s\S]*?\})', cd) + if not match:raise Exception('未找到config') + cm=re.sub(r',\s*}(?=\s*$)', '}', match.group(1)) + config=json.loads(cm) + config.update({'key':self.sha256(f"{self.gettime()}knvod")}) + config.pop('next',None) + headers = { + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.8 Mobile/15E148 Safari/604.1', + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Cache-Control': 'no-cache', + 'DNT': '1', + 'Origin': jxhost, + 'Pragma': 'no-cache', + 'Sec-Fetch-Dest': 'empty', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'same-origin', + 'Sec-Fetch-Storage-Access': 'active', + 'X-Requested-With': 'XMLHttpRequest', + } + h['Origin']=jxhost + jd=self.post(f"{jxhost}/post.php", headers=headers, data=json.dumps(config)) + data=json.loads(jd.content.decode('utf-8-sig')) + url=data.get('knvod') + p = 0 + if not url:raise Exception('未找到播放地址') + except Exception as e: + print('错误信息:',e) + p,url=1,f"{self.host}{id}" + return {"parse": p, "url": url, "header": h} + + def localProxy(self, param): + pass + + def getlist(self,data): + videos=[] + for i in data.items(): + id = i('a').attr('href') + if id: + id = re.search(r'\d+', id).group(0) + img = i('img').attr('data-src') + if img and 'url=' in img and 'http' not in img: img = f'{self.host}{img}' + videos.append({ + 'vod_id': id, + 'vod_name': i('a').attr('title'), + 'vod_pic': img, + 'vod_remarks': i('.public-prt').text() or i('.public-list-prb').text() + }) + return videos + + def getpq(self, data): + try: + return pq(data) + except Exception as e: + print(f"{str(e)}") + return pq(data.encode('utf-8')) + + def gettime(self): + current_time = int(time.time()) + hourly_timestamp = current_time - (current_time % 3600) + return hourly_timestamp + + def sha256(self, text): + sha = SHA256.new() + sha.update(text.encode()) + return sha.hexdigest() diff --git a/lrzy/py/永乐视频.py b/lrzy/py/永乐视频.py new file mode 100644 index 0000000..96d53f8 --- /dev/null +++ b/lrzy/py/永乐视频.py @@ -0,0 +1,231 @@ +# coding=utf-8 +#!/usr/bin/env python3 +#七哥定制版 +import re +import sys +import urllib.parse +import requests +from bs4 import BeautifulSoup + +# 禁用SSL证书验证警告 +import urllib3 +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +sys.path.append('..') +from base.spider import Spider + +class Spider(Spider): + def getName(self): + return "永乐视频" + + def init(self, extend=""): + self.host = "https://www.ylys.tv/" + self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Referer': self.host} + self.session = requests.Session() + self.session.verify = False + self.session.headers.update(self.headers) + + def fetch(self, url, timeout=30): + try: + response = self.session.get(url, timeout=timeout, verify=False) + response.encoding = response.encoding if response.encoding != 'ISO-8859-1' else 'UTF-8' + return response + except: + return None + + def homeContent(self, filter): + result = { + "class": [{'type_id': str(i), 'type_name': t} for i, t in enumerate(['电影', '剧集', '综艺', '动漫'], 1)], + "filters": self._get_filters(), + "list": [] + } + rsp = self.fetch(self.host) + if rsp and rsp.status_code == 200: + result['list'] = self._extract_videos(rsp.text, 20) + return result + + def categoryContent(self, tid, pg, filter, extend): + result = {"list": [], "page": int(pg), "pagecount": 99, "limit": 20, "total": 1980} + url = f"{self.host}/vodtype/{tid}/page/{pg}/" if int(pg) > 1 else f"{self.host}/vodtype/{tid}/" + rsp = self.fetch(url) + if rsp and rsp.status_code == 200: + result['list'] = self._extract_videos(rsp.text) + return result + + def searchContent(self, key, quick, pg=1): + result = {"list": []} + search_key = urllib.parse.quote(key) + url = f"{self.host}/vodsearch/{search_key}-------------/page/{pg}/" if int(pg) > 1 else f"{self.host}/vodsearch/{search_key}-------------/" + rsp = self.fetch(url) + if rsp and rsp.status_code == 200: + result['list'] = self._extract_search_results(rsp.text) + return result + + def detailContent(self, ids): + result = {"list": []} + vid = ids[0] + rsp = self.fetch(f"{self.host}/voddetail/{vid}/") + if not rsp or rsp.status_code != 200: + return result + + html = rsp.text + play_from, play_url = self._extract_play_info(html, vid) + + if play_from: + result['list'] = [{ + 'vod_id': vid, + 'vod_name': self._extract_title(html), + 'vod_pic': self._extract_pic(html), + 'vod_content': self._extract_desc(html), + 'vod_remarks': self._extract_remarks(html), + 'vod_play_from': "$$$".join(play_from), + 'vod_play_url': "$$$".join(play_url) + }] + return result + + def playerContent(self, flag, id, vipFlags): + result = {"parse": 1, "playUrl": "", "url": ""} + if "-" not in id: + return result + + rsp = self.fetch(f"{self.host}/play/{id}/") + if not rsp or rsp.status_code != 200: + return result + + real_url_match = re.search(r'var player_aaaa=.*?"url":"([^"]+\.m3u8)"', rsp.text, re.S | re.I) + if real_url_match: + real_url = real_url_match.group(1).replace(r'\u002F', '/').replace(r'\/', '/') + result["parse"] = 0 + result["url"] = real_url + else: + result["url"] = f"{self.host}/play/{id}/" + return result + + def _get_filters(self): + return { + "1": [{"key": "class", "name": "类型", "value": [ + {"n": "全部", "v": ""}, {"n": "动作片", "v": "6"}, {"n": "喜剧片", "v": "7"}, + {"n": "爱情片", "v": "8"}, {"n": "科幻片", "v": "9"}, {"n": "恐怖片", "v": "11"} + ]}], + "2": [{"key": "class", "name": "类型", "value": [ + {"n": "全部", "v": ""}, {"n": "国产剧", "v": "13"}, {"n": "港台剧", "v": "14"}, + {"n": "日剧", "v": "15"}, {"n": "韩剧", "v": "33"}, {"n": "欧美剧", "v": "16"} + ]}], + "3": [{"key": "class", "name": "类型", "value": [ + {"n": "全部", "v": ""}, {"n": "内地综艺", "v": "27"}, {"n": "港台综艺", "v": "28"}, + {"n": "日本综艺", "v": "29"}, {"n": "韩国综艺", "v": "36"} + ]}], + "4": [{"key": "class", "name": "类型", "value": [ + {"n": "全部", "v": ""}, {"n": "国产动漫", "v": "31"}, {"n": "日本动漫", "v": "32"}, + {"n": "欧美动漫", "v": "42"}, {"n": "其他动漫", "v": "43"} + ]}] + } + + def _extract_videos(self, html, limit=0): + videos = [] + pattern = r'([^<]+).*?data-original="([^"]+)"' + for vid, title, remark, pic in re.findall(pattern, html, re.S | re.I): + videos.append({ + 'vod_id': vid.strip(), + 'vod_name': title.strip(), + 'vod_pic': (self.host + pic if pic.startswith('/') else pic).strip(), + 'vod_remarks': remark.strip() + }) + return videos[:limit] if limit and len(videos) > limit else videos + + def _extract_search_results(self, html): + videos = [] + soup = BeautifulSoup(html, 'html.parser') + for item in soup.select('.module-card-item'): + link = item.select_one('a[href^="/voddetail/"]') + if not link: + continue + + href = link.get('href', '') + vid_match = re.search(r'/voddetail/(\d+)/', href) + if not vid_match: + continue + + vid = vid_match.group(1) + title_elem = item.select_one('.module-card-item-title strong') + img_elem = item.select_one('img') + pic = (img_elem.get('data-original') or img_elem.get('src')) if img_elem else "" + note_elem = item.select_one('.module-item-note') + + videos.append({ + 'vod_id': vid, + 'vod_name': title_elem.get_text(strip=True) if title_elem else "", + 'vod_pic': self.host + pic if pic.startswith('/') else pic, + 'vod_remarks': note_elem.get_text(strip=True) if note_elem else "" + }) + return videos + + def _extract_play_info(self, html, vid): + play_from, play_url = [], [] + line_pattern = r'<(?:div|a)[^>]*class="[^"]*module-tab-item[^"]*"[^>]*>(?:.*?([^<]+).*?(\d+)|.*?([^<]+).*?(\d+))' + + for match in re.findall(line_pattern, html, re.S | re.I): + line_name = match[0] or match[2] + if line_name in play_from: + continue + + play_from.append(line_name) + line_id = self._get_line_id(html, vid, line_name) + + ep_matches = re.findall(rf']*>.*?([^<]+)', html, re.S | re.I) + eps = [f"{ep_name.strip()}${vid}-{line_id}-{ep_num.strip()}" for ep_num, ep_name in ep_matches] + play_url.append("#".join(eps)) + + return play_from, play_url + + def _get_line_id(self, html, vid, line_name): + line_id_match = re.search(rf']*href="/play/{vid}-(\d+)-1/"[^>]*>.*?{re.escape(line_name)}', html, re.S | re.I) + if line_id_match: + return line_id_match.group(1) + + line_id_map = {"全球3线": "3", "大陆0线": "1", "大陆3线": "4", "大陆5线": "2", "大陆6线": "3"} + return line_id_map.get(line_name, "1") + + def _extract_title(self, html): + title_match = re.search(r'', html, re.S | re.I) + year = year_match.group(1) if year_match else "未知年份" + + area_match = re.search(r'', html, re.S | re.I) + area = area_match.group(1) if area_match else "未知产地" + + type_match = re.search(r'vod_class":"([^"]+)"', html, re.S | re.I) + type_str = type_match.group(1).replace(",", "/") if type_match else "未知类型" + + return f"{year} | {area} | {type_str}" + +# 本地测试 +if __name__ == "__main__": + spider = Spider() + spider.init() + + # 测试详情页解析 + detail_result = spider.detailContent(["86027"]) + if detail_result['list']: + detail = detail_result['list'][0] + print(f"视频名称: {detail.get('vod_name', '未知')}") + + # 测试搜索功能 + search_result = spider.searchContent("仙逆", False, 1) + print(f"搜索结果数量: {len(search_result['list'])}") + + # 测试播放功能 + play_result = spider.playerContent("", "86027-5-1", {}) + print(f"播放URL: {play_result.get('url', '')}") \ No newline at end of file diff --git a/lrzy/py/泥视频.py b/lrzy/py/泥视频.py new file mode 100644 index 0000000..a266f1b --- /dev/null +++ b/lrzy/py/泥视频.py @@ -0,0 +1,436 @@ +# -*- coding: utf-8 -*- +# 泥视频 - https://www.nivod.vip/ +import re +import sys +import json +import time +from urllib.parse import quote, unquote +from pyquery import PyQuery as pq +sys.path.append('..') +from base.spider import Spider + +class Spider(Spider): + def init(self, extend=""): + pass + + def getName(self): + return "泥视频" + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host = 'https://www.nivod.vip' + + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'Accept-Encoding': 'gzip, deflate, br', + 'DNT': '1', + 'Connection': 'keep-alive', + 'Upgrade-Insecure-Requests': '1', + } + + def homeContent(self, filter): + """获取首页内容和分类""" + try: + response = self.fetch_with_encoding(self.host, headers=self.headers) + doc = self.getpq(response.text) + + result = {} + classes = [] + + # 获取分类导航 + nav_items = doc('.navbar a') + for item in nav_items.items(): + text = item.text().strip() + href = item.attr('href') + if text and href and href != '/' and '/t/' in href: + # 提取分类ID + type_id = href.split('/t/')[-1].rstrip('/') + if type_id.isdigit(): + classes.append({ + 'type_name': text, + 'type_id': type_id + }) + + # 获取首页视频列表 + videos = [] + video_items = doc('.module-item') + for item in video_items.items(): + try: + title = item.attr('title') or '' + href = item.attr('href') or '' + + if title and href: + # 提取视频ID + vod_id = href.split('/nivod/')[-1].rstrip('/') + + # 获取图片 - 优先获取data-original(真实图片),避免懒加载占位图 + img_elem = item.find('img') + pic = '' + if img_elem: + # 优先获取data-original(真实图片URL),然后是data-src,最后是src + pic = img_elem.attr('data-original') or img_elem.attr('data-src') or img_elem.attr('src') or '' + if pic and not pic.startswith('http'): + pic = self.host + pic if pic.startswith('/') else '' + + # 获取备注信息 + note_elem = item.find('.module-item-note') + remarks = note_elem.text() if note_elem else '' + + videos.append({ + 'vod_id': vod_id, + 'vod_name': title, + 'vod_pic': pic, + 'vod_year': '', + 'vod_remarks': remarks + }) + except Exception as e: + self.log(f"解析视频项时出错: {e}") + continue + + result['class'] = classes + result['list'] = videos + return result + + except Exception as e: + self.log(f"获取首页内容时出错: {e}") + return {'class': [], 'list': []} + + def homeVideoContent(self): + """获取推荐视频""" + return {'list': []} + + def categoryContent(self, tid, pg, filter, extend): + """获取分类内容""" + try: + # 构建分类URL + url = f"{self.host}/t/{tid}/" + if int(pg) > 1: + url = f"{self.host}/t/{tid}/page/{pg}/" + + response = self.fetch_with_encoding(url, headers=self.headers) + doc = self.getpq(response.text) + + # 获取视频列表 + videos = [] + video_items = doc('.module-item') + for item in video_items.items(): + try: + title = item.attr('title') or '' + href = item.attr('href') or '' + + if title and href: + # 提取视频ID + vod_id = href.split('/nivod/')[-1].rstrip('/') + + # 获取图片 - 优先获取data-original(真实图片),避免懒加载占位图 + img_elem = item.find('img') + pic = '' + if img_elem: + # 优先获取data-original(真实图片URL),然后是data-src,最后是src + pic = img_elem.attr('data-original') or img_elem.attr('data-src') or img_elem.attr('src') or '' + if pic and not pic.startswith('http'): + pic = self.host + pic if pic.startswith('/') else '' + + # 获取备注信息 + note_elem = item.find('.module-item-note') + remarks = note_elem.text() if note_elem else '' + + videos.append({ + 'vod_id': vod_id, + 'vod_name': title, + 'vod_pic': pic, + 'vod_year': '', + 'vod_remarks': remarks + }) + except Exception as e: + self.log(f"解析分类视频项时出错: {e}") + continue + + result = { + 'list': videos, + 'page': pg, + 'pagecount': 9999, # 设置一个较大的值 + 'limit': 80, + 'total': 999999 + } + return result + + except Exception as e: + self.log(f"获取分类内容时出错: {e}") + return {'list': [], 'page': pg, 'pagecount': 1, 'limit': 80, 'total': 0} + + def detailContent(self, ids): + """获取视频详情""" + try: + vod_id = ids[0] + url = f"{self.host}/nivod/{vod_id}/" + + response = self.fetch_with_encoding(url, headers=self.headers) + doc = self.getpq(response.text) + + # 获取标题 + title_elem = doc('h1') + title = self.fix_encoding(title_elem.text()) if title_elem else '' + + # 获取视频信息 + info_elem = doc('.module-info') + content = self.fix_encoding(info_elem.text()) if info_elem else '' + + # 获取播放源和播放列表 + play_from = [] + play_url = [] + + # 获取播放源标签 + tab_items = doc('.module-tab-item') + play_lists = doc('.module-play-list') + + for i, tab in enumerate(tab_items.items()): + # 分别提取播放源名称和集数 + span_elem = tab.find('span') + small_elem = tab.find('small') + + source_name = '' + if span_elem: + source_name = self.fix_encoding(span_elem.text().strip()) + # 如果有集数信息,添加到播放源名称后 + if small_elem: + episode_count = self.fix_encoding(small_elem.text().strip()) + source_name = f"{source_name}{episode_count}" + else: + # 如果没有span元素,使用整个文本 + source_name = self.fix_encoding(tab.text().strip()) + + if source_name: + play_from.append(source_name) + + # 获取对应的播放列表 + episodes = [] + if i < len(play_lists): + episode_items = play_lists.eq(i).find('a') + for ep in episode_items.items(): + ep_title = self.fix_encoding(ep.text().strip()) + ep_href = ep.attr('href') + if ep_title and ep_href: + episodes.append(f"{ep_title}${ep_href}") + + play_url.append('#'.join(episodes)) + + vod = { + 'vod_id': vod_id, + 'vod_name': title, + 'vod_pic': '', + 'vod_year': '', + 'vod_remarks': '', + 'vod_actor': '', + 'vod_director': '', + 'vod_content': content, + 'vod_play_from': '$$$'.join(play_from), + 'vod_play_url': '$$$'.join(play_url) + } + + return {'list': [vod]} + + except Exception as e: + self.log(f"获取视频详情时出错: {e}") + return {'list': []} + + def searchContent(self, key, quick, pg="1"): + """搜索内容""" + try: + # 使用正确的搜索URL格式 + search_url = f"{self.host}/s/-------------/" + params = {'wd': key} + + response = self.fetch_with_encoding(search_url, params=params, headers=self.headers) + doc = self.getpq(response.text) + + # 获取搜索结果 + videos = [] + video_items = doc('.module-item') + for item in video_items.items(): + try: + # 搜索页面的结构不同,需要从内部链接获取信息 + # 查找详情链接(通常是第一个或标题链接) + detail_links = item.find('a[href*="/nivod/"]') + if not detail_links: + continue + + # 获取第一个详情链接 + detail_link = detail_links.eq(0) + href = detail_link.attr('href') + + if not href: + continue + + # 提取视频ID + vod_id = href.split('/nivod/')[-1].rstrip('/') + + # 获取标题 - 尝试多种方式 + title = '' + # 方法1: 从链接的strong标签获取 + strong_elem = detail_link.find('strong') + if strong_elem: + title = self.fix_encoding(strong_elem.text().strip()) + + # 方法2: 从图片的alt属性获取 + if not title: + img_elem = item.find('img') + if img_elem: + title = self.fix_encoding(img_elem.attr('alt') or '') + + # 方法3: 从链接文本获取 + if not title: + title = self.fix_encoding(detail_link.text().strip()) + + if not title: + continue + + # 获取图片 - 优先获取data-original(真实图片),避免懒加载占位图 + img_elem = item.find('img') + pic = '' + if img_elem: + # 优先获取data-original(真实图片URL),然后是data-src,最后是src + pic = img_elem.attr('data-original') or img_elem.attr('data-src') or img_elem.attr('src') or '' + if pic and not pic.startswith('http'): + pic = self.host + pic if pic.startswith('/') else '' + + # 获取备注信息 + note_elem = item.find('.module-item-note') + remarks = self.fix_encoding(note_elem.text()) if note_elem else '' + + videos.append({ + 'vod_id': vod_id, + 'vod_name': title, + 'vod_pic': pic, + 'vod_year': '', + 'vod_remarks': remarks + }) + except Exception as e: + self.log(f"解析搜索结果时出错: {e}") + continue + + return {'list': videos, 'page': pg} + + except Exception as e: + self.log(f"搜索时出错: {e}") + return {'list': [], 'page': pg} + + def playerContent(self, flag, id, vipFlags): + """获取播放地址""" + try: + # 播放页面URL + play_url = f"{self.host}{id}" + + response = self.fetch_with_encoding(play_url, headers=self.headers) + doc = self.getpq(response.text) + + # 查找播放器配置 + scripts = doc('script') + for script in scripts.items(): + script_text = script.text() + if 'player' in script_text and ('url' in script_text): + # 尝试提取播放地址 + url_match = re.search(r'"url"\s*:\s*"([^"]+)"', script_text) + if url_match: + video_url = url_match.group(1) + return { + 'parse': 0, + 'url': video_url, + 'header': self.headers + } + + # 如果没有找到直接播放地址,返回播放页面让系统解析 + return { + 'parse': 1, + 'url': play_url, + 'header': self.headers + } + + except Exception as e: + self.log(f"获取播放地址时出错: {e}") + return { + 'parse': 1, + 'url': f"{self.host}{id}", + 'header': self.headers + } + + def localProxy(self, param): + pass + + def fix_encoding(self, text): + """修复UTF-8编码问题""" + if not text: + return text + + try: + # 检查是否包含乱码特征(常见的UTF-8乱码模式) + garbled_patterns = [ + '\u00e4\u00b8', '\u00e5', '\u00e6', '\u00e7', '\u00e8', '\u00e9', # 常见乱码前缀 + '\u00c3\u00a4', '\u00c3\u00a5', '\u00c3\u00a6', # UTF-8被误解为Latin1 + '\u00ef\u00bc', '\u00e2\u0080' # 标点符号乱码 + ] + + has_garbled = any(pattern in text for pattern in garbled_patterns) + + if has_garbled: + self.log("检测到编码问题,尝试修复...") + + # 方法1: 尝试Latin1->UTF-8转换 + try: + fixed = text.encode('latin1').decode('utf-8') + # 检查是否修复成功(包含中文字符) + if re.search(r'[\u4e00-\u9fff]', fixed): + self.log("使用Latin1->UTF-8修复成功") + return fixed + except Exception as e: + self.log(f"Latin1->UTF-8修复失败: {e}") + + # 方法2: 尝试其他编码转换 + encodings = ['cp1252', 'iso-8859-1'] + for encoding in encodings: + try: + fixed = text.encode(encoding).decode('utf-8') + if re.search(r'[\u4e00-\u9fff]', fixed): + self.log(f"使用{encoding}->UTF-8修复成功") + return fixed + except: + continue + + self.log("编码修复失败,返回原文本") + + return text + + except Exception as e: + self.log(f"编码修复异常: {e}") + return text + + def fetch_with_encoding(self, url, **kwargs): + """带编码处理的请求方法""" + try: + response = self.fetch(url, **kwargs) + # 确保使用UTF-8编码 + response.encoding = 'utf-8' + return response + except Exception as e: + self.log(f"请求失败: {e}") + raise + + def getpq(self, text): + """安全的pyquery解析""" + try: + return pq(text) + except Exception as e: + self.log(f"pyquery解析出错: {e}") + try: + return pq(text.encode('utf-8')) + except: + return pq('') diff --git a/lrzy/py/爱瓜影视.py b/lrzy/py/爱瓜影视.py new file mode 100644 index 0000000..e3b1e51 --- /dev/null +++ b/lrzy/py/爱瓜影视.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +# 温馨提示:搜索只能搜拼音联想 +# 播放需要挂代理 +import sys +import time +import uuid +from Crypto.Hash import MD5 +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + self.uid = self.getuid() + self.token, self.code = self.getuserinfo() + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host = 'https://tvapi211.magicetech.com' + + headers = {'User-Agent': 'okhttp/3.11.0'} + + def homeContent(self, filter): + body = {'token': self.token, 'authcode': self.code} + data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/filter-header', json=self.getbody(body), + headers=self.headers).json() + result = {} + classes = [] + filters = {} + for k in data['data']: + classes.append({ + 'type_name': k['channel_name'], + 'type_id': str(k['channel_id']), + }) + filters[str(k['channel_id'])] = [] + for i in k['search_box']: + if len(i['list']): + filters[str(k['channel_id'])].append({ + 'key': i['field'], + 'name': i['label'], + 'value': [{'n': j['display'], 'v': str(j['value'])} for j in i['list'] if j['value']] + }) + result['class'] = classes + result['filters'] = filters + return result + + def homeVideoContent(self): + body = {'token': self.token, 'authcode': self.code} + data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/index-tv', json=self.getbody(body), + headers=self.headers).json() + return {'list': self.getlist(data['data'][0]['banner'])} + + def categoryContent(self, tid, pg, filter, extend): + body = {'token': self.token, 'authcode': self.code, 'channel_id': tid, 'area': extend.get('area', '0'), + 'year': extend.get('year', '0'), 'sort': extend.get('sort', '0'), 'tag': extend.get('tag', 'hot'), + 'status': extend.get('status', '0'), 'page_num': pg, 'page_size': '24'} + data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/filter-video', json=self.getbody(body), + headers=self.headers).json() + result = {} + result['list'] = self.getlist(data['data']['list']) + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + ids = ids[0].split('@') + body = {'token': self.token, 'authcode': self.code, 'channel_id': ids[0], 'video_id': ids[1]} + data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/detail', json=self.getbody(body), + headers=self.headers).json() + vdata = {} + for k in data['data']['chapters']: + i = k['sourcelist'] + for j in i: + if j['source_name'] not in vdata: vdata[j['source_name']] = [] + vdata[j['source_name']].append(f"{k['title']}${j['source_url']}") + plist, names = [], [] + for key, value in vdata.items(): + names.append(key) + plist.append('#'.join(value)) + vod = { + 'vod_play_from': '$$$'.join(names), + 'vod_play_url': '$$$'.join(plist), + } + return {'list': [vod]} + + def searchContent(self, key, quick, pg="1"): + body = {'token': self.token, 'authcode': self.code, 'keyword': key, 'page_num': pg} + data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/search/letter-result', json=self.getbody(body), + headers=self.headers).json() + return {'list': self.getlist(data['data']['list'])} + + def playerContent(self, flag, id, vipFlags): + # https://rysp.tv + # https://aigua.tv + result = { + "parse": 0, + "url": id, + "header": { + "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)", + "Origin": "https://aigua.tv", + "Referer": "https://aigua.tv/" + } + } + return result + + def localProxy(self, param): + pass + + def getuserinfo(self): + data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/user/auth-login', json=self.getbody(), + headers=self.headers).json() + v = data['data'] + return v['user_token'], v['authcode'] + + def getuid(self): + uid = self.getCache('uid') + if not uid: + uid = str(uuid.uuid4()) + self.setCache('uid', uid) + return uid + + def getbody(self, json_data=None): + if json_data is None: json_data = {} + params = {"product": "4", "ver": "1.1.0", "debug": "1", "appId": "1", "osType": "3", "marketChannel": "tv", + "sysVer": "11", "time": str(int(time.time())), "packageName": "com.gzsptv.gztvvideo", + "udid": self.uid, } + json_data.update(params) + sorted_json = dict(sorted(json_data.items(), key=lambda item: item[0])) + text = '&'.join(f"{k}={v}" for k, v in sorted_json.items() if v != '') + md5_hash = self.md5(f"jI7POOBbmiUZ0lmi{text}D9ShYdN51ksWptpkTu11yenAJu7Zu3cR").upper() + json_data.update({'sign': md5_hash}) + return json_data + + def md5(self, text): + h = MD5.new() + h.update(text.encode('utf-8')) + return h.hexdigest() + + def getlist(self, data): + videos = [] + for i in data: + if type(i.get('video')) == dict: i = i['video'] + videos.append({ + 'vod_id': f"{i.get('channel_id')}@{i.get('video_id')}", + 'vod_name': i.get('video_name'), + 'vod_pic': i.get('cover'), + 'vod_year': i.get('score'), + 'vod_remarks': i.get('flag'), + }) + return videos + diff --git a/lrzy/py/爱看短剧.py b/lrzy/py/爱看短剧.py new file mode 100644 index 0000000..638f407 --- /dev/null +++ b/lrzy/py/爱看短剧.py @@ -0,0 +1,314 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import base64 +import binascii +import json +import random +import sys +import time +import uuid +from base64 import b64decode, b64encode +from Crypto.Cipher import AES +from Crypto.Hash import MD5 +from Crypto.Util.Padding import unpad, pad +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + self.ut = False + # self.did, self.ntid =self.getdid() + self.did, self.ntid = 'e59eb2465f61b9ca','65a0de19b3a2ec93fa479ad6' + self.token, self.uid = self.gettoken() + self.phost, self.phz,self.mphost=self.getpic() + # self.phost, self.phz,self.mphost = ('https://dbtp.tgydy.com','.log','https://dplay.nbzsmc.com') + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + host='http://192.151.245.34:8089' + + def md5(self, text): + h = MD5.new() + h.update(text.encode('utf-8')) + return h.hexdigest() + + def uuid(self): + return str(uuid.uuid4()) + + def getdid(self): + did = self.random_str(16) + ntid = self.random_str(24) + return did, ntid + # try: + # if self.getCache('did'): + # return self.getCache('did'), self.getCache('ntid') + # else: + # self.setCache('did', did) + # self.setCache('ntid', ntid) + # return did, ntid + # except Exception as e: + # self.setCache('did', did) + # self.setCache('ntid', ntid) + # return did, ntid + + def aes(self, text, bool=True): + key = b64decode('c0k4N1RfKTY1U1cjJERFRA==') + iv = b64decode('VzIjQWRDVkdZSGFzSEdEVA==') + if bool: + cipher = AES.new(key, AES.MODE_CBC, iv) + ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size)) + ct = b64encode(ct_bytes).decode("utf-8") + return ct + else: + cipher = AES.new(key, AES.MODE_CBC, iv) + pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size) + ptt=json.loads(pt.decode("utf-8")) + return ptt + + def random_str(self,length=24): + hex_chars = '0123456789abcdef' + return ''.join(random.choice(hex_chars) for _ in range(length)) + + def gettoken(self): + params={"deviceId":self.did,"deviceModel":"8848钛晶手机","devicePlatform":"1","tenantId":self.ntid} + data=self.getdata('/supports/anonyLogin',params) + self.ut=True + return data['data']['token'], data['data']['userId'] + + def getdata(self,path,params=None): + t = int(time.time()*1000) + n=self.md5(f'{self.uuid()}{t}') + if params: + ct=self.aes(json.dumps(params)) + else: + ct=f'{t}{n}' + s=self.md5(f'{ct}8j@78m.367HGDF') + headers = { + 'User-Agent': 'okhttp-okgo/jeasonlzy', + 'Connection': 'Keep-Alive', + 'Accept-Language': 'zh-CN,zh;q=0.8', + 'tenantId': self.ntid, + 'n': n, + 't': str(int(t/1000)), + 's': s, + } + if self.ut: + headers['ta-token'] = self.token + headers['userId'] = self.uid + if params: + params={'ct':ct} + response = self.post(f'{self.host}{path}', headers=headers, json=params).text + else: + response = self.fetch(f'{self.host}{path}', headers=headers).text + data=self.aes(response[1:-1],False) + return data + + def getpic(self): + try: + at = int(time.time() * 1000) + t=str(int(at/ 1000)) + n = self.md5(f'{self.uuid()}{at}') + headers = { + 'Host': '192.151.245.34:8089', + 'User-Agent': 'okhttp-okgo/jeasonlzy', + 'Connection': 'Keep-Alive', + 'Accept-Language': 'zh-CN,zh;q=0.8', + 'tenantId': self.ntid, + 'userId': self.uid, + 'ta-token': self.token, + 'n': n, + 't': t, + 's': self.md5(f'{t}{n}8j@78m.367HGDF') + } + params = { + 'tenantId': self.ntid, + } + response = self.fetch(f'{self.host}/supports/configs', params=params, headers=headers).text + data=self.aes(response[1:-1],False) + config = { + 'image_cdn': '', + 'image_cdn_path': '', + 'cdn-domain': '' + } + for item in data.get('data', []): + name = item.get('name') + records = item.get('records', []) + + if name in config and records: + value = records[0].get('value', '') + if name == 'cdn-domain': + value = value.split('#')[0] + config[name] = value + + return config['image_cdn'], config['image_cdn_path'], config['cdn-domain'] + + except Exception as e: + print(f"Error in getpic: {e}") + return 'https://dbtp.tgydy.com', '.log', 'https://dplay.nbzsmc.com' + + def getlist(self,data): + vod=[] + for i in data: + vod.append({ + 'vod_id': f'{i.get("movieId")}@{i.get("entryNum")}', + 'vod_name': i.get('title'), + 'vod_pic': f'{self.getProxyUrl()}&path={i.get("thumbnail")}', + 'vod_year': i.get('score'), + 'vod_remarks': f'{i.get("entryNum")}集' + }) + return vod + + def homeContent(self, filter): + data=self.getdata('/movies/classifies') + result = {} + cateManual = { + "榜单": "ranking/getTodayHotRank", + "专辑": "getTMovieFolderPage", + "剧场": "getClassMoviePage2", + "演员": "follow/getRecommendActorPage", + } + classes = [] + for k in cateManual: + classes.append({ + 'type_name': k, + 'type_id': cateManual[k] + }) + filters = {} + if data.get('data'): + filters["getClassMoviePage2"] = [ + { + "key": "type", + "name": "分类", + "value": [ + {"n": item["name"], "v": item["classifyId"]} + for item in data["data"] + ] + } + ] + filters["ranking/getTodayHotRank"] = [ + { + "key": "type", + "name": "榜单", + "value": [ + {"n": "播放榜", "v": "getWeekHotPlayRank"}, + {"n": "高赞榜", "v": "getWeekStarRank"}, + {"n": "追剧榜", "v": "getSubTMoviePage"}, + {"n": "高分榜", "v": "ranking/getScoreRank"} + ] + } + ] + filters["follow/getRecommendActorPage"] = [ + { + "key": "type", + "name": "性别", + "value": [ + {"n": "男", "v": "0"}, + {"n": "女", "v": "1"} + ] + } + ] + result['class'] = classes + result['filters'] = filters + return result + + def homeVideoContent(self): + params = {"pageNo":"1","pageSize":"30","platform":"1","deviceId":self.did,"tenantId":self.ntid} + data=self.getdata('/news/getRecommendTMoviePage',params) + vod=self.getlist(data['data']['records']) + return {'list':vod} + + def categoryContent(self, tid, pg, filter, extend): + params={} + path = f'/news/{tid}' + if tid=='getClassMoviePage2': + parama={"pageNo":pg,"pageSize":"30","orderFlag":"0","haveActor":"-1","classifyId":extend.get('type','-1'),"tagId":""} + elif 'rank' in tid: + path=f'/news/{extend.get("type") or tid}' + parama={"pageNo":pg,"pageSize":"30"} + elif 'follow' in tid: + parama={"pageNo":pg,"pageSize":"20"} + if extend.get('type'): + path=f'/news/getActorPage' + parama={"pageNo":pg,"pageSize":"50","sex":extend.get('type')} + elif tid=='getTMovieFolderPage': + parama={"pageNo":pg,"pageSize":"20"} + elif '@' in tid: + path='/news/getActorTMoviePage' + parama={"id":tid.split('@')[0],"pageNo":pg,"pageSize":"30"} + params['platform'] = '1' + params['deviceId'] = self.did + params['tenantId'] = self.ntid + data=self.getdata(path,parama) + vods=[] + if 'follow' in tid: + for i in data['data']['records']: + vods.append({ + 'vod_id': f'{i.get("id")}@', + 'vod_name': i.get('name'), + 'vod_pic': i.get('avatar'), + 'vod_tag': 'folder', + 'vod_remarks': f'作品{i.get("movieNum")}', + 'style': {"type": "oval"} + }) + else: + vdata=data['data']['records'] + if tid=='getTMovieFolderPage': + vdata=[j for i in data['data']['records'] for j in i['movieList']] + vods=self.getlist(vdata) + result = {} + result['list'] = vods + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + ids=ids[0].split('@') + params = {"pageNo": "1", "pageSize": ids[1], "movieId": ids[0], "platform": "1", "deviceId": self.did, "tenantId": self.ntid} + data = self.getdata('/news/getEntryPage', params) + print(data) + plist=[f'第{i.get("entryNum")}集${i.get("mp4PlayAddress") or i.get("playAddress")}' for i in data['data']['records']] + vod = { + 'vod_play_from': '爱看短剧', + 'vod_play_url': '#'.join(plist), + } + return {'list':[vod]} + + def searchContent(self, key, quick, pg="1"): + params = {"pageNo": pg, "pageSize": "20", "keyWord": key, "orderFlag": "0", "platform": "1", "deviceId": self.did, "tenantId": self.ntid} + data = self.getdata('/news/searchTMoviePage', params) + vod = self.getlist(data['data']['records']) + return {'list':vod,'page':pg} + + def playerContent(self, flag, id, vipFlags): + return {'parse': 0, 'url': f'{self.mphost}{id}', 'header': {'User-Agent':'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'}} + + def localProxy(self, param): + type=param.get('path').split('.')[-1] + data=self.fetch(f'{self.phost}{param.get("path")}{self.phz}',headers={'User-Agent':'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'}) + def decrypt(encrypted_text): + try: + key = base64.urlsafe_b64decode("iM41VipvCFtToAFFRExEXw==") + iv = base64.urlsafe_b64decode("0AXRTXzmMSrlRSemWb4sVQ==") + cipher = AES.new(key, AES.MODE_CBC, iv) + decrypted_padded = cipher.decrypt(encrypted_text) + decrypted_data = unpad(decrypted_padded, AES.block_size) + return decrypted_data + except (binascii.Error, ValueError): + return None + return [200, f'image/{type}', decrypt(data.content)] + diff --git a/lrzy/py/猎手影视.py b/lrzy/py/猎手影视.py new file mode 100644 index 0000000..1a6a4d7 --- /dev/null +++ b/lrzy/py/猎手影视.py @@ -0,0 +1,279 @@ +# coding=utf-8 +# !/usr/bin/python +# by嗷呜(finally) +import sys +import os +sys.path.append("..") +import re +import hashlib +import hmac +import random +import string +from Crypto.Util.Padding import unpad +from concurrent.futures import ThreadPoolExecutor +from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_v1_5, AES +from base64 import b64encode, b64decode +import json +import time +from base.spider import Spider + +class Spider(Spider): + + def getName(self): + return "电影猎手" + + def init(self, extend=""): + self.device = self.device_id() + self.host = self.gethost() + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def action(self, action): + pass + + def destroy(self): + pass + + t = str(int(time.time())) + + def homeContent(self, filter): + result = {} + filters = {} + classes = [] + bba = self.url() + data = self.fetch(f"{self.host}/api/v1/app/config?pack={bba[0]}&signature={bba[1]}", headers=self.header()).text + data1 = self.aes(data) + dy = {"class":"类型","area":"地区","lang":"语言","year":"年份","letter":"字母","by":"排序","sort":"排序"} + data1['data']['movie_screen']['sort'].pop(0) + for item in data1['data']['movie_screen']['sort']: + item['n'] = item.pop('name') + item['v'] = item.pop('value') + for item in data1['data']['movie_screen']['filter']: + has_non_empty_field = False + classes.append({"type_name": item["name"], "type_id": str(item["id"])}) + for key in dy: + if key in item and item[key]: + has_non_empty_field = True + break + if has_non_empty_field: + filters[str(item["id"])] = [] + filters[str(item["id"])].append( + {"key": 'sort', "name": '排序', "value": data1['data']['movie_screen']['sort']}) + for dkey in item: + if dkey in dy and item[dkey]: + item[dkey].pop(0) + value_array = [ + {"n": value.strip(), "v": value.strip()} + for value in item[dkey] + if value.strip() != "" + ] + filters[str(item["id"])].append( + {"key": dkey, "name": dy[dkey], "value": value_array} + ) + result["class"] = classes + result["filters"] = filters + return result + + def homeVideoContent(self): + bba = self.url() + url = f'{self.host}/api/v1/movie/index_recommend?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json() + videos = [] + for item in data['data']: + if len(item['list']) > 0: + for it in item['list']: + try: + videos.append(self.voides(it)) + except Exception as e: + continue + result = {"list": videos} + return result + + def categoryContent(self, tid, pg, filter, extend): + body = {"type_id": tid, "sort": extend.get("sort", "by_default"), "class": extend.get("class", "类型"), + "area": extend.get("area", "地区"), "year": extend.get("year", "年份"), "page": str(pg), + "pageSize": "21"} + result = {} + list = [] + bba = self.url(body) + url = f"{self.host}/api/v1/movie/screen/list?pack={bba[0]}&signature={bba[1]}" + data = self.fetch(url, headers=self.header()).json()['data']['list'] + for item in data: + list.append(self.voides(item)) + result["list"] = list + result["page"] = pg + result["pagecount"] = 9999 + result["limit"] = 90 + result["total"] = 999999 + return result + + def detailContent(self, ids): + body = {"id": ids[0]} + bba = self.url(body) + url = f'{self.host}/api/v1/movie/detail?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json()['data'] + video = {'vod_name': data.get('name'),'type_name': data.get('type_name'),'vod_year': data.get('year'),'vod_area': data.get('area'),'vod_remarks': data.get('dynami'),'vod_content': data.get('content')} + play = [] + names = [] + tasks = [] + for itt in data["play_from"]: + name = itt["name"] + a = [] + if len(itt["list"]) > 0: + names.append(name) + play.append(self.playeach(itt['list'])) + else: + tasks.append({"movie_id": ids[0], "from_code": itt["code"]}) + names.append(name) + if tasks: + with ThreadPoolExecutor(max_workers=len(tasks)) as executor: + results = executor.map(self.playlist, tasks) + for result in results: + if result: + play.append(result) + else: + play.append("") + video["vod_play_from"] = "$$$".join(names) + video["vod_play_url"] = "$$$".join(play) + result = {"list": [video]} + return result + + def searchContent(self, key, quick, pg=1): + body = {"keyword": key, "sort": "", "type_id": "0", "page": str(pg), "pageSize": "10", + "res_type": "by_movie_name"} + bba = self.url(body) + url = f"{self.host}/api/v1/movie/search?pack={bba[0]}&signature={bba[1]}" + data = self.fetch(url, headers=self.header()).json()['data'].get('list') + videos = [] + for it in data: + try: + videos.append(self.voides(it)) + except Exception as e: + continue + result = {"list": videos, "page": pg} + return result + + def playerContent(self, flag, id, vipFlags): + url = id + if "m3u8" not in url and "mp4" not in url: + try: + add = id.split('|||') + data = {"from_code": add[0], "play_url": add[1], "episode_id": add[2], "type": "play"} + bba = self.url(data) + data2 = self.fetch(f"{self.host}/api/v1/movie_addr/parse_url?pack={bba[0]}&signature={bba[1]}", + headers=self.header()).json()['data'] + url = data2.get('play_url') or data2.get('download_url') + try: + url1 = self.fetch(url, headers=self.header(), allow_redirects=False).headers['Location'] + if url1 and "http" in url1: + url = url1 + except: + pass + except Exception as e: + pass + if '.jpg' in url or '.jpeg' in url or '.png' in url: + url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8" + result = {} + result["parse"] = 0 + result["url"] = url + result["header"] = {'user-agent': 'okhttp/4.9.2'} + return result + + def localProxy(self, param): + url = b64decode(param["url"]).decode('utf-8') + durl = url[:url.rfind('/')] + data = self.fetch(url, headers=self.header()).content.decode("utf-8") + lines = data.strip().split('\n') + for index, string in enumerate(lines): + # if 'URI="' in string and 'http' not in string: + # lines[index] = index + # 暂时预留,貌似用不到 + if '#EXT' not in string and 'http' not in string: + lines[index] = durl + ('' if string.startswith('/') else '/') + string + data = '\n'.join(lines) + return [200, "application/vnd.apple.mpegur", data] + + def device_id(self): + characters = string.ascii_lowercase + string.digits + random_string = ''.join(random.choices(characters, k=32)) + return random_string + + def gethost(self): + headers = { + 'User-Agent': 'okhttp/4.9.2', + 'Connection': 'Keep-Alive', + } + response = self.fetch('https://app-site.ecoliving168.com/domain_v5.json', headers=headers).json() + url = response['api_service'].replace('/api/', '') + return url + + def header(self): + headers = { + 'User-Agent': 'Android', + 'Accept': 'application/prs.55App.v2+json', + 'timestamp': self.t, + 'x-client-setting': '{"pure-mode":1}', + 'x-client-uuid': '{"device_id":' + self.device + '}, "type":1,"brand":"Redmi", "model":"M2012K10C", "system_version":30, "sdk_version":"3.1.0.7"}', + 'x-client-version': '3096 ' + } + return headers + + def url(self, id=None): + if not id: + id = {} + id["timestamp"] = self.t + public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02F/kPg5A2NX4qZ5JSns+bjhVMCC6JbTiTKpbgNgiXU+Kkorg6Dj76gS68gB8llhbUKCXjIdygnHPrxVHWfzmzisq9P9awmXBkCk74Skglx2LKHa/mNz9ivg6YzQ5pQFUEWS0DfomGBXVtqvBlOXMCRxp69oWaMsnfjnBV+0J7vHbXzUIkqBLdXSNfM9Ag5qdRDrJC3CqB65EJ3ARWVzZTTcXSdMW9i3qzEZPawPNPe5yPYbMZIoXLcrqvEZnRK1oak67/ihf7iwPJqdc+68ZYEmmdqwunOvRdjq89fQMVelmqcRD9RYe08v+xDxG9Co9z7hcXGTsUquMxkh29uNawIDAQAB' + encrypted_text = json.dumps(id) + public_key = RSA.import_key(b64decode(public_key)) + cipher = PKCS1_v1_5.new(public_key) + encrypted_message = cipher.encrypt(encrypted_text.encode('utf-8')) + encrypted_message_base64 = b64encode(encrypted_message).decode('utf-8') + result = encrypted_message_base64.replace('+', '-').replace('/', '_').replace('=', '') + key = '635a580fcb5dc6e60caa39c31a7bde48' + sign = hmac.new(key.encode(), result.encode(), hashlib.md5).hexdigest() + return result, sign + + def playlist(self, body): + try: + bba = self.url(body) + url = f'{self.host}/api/v1/movie_addr/list?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json()['data'] + return self.playeach(data) + except Exception: + return [] + + def playeach(self,data): + play_urls = [] + for it in data: + if re.search(r"mp4|m3u8", it["play_url"]): + play_urls.append(f"{it['episode_name']}${it['play_url']}") + else: + play_urls.append( + f"{it['episode_name']}${it['from_code']}|||{it['play_url']}|||{it['episode_id']}" + ) + return '#'.join(play_urls) + + def voides(self, item): + if item['name'] or item['title']: + voide = { + "vod_id": item.get('id') or item.get('click'), + 'vod_name': item.get('name') or item.get('title'), + 'vod_pic': item.get('cover') or item.get('image'), + 'vod_year': item.get('year') or item.get('label'), + 'vod_remarks': item.get('dynamic') or item.get('sub_title') + } + return voide + + def aes(self, text): + text = text.replace('-', '+').replace('_', '/') + '==' + key = b"e6d5de5fcc51f53d" + iv = b"2f13eef7dfc6c613" + cipher = AES.new(key, AES.MODE_CBC, iv) + pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size).decode("utf-8") + return json.loads(pt) diff --git a/lrzy/py/甜圈短剧.py b/lrzy/py/甜圈短剧.py new file mode 100644 index 0000000..9d1ca26 --- /dev/null +++ b/lrzy/py/甜圈短剧.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- +# by @嗷呜 +import sys +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + + def init(self, extend=""): + pass + + def getName(self): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def destroy(self): + pass + + ahost='https://api.cenguigui.cn' + + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'sec-ch-ua-platform': '"macOS"', + 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="134", "Google Chrome";v="134"', + 'DNT': '1', + 'sec-ch-ua-mobile': '?0', + 'Sec-Fetch-Site': 'cross-site', + 'Sec-Fetch-Mode': 'no-cors', + 'Sec-Fetch-Dest': 'video', + 'Sec-Fetch-Storage-Access': 'active', + 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', + } + + def homeContent(self, filter): + result = {'class': [{'type_id': '推荐榜', 'type_name': '🔥 推荐榜'}, + {'type_id': '新剧', 'type_name': '🎬 新剧'}, + {'type_id': '逆袭', 'type_name': '🎬 逆袭'}, + {'type_id': '霸总', 'type_name': '🎬 霸总'}, + {'type_id': '现代言情', 'type_name': '🎬 现代言情'}, + {'type_id': '打脸虐渣', 'type_name': '🎬 打脸虐渣'}, + {'type_id': '豪门恩怨', 'type_name': '🎬 豪门恩怨'}, + {'type_id': '神豪', 'type_name': '🎬 神豪'}, + {'type_id': '马甲', 'type_name': '🎬 马甲'}, + {'type_id': '都市日常', 'type_name': '🎬 都市日常'}, + {'type_id': '战神归来', 'type_name': '🎬 战神归来'}, + {'type_id': '小人物', 'type_name': '🎬 小人物'}, + {'type_id': '女性成长', 'type_name': '🎬 女性成长'}, + {'type_id': '大女主', 'type_name': '🎬 大女主'}, + {'type_id': '穿越', 'type_name': '🎬 穿越'}, + {'type_id': '都市修仙', 'type_name': '🎬 都市修仙'}, + {'type_id': '强者回归', 'type_name': '🎬 强者回归'}, + {'type_id': '亲情', 'type_name': '🎬 亲情'}, + {'type_id': '古装', 'type_name': '🎬 古装'}, + {'type_id': '重生', 'type_name': '🎬 重生'}, + {'type_id': '闪婚', 'type_name': '🎬 闪婚'}, + {'type_id': '赘婿逆袭', 'type_name': '🎬 赘婿逆袭'}, + {'type_id': '虐恋', 'type_name': '🎬 虐恋'}, + {'type_id': '追妻', 'type_name': '🎬 追妻'}, + {'type_id': '天下无敌', 'type_name': '🎬 天下无敌'}, + {'type_id': '家庭伦理', 'type_name': '🎬 家庭伦理'}, + {'type_id': '萌宝', 'type_name': '🎬 萌宝'}, + {'type_id': '古风权谋', 'type_name': '🎬 古风权谋'}, + {'type_id': '职场', 'type_name': '🎬 职场'}, + {'type_id': '奇幻脑洞', 'type_name': '🎬 奇幻脑洞'}, + {'type_id': '异能', 'type_name': '🎬 异能'}, + {'type_id': '无敌神医', 'type_name': '🎬 无敌神医'}, + {'type_id': '古风言情', 'type_name': '🎬 古风言情'}, + {'type_id': '传承觉醒', 'type_name': '🎬 传承觉醒'}, + {'type_id': '现言甜宠', 'type_name': '🎬 现言甜宠'}, + {'type_id': '奇幻爱情', 'type_name': '🎬 奇幻爱情'}, + {'type_id': '乡村', 'type_name': '🎬 乡村'}, + {'type_id': '历史古代', 'type_name': '🎬 历史古代'}, + {'type_id': '王妃', 'type_name': '🎬 王妃'}, + {'type_id': '高手下山', 'type_name': '🎬 高手下山'}, + {'type_id': '娱乐圈', 'type_name': '🎬 娱乐圈'}, + {'type_id': '强强联合', 'type_name': '🎬 强强联合'}, + {'type_id': '破镜重圆', 'type_name': '🎬 破镜重圆'}, + {'type_id': '暗恋成真', 'type_name': '🎬 暗恋成真'}, + {'type_id': '民国', 'type_name': '🎬 民国'}, + {'type_id': '欢喜冤家', 'type_name': '🎬 欢喜冤家'}, + {'type_id': '系统', 'type_name': '🎬 系统'}, + {'type_id': '真假千金', 'type_name': '🎬 真假千金'}, + {'type_id': '龙王', 'type_name': '🎬 龙王'}, + {'type_id': '校园', 'type_name': '🎬 校园'}, + {'type_id': '穿书', 'type_name': '🎬 穿书'}, + {'type_id': '女帝', 'type_name': '🎬 女帝'}, + {'type_id': '团宠', 'type_name': '🎬 团宠'}, + {'type_id': '年代爱情', 'type_name': '🎬 年代爱情'}, + {'type_id': '玄幻仙侠', 'type_name': '🎬 玄幻仙侠'}, + {'type_id': '青梅竹马', 'type_name': '🎬 青梅竹马'}, + {'type_id': '悬疑推理', 'type_name': '🎬 悬疑推理'}, + {'type_id': '皇后', 'type_name': '🎬 皇后'}, + {'type_id': '替身', 'type_name': '🎬 替身'}, + {'type_id': '大叔', 'type_name': '🎬 大叔'}, + {'type_id': '喜剧', 'type_name': '🎬 喜剧'}, + {'type_id': '剧情', 'type_name': '🎬 剧情'}]} + return result + + def homeVideoContent(self): + pass + + def categoryContent(self, tid, pg, filter, extend): + params = { + 'classname': tid, + 'offset': str((int(pg) - 1)), + } + data = self.fetch(f'{self.ahost}/api/duanju/api.php', params=params, headers=self.headers).json() + videos = [] + for k in data['data']: + videos.append({ + 'vod_id': k.get('book_id'), + 'vod_name': k.get('title'), + 'vod_pic': k.get('cover'), + 'vod_year': k.get('score'), + 'vod_remarks': f"{k.get('sub_title')}|{k.get('episode_cnt')}" + }) + result = {} + result['list'] = videos + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + v=self.fetch(f'{self.ahost}/api/duanju/api.php', params={'book_id': ids[0]}, headers=self.headers).json() + vod = { + 'type_name': v.get('category'), + 'vod_year': v.get('time'), + 'vod_remarks': v.get('duration'), + 'vod_content': v.get('desc'), + 'vod_play_from': '嗷呜爱看短剧', + 'vod_play_url': '#'.join([f"{i['title']}${i['video_id']}" for i in v['data']]) + } + return {'list':[vod]} + + def searchContent(self, key, quick, pg="1"): + return self.categoryContent(key, pg, True, {}) + + def playerContent(self, flag, id, vipFlags): + data=self.fetch(f'{self.ahost}/api/duanju/api.php', params={'video_id': id}, headers=self.headers).json() + return {'parse': 0, 'url': data['data']['url'], 'header': self.headers} + + def localProxy(self, param): + pass diff --git a/lrzy/py/电影云集[盘].py b/lrzy/py/电影云集[盘].py new file mode 100644 index 0000000..0a71253 --- /dev/null +++ b/lrzy/py/电影云集[盘].py @@ -0,0 +1,217 @@ +import sys +import json +import re +sys.path.append('..') +from base.spider import Spider + +class Spider(Spider): + def __init__(self): + self.name = "电影云集" + self.host = "https://dyyjpro.com" + self.timeout = 10000 + self.limit = 20 + self.headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" + } + self.default_image = "https://picsum.photos/300/400" + + def getName(self): + return self.name + + def init(self, extend=""): + print(f"============{extend}============") + + def homeContent(self, filter): + return { + 'class': [ + {"type_name": "电影", "type_id": "dianying"}, + {"type_name": "剧集", "type_id": "剧集"}, + {"type_name": "动漫", "type_id": "dongman"}, + {"type_name": "综艺", "type_id": "zongyi"}, + {"type_name": "短剧", "type_id": "短剧"}, + {"type_name": "学习", "type_id": "xuexi"}, + {"type_name": "读物", "type_id": "读物"}, + {"type_name": "音频", "type_id": "音频"} + ] + } + + def categoryContent(self, tid, pg, filter, extend): + result = {} + url = f"{self.host}/category/{tid}/" if pg == 1 else f"{self.host}/category/{tid}/page/{pg}/" + + try: + rsp = self.fetch(url, headers=self.headers, timeout=self.timeout) + if rsp: + videos = self._parse_video_list(rsp.text) + result.update({ + 'list': videos, + 'page': pg, + 'pagecount': 9999, + 'limit': self.limit, + 'total': 999999 + }) + except Exception as e: + print(f"Category parse error: {e}") + + return result + + def _parse_video_list(self, html_text): + videos = [] + + def build_full_url(href): + if href.startswith("http"): + return href + return f"{self.host}{href}" if href.startswith("/") else f"{self.host}/{href}" + + try: + pattern = r']*class="[^"]*post-item[^"]*"[^>]*>(.*?)' + for match in re.finditer(pattern, html_text, re.S): + item_html = match.group(1) + href_match = re.search(r']*href="([^"]*)"[^>]*>', item_html, re.S) + if not href_match: + continue + href = href_match.group(1) + title_match = re.search(r']*title="([^"]*)"', item_html, re.S) + title = title_match.group(1).strip() if title_match else "" + + if not title: + h2_match = re.search(r']*>(.*?)', item_html, re.S) + if h2_match: + title = re.sub(r'<[^>]+>', '', h2_match.group(1)).strip() + + if not href or not title: + continue + img_match = re.search(r']*src="([^"]*)"[^>]*>', item_html, re.S) + if not img_match: + img_match = re.search(r'data-bg="([^"]*)"', item_html, re.S) + + img_url = img_match.group(1) if img_match else self.default_image + + videos.append({ + "vod_id": build_full_url(href), + "vod_name": title, + "vod_pic": build_full_url(img_url) if img_url.startswith("/") else img_url, + "vod_remarks": "", + "vod_content": title + }) + except Exception as e: + print(f"Parse video list error: {e}") + return videos[:self.limit] + + def detailContent(self, array): + result = {'list': []} + if array: + try: + vod_id = array[0] + detail_url = vod_id if vod_id.startswith("http") else f"{self.host}{vod_id}" + rsp = self.fetch(detail_url, headers=self.headers, timeout=self.timeout) + if rsp: + vod = self._parse_detail_page(rsp.text, detail_url) + if vod: + result['list'] = [vod] + except Exception as e: + print(f"Detail parse error: {e}") + return result + + def _parse_detail_page(self, html_text, detail_url): + try: + title_match = re.search(r']*>(.*?)', html_text, re.S) + title = title_match.group(1).strip() if title_match else "未知标题" + title = re.sub(r'<[^>]+>', '', title).strip() + content_match = re.search(r']*class="[^"]*post-content[^"]*"[^>]*>.*?

(.*?)

', html_text, re.S) + content = content_match.group(1).strip() if content_match else title + img_match = re.search(r']*property="og:image"[^>]*content="([^"]*)"', html_text, re.S) + if not img_match: + img_match = re.search(r']*class="[^"]*wp-post-image[^"]*"[^>]*src="([^"]*)"', html_text, re.S) + img_url = img_match.group(1) if img_match else self.default_image + if img_url and not img_url.startswith("http"): + img_url = f"{self.host}{img_url}" if img_url.startswith("/") else f"{self.host}/{img_url}" + pan_links = [] + link_pattern = r']*href="([^"]*)"[^>]*>.*?
' + for match in re.finditer(link_pattern, html_text, re.S): + href = match.group(1) + if href and ("pan.baidu.com" in href or "pan.quark.cn" in href): + pan_links.append(href) + play_from = [] + play_url = [] + baidu_links = [link for link in pan_links if "pan.baidu.com" in link] + quark_links = [link for link in pan_links if "pan.quark.cn" in link] + all_links = [] + if baidu_links: + all_links.extend([f"百度网盘${link}" for link in baidu_links]) + if quark_links: + all_links.extend([f"夸克网盘${link}" for link in quark_links]) + if all_links: + play_from.append("电影云集") + play_url.append("#".join(all_links)) + else: + play_from = ["无资源"] + play_url = ["暂无资源$#"] + + return { + "vod_id": detail_url, + "vod_name": title, + "vod_pic": img_url, + "vod_content": content, + "vod_remarks": f"共{len(pan_links)}个网盘源" if pan_links else "暂无网盘资源", + "vod_play_from": "$$$".join(play_from), + "vod_play_url": "$$$".join(play_url) + } + except Exception as e: + print(f"Parse detail page error: {e}") + return { + "vod_id": detail_url, + "vod_name": "未知标题", + "vod_pic": self.default_image, + "vod_content": f"加载详情页失败:{str(e)}", + "vod_remarks": "", + "vod_play_from": "无资源", + "vod_play_url": "暂无资源$#" + } + + def searchContent(self, key, quick, pg): + result = {'list': []} + try: + encoded_key = key.replace(" ", "+") + url = f"{self.host}/?cat=&s={encoded_key}" if pg == 1 else f"{self.host}/page/{pg}?cat=&s={encoded_key}" + rsp = self.fetch(url, headers=self.headers, timeout=self.timeout) + if rsp: + result['list'] = self._parse_video_list(rsp.text) + except Exception as e: + print(f"Search error: {e}") + return result + + def playerContent(self, flag, id, vipFlags): + if id.startswith("http"): + return { + "parse": 0, + "playUrl": "", + "url": f"push://{id}", + "header": json.dumps(self.headers) + } + return { + "parse": 0, + "playUrl": "", + "url": id, + "header": json.dumps(self.headers) + } + + def homeVideoContent(self): + return { + 'list': [] + } + + def isVideoFormat(self, url): + video_formats = ['.mp4', '.m3u8', '.flv', '.avi', '.mkv', '.wmv', '.rmvb', '.mov'] + return any(url.lower().endswith(fmt) for fmt in video_formats) + + def localProxy(self, url, param): + return { + "parse": 0, + "playUrl": "", + "url": url, + "header": "" + } + + def manualVideoCheck(self, url): + return True diff --git a/lrzy/py/电影猎手.py b/lrzy/py/电影猎手.py new file mode 100644 index 0000000..1a6a4d7 --- /dev/null +++ b/lrzy/py/电影猎手.py @@ -0,0 +1,279 @@ +# coding=utf-8 +# !/usr/bin/python +# by嗷呜(finally) +import sys +import os +sys.path.append("..") +import re +import hashlib +import hmac +import random +import string +from Crypto.Util.Padding import unpad +from concurrent.futures import ThreadPoolExecutor +from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_v1_5, AES +from base64 import b64encode, b64decode +import json +import time +from base.spider import Spider + +class Spider(Spider): + + def getName(self): + return "电影猎手" + + def init(self, extend=""): + self.device = self.device_id() + self.host = self.gethost() + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def action(self, action): + pass + + def destroy(self): + pass + + t = str(int(time.time())) + + def homeContent(self, filter): + result = {} + filters = {} + classes = [] + bba = self.url() + data = self.fetch(f"{self.host}/api/v1/app/config?pack={bba[0]}&signature={bba[1]}", headers=self.header()).text + data1 = self.aes(data) + dy = {"class":"类型","area":"地区","lang":"语言","year":"年份","letter":"字母","by":"排序","sort":"排序"} + data1['data']['movie_screen']['sort'].pop(0) + for item in data1['data']['movie_screen']['sort']: + item['n'] = item.pop('name') + item['v'] = item.pop('value') + for item in data1['data']['movie_screen']['filter']: + has_non_empty_field = False + classes.append({"type_name": item["name"], "type_id": str(item["id"])}) + for key in dy: + if key in item and item[key]: + has_non_empty_field = True + break + if has_non_empty_field: + filters[str(item["id"])] = [] + filters[str(item["id"])].append( + {"key": 'sort', "name": '排序', "value": data1['data']['movie_screen']['sort']}) + for dkey in item: + if dkey in dy and item[dkey]: + item[dkey].pop(0) + value_array = [ + {"n": value.strip(), "v": value.strip()} + for value in item[dkey] + if value.strip() != "" + ] + filters[str(item["id"])].append( + {"key": dkey, "name": dy[dkey], "value": value_array} + ) + result["class"] = classes + result["filters"] = filters + return result + + def homeVideoContent(self): + bba = self.url() + url = f'{self.host}/api/v1/movie/index_recommend?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json() + videos = [] + for item in data['data']: + if len(item['list']) > 0: + for it in item['list']: + try: + videos.append(self.voides(it)) + except Exception as e: + continue + result = {"list": videos} + return result + + def categoryContent(self, tid, pg, filter, extend): + body = {"type_id": tid, "sort": extend.get("sort", "by_default"), "class": extend.get("class", "类型"), + "area": extend.get("area", "地区"), "year": extend.get("year", "年份"), "page": str(pg), + "pageSize": "21"} + result = {} + list = [] + bba = self.url(body) + url = f"{self.host}/api/v1/movie/screen/list?pack={bba[0]}&signature={bba[1]}" + data = self.fetch(url, headers=self.header()).json()['data']['list'] + for item in data: + list.append(self.voides(item)) + result["list"] = list + result["page"] = pg + result["pagecount"] = 9999 + result["limit"] = 90 + result["total"] = 999999 + return result + + def detailContent(self, ids): + body = {"id": ids[0]} + bba = self.url(body) + url = f'{self.host}/api/v1/movie/detail?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json()['data'] + video = {'vod_name': data.get('name'),'type_name': data.get('type_name'),'vod_year': data.get('year'),'vod_area': data.get('area'),'vod_remarks': data.get('dynami'),'vod_content': data.get('content')} + play = [] + names = [] + tasks = [] + for itt in data["play_from"]: + name = itt["name"] + a = [] + if len(itt["list"]) > 0: + names.append(name) + play.append(self.playeach(itt['list'])) + else: + tasks.append({"movie_id": ids[0], "from_code": itt["code"]}) + names.append(name) + if tasks: + with ThreadPoolExecutor(max_workers=len(tasks)) as executor: + results = executor.map(self.playlist, tasks) + for result in results: + if result: + play.append(result) + else: + play.append("") + video["vod_play_from"] = "$$$".join(names) + video["vod_play_url"] = "$$$".join(play) + result = {"list": [video]} + return result + + def searchContent(self, key, quick, pg=1): + body = {"keyword": key, "sort": "", "type_id": "0", "page": str(pg), "pageSize": "10", + "res_type": "by_movie_name"} + bba = self.url(body) + url = f"{self.host}/api/v1/movie/search?pack={bba[0]}&signature={bba[1]}" + data = self.fetch(url, headers=self.header()).json()['data'].get('list') + videos = [] + for it in data: + try: + videos.append(self.voides(it)) + except Exception as e: + continue + result = {"list": videos, "page": pg} + return result + + def playerContent(self, flag, id, vipFlags): + url = id + if "m3u8" not in url and "mp4" not in url: + try: + add = id.split('|||') + data = {"from_code": add[0], "play_url": add[1], "episode_id": add[2], "type": "play"} + bba = self.url(data) + data2 = self.fetch(f"{self.host}/api/v1/movie_addr/parse_url?pack={bba[0]}&signature={bba[1]}", + headers=self.header()).json()['data'] + url = data2.get('play_url') or data2.get('download_url') + try: + url1 = self.fetch(url, headers=self.header(), allow_redirects=False).headers['Location'] + if url1 and "http" in url1: + url = url1 + except: + pass + except Exception as e: + pass + if '.jpg' in url or '.jpeg' in url or '.png' in url: + url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8" + result = {} + result["parse"] = 0 + result["url"] = url + result["header"] = {'user-agent': 'okhttp/4.9.2'} + return result + + def localProxy(self, param): + url = b64decode(param["url"]).decode('utf-8') + durl = url[:url.rfind('/')] + data = self.fetch(url, headers=self.header()).content.decode("utf-8") + lines = data.strip().split('\n') + for index, string in enumerate(lines): + # if 'URI="' in string and 'http' not in string: + # lines[index] = index + # 暂时预留,貌似用不到 + if '#EXT' not in string and 'http' not in string: + lines[index] = durl + ('' if string.startswith('/') else '/') + string + data = '\n'.join(lines) + return [200, "application/vnd.apple.mpegur", data] + + def device_id(self): + characters = string.ascii_lowercase + string.digits + random_string = ''.join(random.choices(characters, k=32)) + return random_string + + def gethost(self): + headers = { + 'User-Agent': 'okhttp/4.9.2', + 'Connection': 'Keep-Alive', + } + response = self.fetch('https://app-site.ecoliving168.com/domain_v5.json', headers=headers).json() + url = response['api_service'].replace('/api/', '') + return url + + def header(self): + headers = { + 'User-Agent': 'Android', + 'Accept': 'application/prs.55App.v2+json', + 'timestamp': self.t, + 'x-client-setting': '{"pure-mode":1}', + 'x-client-uuid': '{"device_id":' + self.device + '}, "type":1,"brand":"Redmi", "model":"M2012K10C", "system_version":30, "sdk_version":"3.1.0.7"}', + 'x-client-version': '3096 ' + } + return headers + + def url(self, id=None): + if not id: + id = {} + id["timestamp"] = self.t + public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02F/kPg5A2NX4qZ5JSns+bjhVMCC6JbTiTKpbgNgiXU+Kkorg6Dj76gS68gB8llhbUKCXjIdygnHPrxVHWfzmzisq9P9awmXBkCk74Skglx2LKHa/mNz9ivg6YzQ5pQFUEWS0DfomGBXVtqvBlOXMCRxp69oWaMsnfjnBV+0J7vHbXzUIkqBLdXSNfM9Ag5qdRDrJC3CqB65EJ3ARWVzZTTcXSdMW9i3qzEZPawPNPe5yPYbMZIoXLcrqvEZnRK1oak67/ihf7iwPJqdc+68ZYEmmdqwunOvRdjq89fQMVelmqcRD9RYe08v+xDxG9Co9z7hcXGTsUquMxkh29uNawIDAQAB' + encrypted_text = json.dumps(id) + public_key = RSA.import_key(b64decode(public_key)) + cipher = PKCS1_v1_5.new(public_key) + encrypted_message = cipher.encrypt(encrypted_text.encode('utf-8')) + encrypted_message_base64 = b64encode(encrypted_message).decode('utf-8') + result = encrypted_message_base64.replace('+', '-').replace('/', '_').replace('=', '') + key = '635a580fcb5dc6e60caa39c31a7bde48' + sign = hmac.new(key.encode(), result.encode(), hashlib.md5).hexdigest() + return result, sign + + def playlist(self, body): + try: + bba = self.url(body) + url = f'{self.host}/api/v1/movie_addr/list?pack={bba[0]}&signature={bba[1]}' + data = self.fetch(url, headers=self.header()).json()['data'] + return self.playeach(data) + except Exception: + return [] + + def playeach(self,data): + play_urls = [] + for it in data: + if re.search(r"mp4|m3u8", it["play_url"]): + play_urls.append(f"{it['episode_name']}${it['play_url']}") + else: + play_urls.append( + f"{it['episode_name']}${it['from_code']}|||{it['play_url']}|||{it['episode_id']}" + ) + return '#'.join(play_urls) + + def voides(self, item): + if item['name'] or item['title']: + voide = { + "vod_id": item.get('id') or item.get('click'), + 'vod_name': item.get('name') or item.get('title'), + 'vod_pic': item.get('cover') or item.get('image'), + 'vod_year': item.get('year') or item.get('label'), + 'vod_remarks': item.get('dynamic') or item.get('sub_title') + } + return voide + + def aes(self, text): + text = text.replace('-', '+').replace('_', '/') + '==' + key = b"e6d5de5fcc51f53d" + iv = b"2f13eef7dfc6c613" + cipher = AES.new(key, AES.MODE_CBC, iv) + pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size).decode("utf-8") + return json.loads(pt) diff --git a/lrzy/py/界影视.py b/lrzy/py/界影视.py new file mode 100644 index 0000000..e4820bf --- /dev/null +++ b/lrzy/py/界影视.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- +# @Author : Doubebly +# @Time : 2025/1/21 23:07 + +import hashlib +import re +import sys +import time +import requests +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + def getName(self): + return "JieYingShi" + + def init(self, extend): + self.home_url = 'https://www.hkybqufgh.com' + self.error_url = 'https://json.doube.eu.org/error/4gtv/index.m3u8' + self.headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", + } + + def getDependence(self): + return [] + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def homeContent(self, filter): + + return {'class': [ + { + 'type_id': '1', + 'type_name': '电影' + }, + { + 'type_id': '2', + 'type_name': '电视剧' + }, + { + 'type_id': '4', + 'type_name': '动漫' + }, + { + 'type_id': '3', + 'type_name': '综艺' + } + ]} + + def homeVideoContent(self): + a = self.get_data(self.home_url) + return {'list': a, 'parse': 0, 'jx': 0} + + def categoryContent(self, cid, page, filter, ext): + url = self.home_url + f'/vod/show/id/{cid}/page/{page}' + data = self.get_data(url) + return {'list': data, 'parse': 0, 'jx': 0} + + + def detailContent(self, did): + ids = did[0] + data = self.get_detail_data(ids) + return {"list": data, 'parse': 0, 'jx': 0} + + def searchContent(self, key, quick, page='1'): + if int(page) > 1: + return {'list': [], 'parse': 0, 'jx': 0} + url = self.home_url + f'/vod/search/{key}' + data = self.get_data(url) + return {'list': data, 'parse': 0, 'jx': 0} + + def playerContent(self, flag, pid, vipFlags): + url = self.get_play_data(pid) + return {"url": url, "header": self.headers, "parse": 1, "jx": 0} + + def localProxy(self, params): + pass + + def destroy(self): + return '正在Destroy' + + + def get_data(self, url): + data = [] + try: + res = requests.get(url, headers=self.headers) + if res.status_code != 200: + return data + vod_id_s = re.findall(r'\\"vodId\\":(.*?),', res.text) + vod_name_s = re.findall(r'\\"vodName\\":\\"(.*?)\\"', res.text) + vod_pic_s = re.findall(r'\\"vodPic\\":\\"(.*?)\\"', res.text) + vod_remarks_s = re.findall(r'\\"vodRemarks\\":\\"(.*?)\\"', res.text) + + for i in range(len(vod_id_s)): + data.append( + { + 'vod_id': vod_id_s[i], + 'vod_name': vod_name_s[i], + 'vod_pic': vod_pic_s[i], + 'vod_remarks': vod_remarks_s[i], + } + ) + except requests.RequestException as e: + print(e) + return data + + def get_detail_data(self, ids): + url = self.home_url + f'/api/mw-movie/anonymous/video/detail?id={ids}' + t = str(int(time.time() * 1000)) + headers = self.get_headers(t, f'id={ids}&key=cb808529bae6b6be45ecfab29a4889bc&t={t}') + try: + res = requests.get(url, headers=headers) + if res.status_code != 200: + return [] + i = res.json()['data'] + urls = [] + for ii in res.json()['data']['episodeList']: + name = ii['name'] + url = ii['nid'] + urls.append(f'{name}${ids}-{url}') + data = { + 'type_name': i['vodClass'], + 'vod_id': i['vodId'], + 'vod_name': i['vodName'], + 'vod_remarks': i['vodRemarks'], + 'vod_year': i['vodYear'], + 'vod_area': i['vodArea'], + 'vod_actor': i['vodActor'], + 'vod_director': i['vodDirector'], + 'vod_content': i['vodContent'], + 'vod_play_from': '默认', + 'vod_play_url': '#'.join(urls), + + } + return [data] + + except requests.RequestException as e: + print(e) + return [] + + def get_play_data(self, play): + info = play.split('-') + _id = info[0] + _pid = info[1] + url = self.home_url + f'/api/mw-movie/anonymous/v2/video/episode/url?id={_id}&nid={_pid}' + t = str(int(time.time() * 1000)) + headers = self.get_headers(t, f'id={_id}&nid={_pid}&key=cb808529bae6b6be45ecfab29a4889bc&t={t}') + try: + res = requests.get(url, headers=headers) + if res.status_code != 200: + return self.error_url + return res.json()['data']['list'][0]['url'] + except requests.RequestException as e: + print(e) + return self.error_url + + @staticmethod + def get_headers(t, e): + sign = hashlib.sha1(hashlib.md5(e.encode()).hexdigest().encode()).hexdigest() + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', + 'Accept': 'application/json, text/plain, */*', + 'sign': sign, + 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"', + 't': t, + 'referer': 'https://www.hkybqufgh.com/', + } + return headers + +if __name__ == '__main__': + pass + + + + diff --git a/lrzy/py/金牌.py b/lrzy/py/金牌.py new file mode 100644 index 0000000..7c623ef --- /dev/null +++ b/lrzy/py/金牌.py @@ -0,0 +1,463 @@ +# -*- coding: utf-8 -*- +# @Author : Doubebly +# @Time : 2025/5/29 22:07 + + +import sys +import hashlib +import time +import requests +import re +import json +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + def getName(self): + return "Aidianying" + + def init(self, extend): + self.home_url = 'https://m.sdzhgt.com/' + self.ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" + self.error_url = "https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4" + + def getDependence(self): + return [] + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def homeContent(self, filter): + return { + 'class': [{'type_id': '1', 'type_name': '电影'}, + {'type_id': '2', 'type_name': '电视剧'}, + {'type_id': '3', 'type_name': '综艺'}, + {'type_id': '4', 'type_name': '动漫'}], + 'filters': { + '1': [ + {'key': 'type', + 'name': '类型', + 'value': [{'n': '全部', 'v': ''}, + {'n': '喜剧', 'v': '/type/22'}, + {'n': '动作', 'v': '/type/23'}, + {'n': '科幻', 'v': '/type/30'}, + {'n': '爱情', 'v': '/type/26'}, + {'n': '悬疑', 'v': '/type/27'}, + {'n': '奇幻', 'v': '/type/87'}, + {'n': '剧情', 'v': '/type/37'}, + {'n': '恐怖', 'v': '/type/36'}, + {'n': '犯罪', 'v': '/type/35'}, + {'n': '动画', 'v': '/type/33'}, + {'n': '惊悚', 'v': '/type/34'}, + {'n': '战争', 'v': '/type/25'}, + {'n': '冒险', 'v': '/type/31'}, + {'n': '灾难', 'v': '/type/81'}, + {'n': '伦理', 'v': '/type/83'}, + {'n': '其他', 'v': '/type/43'}]}, + {'key': 'area', + 'name': '地区', + 'value': [{'n': '全部', 'v': ''}, + {'n': '中国大陆', 'v': '/area/中国大陆'}, + {'n': '中国香港', 'v': '/area/中国香港'}, + {'n': '中国台湾', 'v': '/area/中国台湾'}, + {'n': '美国', 'v': '/area/美国'}, + {'n': '日本', 'v': '/area/日本'}, + {'n': '韩国', 'v': '/area/韩国'}, + {'n': '印度', 'v': '/area/印度'}, + {'n': '泰国', 'v': '/area/泰国'}, + {'n': '其他', 'v': '/area/其他'}]}, + {'key': 'year', + 'name': '年份', + 'value': [{'n': '全部', 'v': ''}, + {'n': '2024', 'v': '/year/2024'}, + {'n': '2023', 'v': '/year/2023'}, + {'n': '2022', 'v': '/year/2022'}, + {'n': '2021', 'v': '/year/2021'}, + {'n': '2020', 'v': '/year/2020'}, + {'n': '2019', 'v': '/year/2019'}, + {'n': '2018', 'v': '/year/2018'}, + {'n': '2017', 'v': '/year/2017'}, + {'n': '2016', 'v': '/year/2016'}, + {'n': '2015', 'v': '/year/2015'}, + {'n': '2014', 'v': '/year/2014'}, + {'n': '2013', 'v': '/year/2013'}, + {'n': '2012', 'v': '/year/2012'}, + {'n': '2011', 'v': '/year/2011'}, + {'n': '2010', 'v': '/year/2010'}, + {'n': '2009~2000', 'v': '/year/2009~2000'}]}, + {'key': 'lang', + 'name': '语言', + 'value': [{'n': '全部', 'v': ''}, + {'n': '国语', 'v': '/lang/国语'}, + {'n': '英语', 'v': '/lang/英语'}, + {'n': '粤语', 'v': '/lang/粤语'}, + {'n': '韩语', 'v': '/lang/韩语'}, + {'n': '日语', 'v': '/lang/日语'}, + {'n': '其他', 'v': '/lang/其他'}]}, + {'key': 'by', + 'name': '排序', + 'value': [{'n': '上映时间', 'v': '/sortType/1/sortOrder/0'}, + {'n': '人气高低', 'v': '/sortType/3/sortOrder/0'}, + {'n': '评分高低', 'v': '/sortType/4/sortOrder/0'}]} + ], + '2': [ + {'key': 'type', + 'name': '类型', + 'value': [{'n': '全部', 'v': ''}, + {'n': '国产剧', 'v': '/type/14'}, + {'n': '欧美剧', 'v': '/type/15'}, + {'n': '港台剧', 'v': '/type/16'}, + {'n': '日韩剧', 'v': '/type/62'}, + {'n': '其他剧', 'v': '/type/68'}]}, + {'key': 'class', + 'name': '剧情', + 'value': [{'n': '全部', 'v': ''}, + {'n': '古装', 'v': '/class/古装'}, + {'n': '战争', 'v': '/class/战争'}, + {'n': '喜剧', 'v': '/class/喜剧'}, + {'n': '家庭', 'v': '/class/家庭'}, + {'n': '犯罪', 'v': '/class/犯罪'}, + {'n': '动作', 'v': '/class/动作'}, + {'n': '奇幻', 'v': '/class/奇幻'}, + {'n': '剧情', 'v': '/class/剧情'}, + {'n': '历史', 'v': '/class/历史'}, + {'n': '短片', 'v': '/class/短片'}]}, + {'key': 'area', + 'name': '地区', + 'value': [{'n': '全部', 'v': ''}, + {'n': '中国大陆', 'v': '/area/中国大陆'}, + {'n': '中国香港', 'v': '/area/中国香港'}, + {'n': '中国台湾', 'v': '/area/中国台湾'}, + {'n': '日本', 'v': '/area/日本'}, + {'n': '韩国', 'v': '/area/韩国'}, + {'n': '美国', 'v': '/area/美国'}, + {'n': '泰国', 'v': '/area/泰国'}, + {'n': '其他', 'v': '/area/其他'}]}, + {'key': 'year', + 'name': '时间', + 'value': [{'n': '全部', 'v': ''}, + {'n': '2024', 'v': '/year/2024'}, + {'n': '2023', 'v': '/year/2023'}, + {'n': '2022', 'v': '/year/2022'}, + {'n': '2021', 'v': '/year/2021'}, + {'n': '2020', 'v': '/year/2020'}, + {'n': '2019', 'v': '/year/2019'}, + {'n': '2018', 'v': '/year/2018'}, + {'n': '2017', 'v': '/year/2017'}, + {'n': '2016', 'v': '/year/2016'}, + {'n': '2015', 'v': '/year/2015'}, + {'n': '2014', 'v': '/year/2014'}, + {'n': '2013', 'v': '/year/2013'}, + {'n': '2012', 'v': '/year/2012'}, + {'n': '2011', 'v': '/year/2011'}, + {'n': '2010', 'v': '/year/2010'}]}, + {'key': 'lang', + 'name': '语言', + 'value': [{'n': '全部', 'v': ''}, + {'n': '普通话', 'v': '/lang/普通话'}, + {'n': '英语', 'v': '/lang/英语'}, + {'n': '粤语', 'v': '/lang/粤语'}, + {'n': '韩语', 'v': '/lang/韩语'}, + {'n': '日语', 'v': '/lang/日语'}, + {'n': '泰语', 'v': '/lang/泰语'}, + {'n': '其他', 'v': '/lang/其他'}, ]}, + {'key': 'by', + 'name': '排序', + 'value': [{'n': '最近更新', 'v': '/sortType/1/sortOrder/0'}, + {'n': '添加时间', 'v': '/sortType/2/sortOrder/0'}, + {'n': '人气高低', 'v': '/sortType/3/sortOrder/0'}, + {'n': '评分高低', 'v': '/sortType/4/sortOrder/0'}]} + ], + '3': [ + {'key': 'type', + 'name': '类型', + 'value': [{'n': '全部', 'v': ''}, + {'n': '国产综艺', 'v': '/type/69'}, + {'n': '港台综艺', 'v': '/type/70'}, + {'n': '日韩综艺', 'v': '/type/72'}, + {'n': '欧美综艺', 'v': '/type/73'}]}, + {'key': 'class', + 'name': '剧情', + 'value': [{'n': '全部', 'v': ''}, + {'n': '真人秀', 'v': '/class/真人秀'}, + {'n': '音乐', 'v': '/class/音乐'}, + {'n': '脱口秀', 'v': '/class/脱口秀'}]}, + {'key': 'area', + 'name': '地区', + 'value': [{'n': '全部', 'v': ''}, + {'n': '中国大陆', 'v': '/area/中国大陆'}, + {'n': '中国香港', 'v': '/area/中国香港'}, + {'n': '中国台湾', 'v': '/area/中国台湾'}, + {'n': '日本', 'v': '/area/日本'}, + {'n': '韩国', 'v': '/area/韩国'}, + {'n': '美国', 'v': '/area/美国'}, + {'n': '其他', 'v': '/area/其他'}]}, + {'key': 'year', + 'name': '时间', + 'value': [{'n': '全部', 'v': ''}, + {'n': '2024', 'v': '/year/2024'}, + {'n': '2023', 'v': '/year/2023'}, + {'n': '2022', 'v': '/year/2022'}, + {'n': '2021', 'v': '/year/2021'}, + {'n': '2020', 'v': '/year/2020'}]}, + {'key': 'lang', + 'name': '语言', + 'value': [{'n': '全部', 'v': ''}, + {'n': '国语', 'v': '/lang/国语'}, + {'n': '英语', 'v': '/lang/英语'}, + {'n': '粤语', 'v': '/lang/粤语'}, + {'n': '韩语', 'v': '/lang/韩语'}, + {'n': '日语', 'v': '/lang/日语'}, + {'n': '其他', 'v': '/lang/其他'}, ]}, + {'key': 'by', + 'name': '排序', + 'value': [{'n': '最近更新', 'v': '/sortType/1/sortOrder/0'}, + {'n': '添加时间', 'v': '/sortType/2/sortOrder/0'}, + {'n': '人气高低', 'v': '/sortType/3/sortOrder/0'}, + {'n': '评分高低', 'v': '/sortType/4/sortOrder/0'}]} + ], + '4': [ + {'key': 'type', + 'name': '类型', + 'value': [{'n': '全部', 'v': ''}, + {'n': '国产动漫', 'v': '/type/75'}, + {'n': '日韩动漫', 'v': '/type/76'}, + {'n': '欧美动漫', 'v': '/type/77'}]}, + {'key': 'class', + 'name': '剧情', + 'value': [{'n': '全部', 'v': ''}, + {'n': '喜剧', 'v': '/class/喜剧'}, + {'n': '科幻', 'v': '/class/科幻'}, + {'n': '热血', 'v': '/class/热血'}, + {'n': '冒险', 'v': '/class/冒险'}, + {'n': '动作', 'v': '/class/动作'}, + {'n': '运动', 'v': '/class/运动'}, + {'n': '战争', 'v': '/class/战争'}, + {'n': '儿童', 'v': '/class/儿童'}]}, + {'key': 'area', + 'name': '地区', + 'value': [{'n': '全部', 'v': ''}, + {'n': '中国大陆', 'v': '/area/中国大陆'}, + {'n': '日本', 'v': '/area/日本'}, + {'n': '美国', 'v': '/area/美国'}, + {'n': '其他', 'v': '/area/其他'}]}, + {'key': 'year', + 'name': '时间', + 'value': [{'n': '全部', 'v': ''}, + {'n': '2024', 'v': '/year/2024'}, + {'n': '2023', 'v': '/year/2023'}, + {'n': '2022', 'v': '/year/2022'}, + {'n': '2021', 'v': '/year/2021'}, + {'n': '2020', 'v': '/year/2020'}, + {'n': '2019', 'v': '/year/2019'}, + {'n': '2018', 'v': '/year/2018'}, + {'n': '2017', 'v': '/year/2017'}, + {'n': '2016', 'v': '/year/2016'}, + {'n': '2015', 'v': '/year/2015'}, + {'n': '2014', 'v': '/year/2014'}, + {'n': '2013', 'v': '/year/2013'}, + {'n': '2012', 'v': '/year/2012'}, + {'n': '2011', 'v': '/year/2011'}, + {'n': '2010', 'v': '/year/2010'}]}, + {'key': 'lang', + 'name': '语言', + 'value': [{'n': '全部', 'v': ''}, + {'n': '国语', 'v': '/lang/国语'}, + {'n': '英语', 'v': '/lang/英语'}, + {'n': '日语', 'v': '/lang/日语'}, + {'n': '其他', 'v': '/lang/其他'}]}, + {'key': 'by', + 'name': '排序', + 'value': [{'n': '最近更新', 'v': '/sortType/1/sortOrder/0'}, + {'n': '添加时间', 'v': '/sortType/2/sortOrder/0'}, + {'n': '人气高低', 'v': '/sortType/3/sortOrder/0'}, + {'n': '评分高低', 'v': '/sortType/4/sortOrder/0'}]} + ] +} + } + + def homeVideoContent(self): + video_list = [] + t = str(int(time.time() * 1000)) + # t = '1723292093234' + data = f'key=cb808529bae6b6be45ecfab29a4889bc&t={t}' + data_md5 = hashlib.md5(data.encode()).hexdigest() + data_sha1 = hashlib.sha1(data_md5.encode()).hexdigest() + h = { + "User-Agent": self.ua, + 'referer': self.home_url, 't': t, 'sign': data_sha1} + try: + res = requests.get(f'{self.home_url}/api/mw-movie/anonymous/home/hotSearch', headers=h) + data_list = res.json()['data'] + for i in data_list: + video_list.append( + { + 'vod_id': i['vodId'], + 'vod_name': i['vodName'], + 'vod_pic': i['vodPic'], + 'vod_remarks': i['vodVersion'] if i['typeId1'] == 1 else i['vodRemarks'] + } + ) + except requests.RequestException as e: + return { + 'list': [], + 'parse': 0, + 'jx': 0 + } + + return { + 'list': video_list, + 'parse': 0, + 'jx': 0 + } + + def categoryContent(self, cid, page, filter, ext): + t = cid + _type = ext.get('type') if ext.get('type') else '' + __class = ext.get('class') if ext.get('class') else '' + _area = ext.get('area') if ext.get('area') else '' + _year = ext.get('year') if ext.get('year') else '' + _lang = ext.get('lang') if ext.get('lang') else '' + _by = ext.get('by') if ext.get('by') else '' + video_list = [] + h = { + "User-Agent": self.ua, + 'referer': self.home_url, + } + try: + res = requests.get( + f'{self.home_url}/vod/show/id/{t}{_type}{__class}{_area}{_year}{_lang}{_by}/page/{page}', + headers=h) + aa = re.findall(r'\\"list\\":(.*?)}}}]', res.text) + if not aa: + return {'list': [], 'parse': 0, 'jx': 0} + bb = aa[0].replace('\\"', '"') + data_list = json.loads(bb) + for i in data_list: + video_list.append( + { + 'vod_id': i['vodId'], + 'vod_name': i['vodName'], + 'vod_pic': i['vodPic'], + 'vod_remarks': i['vodVersion'] if i['typeId1'] == 1 else i['vodRemarks'] + } + ) + except requests.RequestException as e: + return {'list': [], 'msg': e} + return {'list': video_list, 'parse': 0, 'jx': 0} + + def detailContent(self, did): + ids = did[0] + video_list = [] + t = str(int(time.time() * 1000)) + # t = '1723292093234' + data = f'id={ids}&key=cb808529bae6b6be45ecfab29a4889bc&t={t}' + data_md5 = hashlib.md5(data.encode()).hexdigest() + data_sha1 = hashlib.sha1(data_md5.encode()).hexdigest() + h = { + "User-Agent": self.ua, + 'referer': self.home_url, + 't': t, 'sign': data_sha1 + } + try: + res = requests.get(f'{self.home_url}/api/mw-movie/anonymous/video/detail?id={ids}', headers=h) + data = res.json()['data'] + play_list = data['episodeList'] + vod_play_url = [] + for i in play_list: + name = i['name'] + url = ids + '/' + str(i['nid']) + vod_play_url.append(name + '$' + url) + + video_list.append( + { + 'type_name': data['typeName'], + 'vod_id': ids, + 'vod_name': data['vodName'], + 'vod_remarks': data['vodRemarks'], + 'vod_year': data['vodYear'], + 'vod_area': data['vodArea'], + 'vod_actor': data['vodActor'], + 'vod_director': data['vodDirector'], + 'vod_content': data['vodContent'], + 'vod_play_from': '老僧酿酒', + 'vod_play_url': '#'.join(vod_play_url) + + } + ) + except requests.RequestException as e: + return {'list': [], 'msg': e} + return {"list": video_list, 'parse': 0, 'jx': 0} + + def searchContent(self, key, quick, page='1'): + wd = key + video_list = [] + t = str(int(time.time() * 1000)) + data = f'keyword={wd}&pageNum={page}&pageSize=12&key=cb808529bae6b6be45ecfab29a4889bc&t={t}' + data_md5 = hashlib.md5(data.encode()).hexdigest() + data_sha1 = hashlib.sha1(data_md5.encode()).hexdigest() + h = { + "User-Agent": self.ua, + 'referer': self.home_url, + 't': t, 'sign': data_sha1 + } + try: + response = requests.get( + f'{self.home_url}/api/mw-movie/anonymous/video/searchByWord?keyword={wd}&pageNum={page}&pageSize=12', + headers=h, + ) + data_list = response.json()['data']['result']['list'] + for i in data_list: + video_list.append( + { + 'vod_id': i['vodId'], + 'vod_name': i['vodName'], + 'vod_pic': i['vodPic'], + 'vod_remarks': i['vodVersion'] if i['typeId1'] == 1 else i['vodRemarks'] + } + ) + except requests.RequestException as e: + return {'list': [], 'msg': e} + return {'list': video_list, 'parse': 0, 'jx': 0} + + def playerContent(self, flag, pid, vipFlags): + url = pid + play_url = self.error_url + data = url.split('/') + _id = data[0] + _nid = data[1] + t = str(int(time.time() * 1000)) + # t = '1723292093234' + data = f'id={_id}&nid={_nid}&key=cb808529bae6b6be45ecfab29a4889bc&t={t}' + data_md5 = hashlib.md5(data.encode()).hexdigest() + data_sha1 = hashlib.sha1(data_md5.encode()).hexdigest() + h = { + "User-Agent": self.ua, + 'referer': self.home_url, + 't': t, 'sign': data_sha1 + } + h2 = { + "User-Agent": self.ua, + } + try: + res = requests.get( + f'{self.home_url}/api/mw-movie/anonymous/v2/video/episode/url?id={_id}&nid={_nid}', + headers=h) + play_url = res.json()['data']['list'][0]['url'] + except requests.RequestException as e: + return {"url": play_url, "header": h2, "parse": 0, "jx": 0} + + return {"url": play_url, "header": h2, "parse": 0, "jx": 0} + + def localProxy(self, params): + pass + + def destroy(self): + return '正在Destroy' + +if __name__ == '__main__': + pass \ No newline at end of file diff --git a/lrzy/py/飞快TV.py b/lrzy/py/飞快TV.py new file mode 100644 index 0000000..8058cd1 --- /dev/null +++ b/lrzy/py/飞快TV.py @@ -0,0 +1,374 @@ +""" +@header({ + searchable: 1, + filterable: 1, + quickSearch: 1, + title: '飞快', + lang: 'hipy' +}) +""" + +import sys +import json +import re +import base64 +import datetime +from urllib.parse import quote_plus, unquote +from lxml import etree + +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + def getName(self): + return "飞快" + + def init(self, extend=""): + pass + + def homeContent(self, filter): + result = {} + cateManual = { + "电影": "1", + "剧集": "2", + "综艺": "3", + "动漫": "4" + } + classes = [{'type_name': k, 'type_id': v} for k, v in cateManual.items()] + result['class'] = classes + + return result + + def _parse_video_item(self, a_element): + """解析单个视频项的公共方法""" + try: + href = a_element.xpath('./@href')[0] if a_element.xpath('./@href') else '' + m = re.search(r'/voddetail/(\d+)\.html', href) + if not m: + return None + sid = m.group(1) + + title_nodes = (a_element.xpath('.//div[contains(@class, "module-poster-item-title")]//text()') or + a_element.xpath('.//div[contains(@class, "module-card-item-title")]/a//text()') or + a_element.xpath('./@title') or a_element.xpath('.//img/@alt')) + name = title_nodes[0].strip() if title_nodes else f"视频_{sid}" + + img = self._parse_image_url(a_element) + + remark_nodes = a_element.xpath('.//div[contains(@class, "module-item-note")]//text()') + remark = ''.join([x.strip() for x in remark_nodes if x.strip()]) if remark_nodes else "" + + return { + "vod_id": sid, + "vod_name": name, + "vod_pic": img, + "vod_remarks": remark + } + except Exception: + return None + + def _parse_image_url(self, element): + """解析图片URL的公共方法""" + img_nodes = (element.xpath('.//img[contains(@class, "lazy")]/@data-original[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') or + element.xpath('.//img[contains(@class, "lazy")]/@src[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') or + element.xpath('.//img/@data-original[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') or + element.xpath('.//img/@src[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]')) + + if img_nodes: + img = img_nodes[0] + if img.startswith('/'): + img = 'https://feikuai.tv' + img + return img + return '' + + def homeVideoContent(self): + recommend_list = [] + try: + url = "https://feikuai.tv/" + rsp = self.fetch(url, headers=self.header) + if not rsp or not rsp.text: + return {'list': recommend_list} + + root = self._parse_html(rsp) + if not root: + return {'list': recommend_list} + + recommend_links = root.xpath( + '//div[contains(@class, "module-focus")]//a[contains(@href, "/voddetail/")] | ' + '//div[contains(@class, "module-hot")]//a[contains(@href, "/voddetail/")] | ' + '//div[contains(@class, "module-recommend")]//a[contains(@href, "/voddetail/")] | ' + '//div[contains(@class, "module-items") and contains(@class, "module-poster-items")]//a[contains(@href, "/voddetail/")]' + ) + + seen = set() + for a in recommend_links: + video_item = self._parse_video_item(a) + if video_item and video_item["vod_id"] not in seen: + seen.add(video_item["vod_id"]) + recommend_list.append(video_item) + + recommend_list = recommend_list[:30] + except Exception: + pass + return {'list': recommend_list} + + def _parse_html(self, rsp): + try: + parser = etree.HTMLParser(encoding='utf-8', recover=True, remove_blank_text=True) + if hasattr(rsp, 'content'): + return etree.HTML(rsp.content, parser=parser) + return etree.HTML(rsp.text.encode('utf-8', errors='ignore'), parser=parser) + except Exception: + + return None + + def _build_vodshow_url(self, tid, pg, ext): + area = (ext.get('area') or ext.get('1') or '').strip() + cate = (ext.get('class') or ext.get('3') or '').strip() + year = (ext.get('year') or ext.get('11') or '').strip() + + enc_area = quote_plus(area) if area else '' + enc_cate = quote_plus(cate) if cate else '' + pg_str = '' if str(pg) in ('', '1') else str(pg) + return f'https://feikuai.tv/vodshow/{tid}-{enc_area}--{enc_cate}-----{pg_str}---{year}.html' + + def categoryContent(self, tid, pg, filter, extend): + if tid == '0': + return self.homeVideoContent() + + result = {'list': [], 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999} + try: + ext = json.loads(extend) if extend and isinstance(extend, str) else {} + url = self._build_vodshow_url(tid, pg, ext) + except Exception: + url = f'https://feikuai.tv/vodshow/{tid}-----------.html' + + headers = self.header.copy() + + headers['Referer'] = f'https://feikuai.tv/vodtype/{tid}.html' + + rsp = self.fetch(url, headers=headers) + if not rsp or not rsp.text: + return result + + root = self._parse_html(rsp) + videos = [] + seen = set() + try: + links = root.xpath('//div[contains(@class, "module-items") and contains(@class, "module-poster-items")]//a[contains(@href, "/voddetail/")]') or \ + root.xpath('//a[contains(@class, "module-poster-item") and contains(@href, "/voddetail/")]') or \ + root.xpath('//div[contains(@class, "module-card-items")]//a[contains(@href, "/voddetail/")]') + + for a in links: + video_item = self._parse_video_item(a) + if video_item and video_item["vod_id"] not in seen: + seen.add(video_item["vod_id"]) + videos.append(video_item) + except Exception: + pass + + result['list'] = videos + return result + + def _decode_url_field(self, raw, encrypt): + try: + if not raw: + return '' + enc = str(encrypt or '0').strip() + if enc == '1': + txt = unquote(raw) + elif enc == '2': + try: + b = base64.b64decode(raw + '===') + txt = unquote(b.decode('utf-8', errors='ignore')) + except Exception: + txt = unquote(raw) + else: + txt = raw + + txt = re.sub(r'%u([0-9a-fA-F]{4})', + lambda m: chr(int(m.group(1), 16)), txt) + return txt + except Exception: + return raw + + def detailContent(self, ids): + if not ids: + return {'list': []} + tid = str(ids[0]).strip() + url = f'https://feikuai.tv/voddetail/{tid}.html' + try: + rsp = self.fetch(url, headers=self.header) + if not rsp or not rsp.text: + return {'list': []} + root = self._parse_html(rsp) + if not root: + return {'list': []} + except Exception: + return {'list': []} + + title = root.xpath('//h1/text() | //div[contains(@class, "module-info-heading")]//h1/text()') + title = title[0].strip() if title else '' + pic = '' + try: + pnodes = root.xpath('//div[contains(@class, "module-info-poster")]//img/@data-original[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') + if not pnodes: + pnodes = root.xpath('//div[contains(@class, "module-info-poster")]//img/@src[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') + if not pnodes: + pnodes = root.xpath('//img[contains(@class, "lazy")]/@data-original[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') + if not pnodes: + pnodes = root.xpath('//img[contains(@class, "lazy")]/@src[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') + if pnodes: + pic = pnodes[0] + if pic.startswith('/'): + pic = 'https://feikuai.tv' + pic + except Exception: + pic = '' + + detail = '' + try: + dnodes = root.xpath('//div[contains(@class, "module-info-introduction-content")]//text()') + detail = '\n'.join([x.strip() for x in dnodes if x.strip()]) if dnodes else '' + except Exception: + detail = '' + + vod = { + "vod_id": tid, + "vod_name": title, + "vod_pic": pic, + "type_name": "", + "vod_year": "", + "vod_area": "", + "vod_remarks": "", + "vod_actor": "", + "vod_director": "", + "vod_content": detail + } + + playFrom = [] + playList = [] + try: + ep_links = root.xpath('//div[contains(@class, "module-play-list")]//a[contains(@href, "/vodplay/")] | //ul[contains(@class, "module-play-list")]//a[contains(@href, "/vodplay/")]') + groups = {} + for a in ep_links: + try: + href = a.xpath('./@href')[0] if a.xpath('./@href') else '' + m = re.search(r'/vodplay/(\d+)-(\d+)-(\d+)\.html', href) + if not m: + continue + vid, sid, epid = m.groups() + if vid != tid: + continue + name = ''.join(a.xpath('string(.)')).strip() + if not name or name in ('立即播放', '收藏', '追更', '分享', '报错', '下载'): + continue + if sid not in groups: + groups[sid] = [] + groups[sid].append(f"{name}${vid}-{sid}-{epid}") + except Exception: + continue + + ordered_sids = [] + for blk in root.xpath('//div[contains(@class, "his-tab-list")]'): + try: + first = blk.xpath('.//a[contains(@href, "/vodplay/")][1]/@href') + if first: + mm = re.search(r'/vodplay/(\d+)-(\d+)-(\d+)\.html', first[0]) + if mm: + sid = mm.group(2) + if sid not in ordered_sids: + ordered_sids.append(sid) + except Exception: + continue + + labels = [x.strip() for x in root.xpath('//div[contains(@class, "module-tab-items-box")]//div[contains(@class, "module-tab-item")]//span/text()') if x.strip()] + + for idx, sid in enumerate(ordered_sids): + sname = labels[idx] if idx < len(labels) else f"线路{sid}" + playFrom.append(sname) + playList.append('#'.join(groups.get(sid, []))) + except Exception: + pass + + vod['vod_play_from'] = '$$$'.join(playFrom) if playFrom else "" + vod['vod_play_url'] = '$$$'.join(playList) + return {'list': [vod]} + + def searchContent(self, key, quick, pg='1'): + videos = [] + try: + pg = str(pg) + if pg in ('', '1'): + url = f'https://feikuai.tv/vodsearch/-------------.html?wd={quote_plus(key)}' + headers = self.header.copy() + headers['Referer'] = f'https://feikuai.tv/vodsearch/-------------.html?wd={quote_plus(key)}' + else: + url = f'https://feikuai.tv/label/search_ajax.html?wd={quote_plus(key)}&by=time&order=desc&page={pg}' + headers = self.header.copy() + headers['X-Requested-With'] = 'XMLHttpRequest' + headers['Accept'] = '*/*' + headers['Referer'] = f'https://feikuai.tv/vodsearch/-------------.html?wd={quote_plus(key)}' + + rsp = self.fetch(url, headers=headers) + if not rsp or not rsp.text: + return {'list': []} + + root = self._parse_html(rsp) + items = root.xpath('//div[@id="resultList"]//a[contains(@href, "/voddetail/")]') or \ + root.xpath('//div[contains(@class, "module-card-items")]//a[contains(@href, "/voddetail/")]') or \ + root.xpath('//div[contains(@class, "module-items") and contains(@class, "module-poster-items")]//a[contains(@href, "/voddetail/")]') or \ + root.xpath('//a[contains(@href, "/voddetail/")]') + + seen = set() + for a in items: + video_item = self._parse_video_item(a) + if video_item and video_item["vod_id"] not in seen: + seen.add(video_item["vod_id"]) + videos.append(video_item) + except Exception: + pass + return {'list': videos} + + def playerContent(self, flag, id, vipFlags): + play_url = f'https://feikuai.tv/vodplay/{id}.html' + vurl = play_url + try: + rsp = self.fetch(play_url, headers=self.header, timeout=45) + if not rsp or not rsp.text: + return {"parse": 0, "url": vurl, "header": self.header} + pattern = r'(?:var\s+)?player_[a-zA-Z0-9_]+\s*=\s*(\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})(?=\s*)' + m = re.search(pattern, rsp.text, re.S) + if m: + data = json.loads(m.group(1)) + vurl = data.get('url') or '' + vurl = self._decode_url_field(vurl, str(data.get('encrypt', '0'))) + if vurl.startswith('//'): + vurl = 'https:' + vurl + if vurl.endswith('.m3u8'): + return {"parse": 1, "url": vurl, "header": self.header} + except Exception: + pass + return {"parse": 0, "url": vurl, "header": self.header} + + def localProxy(self, params): + pass + + def isVideoFormat(self, url): + return url + + def manualVideoCheck(self): + return [] + + def destroy(self): + pass + + def getProxyUrl(self, local=True): + return 'http://127.0.0.1:9978/proxy?do=py' + + header = { + "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", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Connection": "keep-alive" + } diff --git a/lrzy/py/飞快TV[推].py b/lrzy/py/飞快TV[推].py new file mode 100644 index 0000000..4842f66 --- /dev/null +++ b/lrzy/py/飞快TV[推].py @@ -0,0 +1,460 @@ +""" +@header({ + searchable: 1, + filterable: 1, + quickSearch: 1, + title: '飞快', + author: 'EylinSir修复版-网盘推送播放', + lang: 'hipy' +}) +""" + +import sys +import json +import re +import base64 +import datetime +from urllib.parse import quote_plus, unquote +from lxml import etree + +sys.path.append('..') +from base.spider import Spider + + +class Spider(Spider): + def getName(self): + return "飞快" + + def init(self, extend=""): + pass + + def homeContent(self, filter): + _r1 = {} + _c1 = { + "电影": "1", + "剧集": "2", + "综艺": "3", + "动漫": "4" + } + _c2 = [{'type_name': _k1, 'type_id': _v1} for _k1, _v1 in _c1.items()] + _r1['class'] = _c2 + return _r1 + + def homeVideoContent(self): + _l1 = [] + try: + _u1 = "".join(['h', 't', 't', 'p', 's', ':', '/', '/', 'f', 'e', 'i', 'k', 'u', 'a', 'i', '.', 't', 'v', '/']) + _r2 = self.fetch(_u1, headers=self._get_header()) + if not _r2 or not _r2.text: + return {'list': _l1} + + _h1 = self._parse_dom(_r2) + if not _h1: + return {'list': _l1} + + _x1 = _h1.xpath( + '//div[contains(@class, "module-focus")]//a[contains(@href, "/voddetail/")] | ' + '//div[contains(@class, "module-hot")]//a[contains(@href, "/voddetail/")] | ' + '//div[contains(@class, "module-recommend")]//a[contains(@href, "/voddetail/")] | ' + '//div[contains(@class, "module-items") and contains(@class, "module-poster-items")]//a[contains(@href, "/voddetail/")]' + ) + + _s1 = set() + for _a1 in _x1: + _v1 = self._parse_item(_a1) + if _v1 and _v1["vod_id"] not in _s1: + _s1.add(_v1["vod_id"]) + _l1.append(_v1) + + _l1 = _l1[:30] + except Exception: + pass + return {'list': _l1} + + def categoryContent(self, tid, pg, filter, extend): + if tid == '0': + return self.homeVideoContent() + + _r3 = {'list': [], 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999} + try: + _e1 = json.loads(extend) if extend and isinstance(extend, str) else {} + _u2 = self._build_url(tid, pg, _e1) + except Exception: + _u2 = f'{"".join(["h","t","t","p","s",":","/","/","f","e","i","k","u","a","i",".","t","v","/","v","o","d","s","h","o","w","/",tid,"-","-","-","-","-","-","-","-","-",".","h","t","m","l"])}' + + _h2 = self._get_header().copy() + _h2['Referer'] = f'https://feikuai.tv/vodtype/{tid}.html' + + _r4 = self.fetch(_u2, headers=_h2) + if not _r4 or not _r4.text: + return _r3 + + _h3 = self._parse_dom(_r4) + _v2 = [] + _s2 = set() + try: + _l2 = _h3.xpath('//div[contains(@class, "module-items") and contains(@class, "module-poster-items")]//a[contains(@href, "/voddetail/")]') or \ + _h3.xpath('//a[contains(@class, "module-poster-item") and contains(@href, "/voddetail/")]') or \ + _h3.xpath('//div[contains(@class, "module-card-items")]//a[contains(@href, "/voddetail/")]') + + for _a2 in _l2: + _v3 = self._parse_item(_a2) + if _v3 and _v3["vod_id"] not in _s2: + _s2.add(_v3["vod_id"]) + _v2.append(_v3) + except Exception: + pass + + _r3['list'] = _v2 + return _r3 + + def detailContent(self, ids): + if not ids: + return {'list': []} + _t1 = str(ids[0]).strip() + _u3 = f'https://feikuai.tv/voddetail/{_t1}.html' + try: + _r5 = self.fetch(_u3, headers=self._get_header()) + if not _r5 or not _r5.text: + return {'list': []} + _h4 = self._parse_dom(_r5) + if not _h4: + return {'list': []} + except Exception: + return {'list': []} + + _t2 = _h4.xpath('//h1/text() | //div[contains(@class, "module-info-heading")]//h1/text()') + _t3 = _t2[0].strip() if _t2 else '' + _p1 = self._get_img(_h4) + _d1 = self._get_desc(_h4) + + _v4 = { + "vod_id": _t1, + "vod_name": _t3, + "vod_pic": _p1, + "type_name": "", + "vod_year": "", + "vod_area": "", + "vod_remarks": "", + "vod_actor": "", + "vod_director": "", + "vod_content": _d1 + } + + _f1, _l3 = self._get_sources(_h4, _t1) + + if not _f1 or not _l3: + _f1 = ['飞快'] + _l3 = [f'{"".join(["暂","无","播","放","源"])}${"".join(["h","t","t","p","s",":","/","/","f","e","i","k","u","a","i",".","t","v","/","v","o","d","d","e","t","a","i","l","/",_t1,".","h","t","m","l"])}'] + + _v4['vod_play_from'] = '$$$'.join(_f1) if _f1 else "" + _v4['vod_play_url'] = '$$$'.join(_l3) + return {'list': [_v4]} + + def searchContent(self, key, quick, pg='1'): + _v5 = [] + try: + _p2 = str(pg) + if _p2 in ('', '1'): + _u4 = f'https://feikuai.tv/vodsearch/-------------.html?wd={quote_plus(key)}' + _h5 = self._get_header().copy() + _h5['Referer'] = f'https://feikuai.tv/vodsearch/-------------.html?wd={quote_plus(key)}' + else: + _u4 = f'https://feikuai.tv/label/search_ajax.html?wd={quote_plus(key)}&by=time&order=desc&page={_p2}' + _h5 = self._get_header().copy() + _h5['X-Requested-With'] = 'XMLHttpRequest' + _h5['Accept'] = '*/*' + _h5['Referer'] = f'https://feikuai.tv/vodsearch/-------------.html?wd={quote_plus(key)}' + + _r6 = self.fetch(_u4, headers=_h5) + if not _r6 or not _r6.text: + return {'list': []} + + _h6 = self._parse_dom(_r6) + _i1 = _h6.xpath('//div[@id="resultList"]//a[contains(@href, "/voddetail/")]') or \ + _h6.xpath('//div[contains(@class, "module-card-items")]//a[contains(@href, "/voddetail/")]') or \ + _h6.xpath('//div[contains(@class, "module-items") and contains(@class, "module-poster-items")]//a[contains(@href, "/voddetail/")]') or \ + _h6.xpath('//a[contains(@href, "/voddetail/")]') + + _s3 = set() + for _a3 in _i1: + _v6 = self._parse_item(_a3) + if _v6 and _v6["vod_id"] not in _s3: + _s3.add(_v6["vod_id"]) + _v5.append(_v6) + except Exception: + pass + return {'list': _v5} + + def playerContent(self, flag, id, vipFlags): + + if isinstance(id, str) and id.startswith(''.join(['p','u','s','h',':','/','/'])): + return {"parse": 0, "url": id} + + + _u5 = f'https://feikuai.tv/vodplay/{id}.html' + _v7 = _u5 + try: + _r7 = self.fetch(_u5, headers=self._get_header(), timeout=45) + if not _r7 or not _r7.text: + return {"parse": 0, "url": _v7, "header": self._get_header()} + + _p3 = r'(?:var\s+)?player_[a-zA-Z0-9_]+\s*=\s*(\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})(?=\s*)' + _m1 = re.search(_p3, _r7.text, re.S) + if _m1: + _d2 = json.loads(_m1.group(1)) + _v7 = _d2.get('url') or '' + _v7 = self._decode_str(_v7, str(_d2.get('encrypt', '0'))) + if _v7.startswith('//'): + _v7 = 'https:' + _v7 + if _v7.endswith('.m3u8'): + return {"parse": 1, "url": _v7, "header": self._get_header()} + except Exception: + pass + return {"parse": 0, "url": _v7, "header": self._get_header()} + + def _parse_item(self, a_element): + try: + _h7 = a_element.xpath('./@href')[0] if a_element.xpath('./@href') else '' + _m2 = re.search(r'/voddetail/(\d+)\.html', _h7) + if not _m2: + return None + _s4 = _m2.group(1) + + _t4 = (a_element.xpath('.//div[contains(@class, "module-poster-item-title")]//text()') or + a_element.xpath('.//div[contains(@class, "module-card-item-title")]/a//text()') or + a_element.xpath('./@title') or a_element.xpath('.//img/@alt')) + _n1 = _t4[0].strip() if _t4 else f"视频_{_s4}" + + _i2 = self._get_img(a_element) + + _r8 = a_element.xpath('.//div[contains(@class, "module-item-note")]//text()') + _r9 = ''.join([x.strip() for x in _r8 if x.strip()]) if _r8 else "" + + return { + "vod_id": _s4, + "vod_name": _n1, + "vod_pic": _i2, + "vod_remarks": _r9 + } + except Exception: + return None + + def _get_img(self, element): + _i3 = (element.xpath('.//img[contains(@class, "lazy")]/@data-original[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') or + element.xpath('.//img[contains(@class, "lazy")]/@src[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') or + element.xpath('.//img/@data-original[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]') or + element.xpath('.//img/@src[contains(., ".webp") or contains(., ".jpg") or contains(., ".png")]')) + + if _i3: + _i4 = _i3[0] + if _i4.startswith('/'): + _i4 = 'https://feikuai.tv' + _i4 + return _i4 + return '' + + def _get_desc(self, root): + try: + _d3 = root.xpath('//div[contains(@class, "module-info-introduction-content")]//text()') + _d4 = '\n'.join([x.strip() for x in _d3 if x.strip()]) if _d3 else '' + return _d4 + except Exception: + return '' + + def _parse_dom(self, rsp): + try: + _p4 = etree.HTMLParser(encoding='utf-8', recover=True, remove_blank_text=True) + if hasattr(rsp, 'content'): + return etree.HTML(rsp.content, parser=_p4) + return etree.HTML(rsp.text.encode('utf-8', errors='ignore'), parser=_p4) + except Exception: + return None + + def _build_url(self, tid, pg, ext): + _a1 = (ext.get('area') or ext.get('1') or '').strip() + _c3 = (ext.get('class') or ext.get('3') or '').strip() + _y1 = (ext.get('year') or ext.get('11') or '').strip() + + _e2 = quote_plus(_a1) if _a1 else '' + _e3 = quote_plus(_c3) if _c3 else '' + _p5 = '' if str(pg) in ('', '1') else str(pg) + return f'https://feikuai.tv/vodshow/{tid}-{_e2}--{_e3}-----{_p5}---{_y1}.html' + + def _get_sources(self, root, tid): + _f2 = [] + _l4 = [] + + self._get_normal_sources(root, tid, _f2, _l4) + + self._get_pan_sources(root, tid, _f2, _l4) + + return _f2, _l4 + + def _get_normal_sources(self, root, tid, playFrom, playList): + try: + _e4 = root.xpath('//div[contains(@class, "module-play-list")]//a[contains(@href, "/vodplay/")] | //ul[contains(@class, "module-play-list")]//a[contains(@href, "/vodplay/")]') + _g1 = {} + for _a4 in _e4: + try: + _h8 = _a4.xpath('./@href')[0] if _a4.xpath('./@href') else '' + _m3 = re.search(r'/vodplay/(\d+)-(\d+)-(\d+)\.html', _h8) + if not _m3: + continue + _v8, _s5, _e5 = _m3.groups() + if _v8 != tid: + continue + _n2 = ''.join(_a4.xpath('string(.)')).strip() + if not _n2 or _n2 in ('立即播放', '收藏', '追更', '分享', '报错', '下载'): + continue + if _s5 not in _g1: + _g1[_s5] = [] + _g1[_s5].append(f"{_n2}${_v8}-{_s5}-{_e5}") + except Exception: + continue + + _o1 = [] + for _b1 in root.xpath('//div[contains(@class, "his-tab-list")]'): + try: + _f3 = _b1.xpath('.//a[contains(@href, "/vodplay/")][1]/@href') + if _f3: + _m4 = re.search(r'/vodplay/(\d+)-(\d+)-(\d+)\.html', _f3[0]) + if _m4: + _s6 = _m4.group(2) + if _s6 not in _o1: + _o1.append(_s6) + except Exception: + continue + + _l5 = [x.strip() for x in root.xpath('//div[contains(@class, "module-tab-items-box")]//div[contains(@class, "module-tab-item")]//span/text()') if x.strip()] + + for _i5, _s7 in enumerate(_o1): + _s8 = _l5[_i5] if _i5 < len(_l5) else f"线路{_s7}" + playFrom.append(_s8) + playList.append('#'.join(_g1.get(_s7, []))) + except Exception: + pass + + def _get_pan_sources(self, root, tid, playFrom, playList): + try: + _d5 = root.xpath('//div[@id="download-list"]') + if not _d5: + return + + _t5 = root.xpath('//div[@id="y-downList"]//div[contains(@class, "module-tab-item")]') + + _p6 = { + '百度网盘': '百度网盘', + '夸克网盘': '夸克网盘', + '迅雷云盘': '迅雷云盘', + '阿里云盘': '阿里云盘', + '天翼云盘': '天翼云盘', + 'UC网盘': 'UC网盘', + '115网盘': '115网盘', + '移动云盘': '移动云盘' + } + + for _t6 in _t5: + try: + _s9 = ''.join(_t6.xpath('.//span/text()')).strip() + if not _s9 or _s9 == '磁力链接': + continue + + _s10 = _p6.get(_s9, _s9) + + _t7 = _t6.xpath('./@data-index') + if not _t7: + continue + _t8 = _t7[0] + + _c4 = root.xpath(f'//div[@id="tab-content-{_t8}"]//div[@class="module-row-info"]//a') + + _e6 = [] + for _i6, _l6 in enumerate(_c4, 1): + try: + _u6 = _l6.xpath('./@href') + if not _u6: + continue + _u7 = _u6[0].strip() + + _h9 = _l6.xpath('.//h4/text()') + if _h9: + _e7 = _h9[0].strip() + _e7 = re.sub(r'@一键搜片-\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}$', '', _e7).strip() + else: + _e7 = f"资源{_i6}" + + _u8 = self._process_url(_u7) + if _u8: + _e6.append(f"{_e7}${_u8}") + except Exception: + continue + + if _e6: + playFrom.append(_s10) + playList.append('#'.join(_e6)) + except Exception: + continue + except Exception: + pass + + def _process_url(self, raw_url): + try: + if not raw_url: + return None + + if not raw_url.startswith(('http://', 'https://')): + if raw_url.startswith('//'): + _u9 = 'https:' + raw_url + elif raw_url.startswith('/'): + _u9 = 'https://feikuai.tv' + raw_url + else: + return None + else: + _u9 = raw_url + + return f"push://{_u9}" + + except Exception: + return None + + def _decode_str(self, raw, encrypt): + try: + if not raw: + return '' + _e8 = str(encrypt or '0').strip() + if _e8 == '1': + _t9 = unquote(raw) + elif _e8 == '2': + try: + _b2 = base64.b64decode(raw + '===') + _t9 = unquote(_b2.decode('utf-8', errors='ignore')) + except Exception: + _t9 = unquote(raw) + else: + _t9 = raw + + _t9 = re.sub(r'%u([0-9a-fA-F]{4})', + lambda _m5: chr(int(_m5.group(1), 16)), _t9) + return _t9 + except Exception: + return raw + + def _get_header(self): + return { + "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", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Connection": "keep-alive" + } + + def localProxy(self, params): + pass + + def isVideoFormat(self, url): + return url + + def manualVideoCheck(self): + return [] + + def destroy(self): + pass diff --git a/lrzy/py/饭团影视.py b/lrzy/py/饭团影视.py new file mode 100644 index 0000000..1d5972d --- /dev/null +++ b/lrzy/py/饭团影视.py @@ -0,0 +1,478 @@ +# coding = utf-8 +# !/usr/bin/python + +""" + +作者 丢丢喵 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容 + ====================Diudiumiao==================== + +""" + +from Crypto.Util.Padding import unpad +from urllib.parse import unquote +from Crypto.Cipher import ARC4 +from urllib.parse import quote +from base.spider import Spider +from Crypto.Cipher import AES +from bs4 import BeautifulSoup +from base64 import b64decode +import urllib.request +import urllib.parse +import binascii +import requests +import base64 +import json +import time +import sys +import re +import os + +sys.path.append('..') + +xurl = "https://fantuansjz.com" + +headerx = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36' + } + +pm = '' + +class Spider(Spider): + global xurl + global headerx + global headers + + def getName(self): + return "首页" + + def init(self, extend): + pass + + def isVideoFormat(self, url): + pass + + def manualVideoCheck(self): + pass + + def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''): + if pl == 3: + plx = [] + while True: + start_index = text.find(start_str) + if start_index == -1: + break + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + break + middle_text = text[start_index + len(start_str):end_index] + plx.append(middle_text) + text = text.replace(start_str + middle_text + end_str, '') + if len(plx) > 0: + purl = '' + for i in range(len(plx)): + matches = re.findall(start_index1, plx[i]) + output = "" + for match in matches: + match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1]) + if match3: + number = match3.group(1) + else: + number = 0 + if 'http' not in match[0]: + output += f"#{match[1]}${number}{xurl}{match[0]}" + else: + output += f"#{match[1]}${number}{match[0]}" + output = output[1:] + purl = purl + output + "$$$" + purl = purl[:-3] + return purl + else: + return "" + else: + start_index = text.find(start_str) + if start_index == -1: + return "" + end_index = text.find(end_str, start_index + len(start_str)) + if end_index == -1: + return "" + + if pl == 0: + middle_text = text[start_index + len(start_str):end_index] + return middle_text.replace("\\", "") + + if pl == 1: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + jg = ' '.join(matches) + return jg + + if pl == 2: + middle_text = text[start_index + len(start_str):end_index] + matches = re.findall(start_index1, middle_text) + if matches: + new_list = [f'{item}' for item in matches] + jg = '$$$'.join(new_list) + return jg + + def homeContent(self, filter): + result = {} + result = {"class": [{"type_id": "1", "type_name": "电影"}, + {"type_id": "2", "type_name": "剧集"}, + {"type_id": "3", "type_name": "综艺"}, + {"type_id": "4", "type_name": "动漫"}, + {"type_id": "40", "type_name": "豆瓣"}], + + "list": [], + "filters": {"1": [{"key": "年代", + "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"}]}], + "2": [{"key": "年代", + "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"}]}], + "3": [{"key": "年代", + "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"}]}], + "4": [{"key": "年代", + "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"}]}], + "40": [{"key": "年代", + "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"}]}]}} + + return result + + def homeVideoContent(self): + videos = [] + + try: + detail = requests.get(url=xurl, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('ul', class_="fed-list-info") + + for soup in soups: + vods = soup.find_all('li') + + for vod in vods: + names = vod.find('a', class_="fed-list-title") + name = names.text.strip() + + id = names['href'] + + pics = vod.find('a', class_="fed-list-pics") + pic = pics['data-original'] + + if 'http' not in pic: + pic = xurl + pic + + remarks = vod.find('span', class_="fed-list-remarks") + remark = remarks.text.strip() + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": '▶️' + remark + } + videos.append(video) + + result = {'list': videos} + return result + except: + pass + + def categoryContent(self, cid, pg, filter, ext): + result = {} + videos = [] + + if pg: + page = int(pg) + else: + page = 1 + + if '年代' in ext.keys(): + NdType = ext['年代'] + else: + NdType = '' + + if page == 1: + url = f'{xurl}/sjvodtype/{cid}.html' + + else: + url = f'{xurl}/sjvodshow/{cid}--------{str(page)}---{NdType}.html' + + try: + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('ul', class_="fed-list-info") + + for soup in soups: + vods = soup.find_all('li') + + for vod in vods: + names = vod.find('a', class_="fed-list-title") + name = names.text.strip() + + id = names['href'] + + pics = vod.find('a', class_="fed-list-pics") + pic = pics['data-original'] + + if 'http' not in pic: + pic = xurl + pic + + remarks = vod.find('span', class_="fed-list-remarks") + remark = remarks.text.strip() + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": '▶️' + remark + } + videos.append(video) + + except: + pass + result = {'list': videos} + result['page'] = pg + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def detailContent(self, ids): + global pm + did = ids[0] + result = {} + videos = [] + + if 'http' not in did: + did = xurl + did + + res = requests.get(url=did, headers=headerx) + res.encoding = "utf-8" + res = res.text + + url = 'https://m.baidu.com/' + response = requests.get(url) + response.encoding = 'utf-8' + code = response.text + name = self.extract_middle_text(code, "s1='", "'", 0) + Jumps = self.extract_middle_text(code, "s2='", "'", 0) + + content = '😸🎉剧情介绍📢' + self.extract_middle_text(res,'剧情介绍:','">', 0) + + director = self.extract_middle_text(res, '导演:', '',1,'target=".*?">(.*?)') + + actor = self.extract_middle_text(res, '主演:', '',1,'target=".*?">(.*?)') + + remarks = self.extract_middle_text(res, 'fed-text-white fed-text-center">', '
', 0) + + year = self.extract_middle_text(res, '年份:', '', 1,'target=".*?">(.*?)') + + area = self.extract_middle_text(res, '地区:', '', 1,'target=".*?">(.*?)') + + if name not in content: + bofang = Jumps + else: + doc = BeautifulSoup(res, "lxml") + + soups = doc.find('ul', class_="fed-padding") + + soup = soups.find_all('a') + + jishu = 0 + xian = [] + xianlu = '' + bofang = '' + gl = [] + + for sou in soup: + jishu = jishu + 1 + + name = sou.text.strip() + + if any(item in name for item in gl): + continue + + xian.append(jishu) + + xianlu = xianlu + name + '$$$' + + xianlu = xianlu[:-3] + + for psou in xian: + jishu = psou - 1 + + soups = doc.find_all('ul', class_="fed-tabs-btm")[jishu] + + soup = soups.find_all('a') + + for sou in soup: + + id = sou['href'] + + if 'http' not in id: + id = xurl + id + + name = sou.text.strip() + + bofang = bofang + name + '$' + id + '#' + + bofang = bofang[:-1] + '$$$' + + bofang = bofang[:-3] + + videos.append({ + "vod_id": did, + "vod_director": director, + "vod_actor": actor, + "vod_remarks": remarks, + "vod_year": year, + "vod_area": area, + "vod_content": content, + "vod_play_from": xianlu, + "vod_play_url": bofang + }) + + result['list'] = videos + return result + + def playerContent(self, flag, id, vipFlags): + parts = id.split("http") + + xiutan = 0 + + if xiutan == 0: + if len(parts) > 1: + before_https, after_https = parts[0], 'http' + parts[1] + + if '/tp/jd.m3u8' in after_https: + url = after_https + else: + res = requests.get(url=after_https, headers=headerx) + res = res.text + + url = self.extract_middle_text(res, '},"url":"', '"', 0).replace('\\', '') + + result = {} + result["parse"] = xiutan + result["playUrl"] = '' + result["url"] = url + result["header"] = headerx + return result + + def searchContentPage(self, key, quick, page): + result = {} + videos = [] + + if not page: + page = '1' + if page == '1': + url = f'{xurl}/sjvodsearch/-------------.html?wd={key}' + + else: + url = f'{xurl}/sjvodsearch/{key}----------{str(page)}---.html' + + detail = requests.get(url=url, headers=headerx) + detail.encoding = "utf-8" + res = detail.text + doc = BeautifulSoup(res, "lxml") + + soups = doc.find_all('dl', class_="fed-list-deta") + + for vod in soups: + names = vod.find('h3', class_="fed-part-eone") + name = names.text.strip() + + ids = vod.find('a', class_="fed-list-pics") + id = ids['href'] + id = id.replace('/sjvodplay/', '/sjvoddetail/').replace('-1-1', '') + + pic = ids['data-original'] + + if 'http' not in pic: + pic = xurl + pic + + remarks = vod.find('span', class_="fed-list-remarks") + remark = remarks.text.strip() + + video = { + "vod_id": id, + "vod_name": name, + "vod_pic": pic, + "vod_remarks": '▶️' + remark + } + videos.append(video) + + result['list'] = videos + result['page'] = page + result['pagecount'] = 9999 + result['limit'] = 90 + result['total'] = 999999 + return result + + def searchContent(self, key, quick, pg="1"): + return self.searchContentPage(key, quick, '1') + + def localProxy(self, params): + if params['type'] == "m3u8": + return self.proxyM3u8(params) + elif params['type'] == "media": + return self.proxyMedia(params) + elif params['type'] == "ts": + return self.proxyTs(params) + return None + + + + +