updated CATJS

This commit is contained in:
lem85930 2024-05-22 19:54:50 +08:00
parent aeb70c2987
commit 3f76a9bb53
118 changed files with 75713 additions and 0 deletions

View File

@ -0,0 +1,144 @@
{
"video": {
"sites": [
{
"key": "feifan18",
"name": "🔞┃非凡资源18+┃🔞",
"api": "./js/feifan18.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "jable",
"name": "🔞┃Jable┃🔞",
"api": "./js/jable.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "liangzi18",
"name": "🔞┃量子资源18+┃🔞",
"api": "./js/liangzi18.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "sehuatang",
"name": "🔞┃色花堂BT┃🔞",
"api": "./js/sehuatang.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "hanxiucao",
"name": "🔞┃含羞草┃🔞",
"api": "./js/hanxiucao.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "ciliduo",
"name": "🔞┃磁力多BT┃🔞",
"api": "./js/ciliduo.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "nivod_18",
"name": "🔞┃泥视频18+┃🔞",
"api": "./js/nivod_18.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "jiujiuliu",
"name": "🔞┃九九六影视┃🔞",
"api": "./js/jiujiuliu.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "asianx",
"name": "🔞┃海外宅┃🔞",
"api": "./js/asianx.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "hscangku",
"name": "🔞┃黄色仓库┃🔞",
"api": "./js/hscangku.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "doll",
"name": "🔞┃玩偶姐姐┃🔞",
"api": "./js/doll.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
},
{
"key": "lovemovie18",
"name": "🔞┃爱情电影网18+┃🔞",
"api": "./js/lovemovie18.js",
"timeout": 30,
"ext": {
"box": "CatOpen"
},
"playerType": 0,
"type": 3
}
]
},
"read": {
"sites": []
},
"pan": {
"sites": []
}
}

507
JN/CATJS/18_tv_config.json Normal file
View File

@ -0,0 +1,507 @@
{
"sites": [
{
"key": "feifan18",
"name": "🔞┃非凡资源18+┃🔞",
"api": "./js/feifan18.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "jable",
"name": "🔞┃Jable┃🔞",
"api": "./js/jable.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "liangzi18",
"name": "🔞┃量子资源18+┃🔞",
"api": "./js/liangzi18.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "sehuatang",
"name": "🔞┃色花堂BT┃🔞",
"api": "./js/sehuatang.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "hanxiucao",
"name": "🔞┃含羞草┃🔞",
"api": "./js/hanxiucao.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "ciliduo",
"name": "🔞┃磁力多BT┃🔞",
"api": "./js/ciliduo.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "nivod_18",
"name": "🔞┃泥视频18+┃🔞",
"api": "./js/nivod_18.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "jiujiuliu",
"name": "🔞┃九九六影视┃🔞",
"api": "./js/jiujiuliu.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "asianx",
"name": "🔞┃海外宅┃🔞",
"api": "./js/asianx.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "hscangku",
"name": "🔞┃黄色仓库┃🔞",
"api": "./js/hscangku.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "doll",
"name": "🔞┃玩偶姐姐┃🔞",
"api": "./js/doll.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
},
{
"key": "lovemovie18",
"name": "🔞┃爱情电影网18+┃🔞",
"api": "./js/lovemovie18.js",
"timeout": 30,
"ext": {
"box": "TVBox"
},
"playerType": 0,
"type": 3
}
],
"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": "max-buffer-size",
"value": "5242880"
},
{
"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": "max-buffer-size",
"value": "5242880"
},
{
"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": [
"wan.51img1.com",
"iqiyi.hbuioo.com",
"vip.ffzyad.com",
"https://lf1-cdn-tos.bytegoofy.com/obj/tos-cn-i-dy/455ccf9e8ae744378118e4bd289288dd",
"static-mozai.4gtv.tv",
"s3t3d2y8.afcdn.net",
"4gtvfreepcvod-cds.cdn.hinet.net"
],
"rules": [
{
"name": "星星",
"hosts": [
"aws.ulivetv.net"
],
"regex": [
"#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:8,[\\s\\S]*?#EXT-X-DISCONTINUITY"
]
},
{
"name": "量子廣告",
"hosts": [
"vip.lz",
"hd.lz"
],
"regex": [
"#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:6.433333,[\\s\\S]*?#EXT-X-DISCONTINUITY",
"#EXTINF.*?\\s+.*?1o.*?\\.ts\\s+"
]
},
{
"name": "非凡廣告",
"hosts": [
"vip.ffzy",
"hd.ffzy"
],
"regex": [
"#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:6.666667,[\\s\\S]*?#EXT-X-DISCONTINUITY",
"#EXTINF.*?\\s+.*?1o.*?\\.ts\\s+"
]
},
{
"name": "火山嗅探",
"hosts": [
"huoshan.com"
],
"regex": [
"item_id="
]
},
{
"name": "抖音嗅探",
"hosts": [
"douyin.com"
],
"regex": [
"is_play_url="
]
}
],
"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-quer",
"ips": [
"9.9.9.9",
"149.112.112.112"
]
}
],
"parses": [
{
"name": "聚合",
"type": 3,
"url": "Demo"
},
{
"name": "线路1",
"type": 0,
"url": "https://jx.xmflv.com/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57"
}
}
},
{
"name": "线路2",
"type": 0,
"url": "https://jx.quankan.app/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36"
}
}
},
{
"name": "线路3",
"type": 0,
"url": "https://jx.yparse.com/index.php?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36"
}
}
},
{
"name": "线路4",
"type": 0,
"url": "https://jx.jsonplayer.com/player/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36"
}
}
},
{
"name": "线路5",
"type": 0,
"url": "https://jx.aidouer.net/?url=",
"ext": {
"header": {
"user-agent": "Mozilla/5.0 (Linux; Android 13; V2049A Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36",
"referer": "https://jiejie.uk/"
}
}
},
{
"name": "线路6",
"type": 0,
"url": "https://jx.777jiexi.com/player/?url="
},
{
"name": "线路7",
"type": 0,
"url": "https://www.8090g.cn/?url="
},
{
"name": "线路8",
"type": 0,
"url": "https://jx.yangtu.top?url="
},
{
"name": "线路9",
"type": 0,
"url": "https://jx.m3u8.tv/jiexi/?url="
},
{
"name": "线路10",
"type": 0,
"url": "https://www.ckplayer.vip/jiexi/?url="
}
],
"lives": [
{
"name": "live",
"type": 0,
"url": "https://gh.con.sh/https://github.com/jadehh/LiveSpider/blob/main/live/live.txt",
"playerType": 1,
"ua": "okhttp/3.15",
"epg": "http://epg.112114.xyz/?ch={name}&date={date}",
"logo": "https://epg.112114.xyz/logo/{name}.png"
}
],
"wallpaper": "https://api.likepoems.com/img/bing"
}

80
JN/CATJS/README.md Normal file
View File

@ -0,0 +1,80 @@
# CatVodOpen和TvBox
## 食用前阅读
&ensp;&ensp;授人以鱼不如授人以渔本仓意指在教会大家学会Spider也欢迎大家提ISSUE一起学习一起进步。<br>
&ensp;&ensp;以下资源不能保证内容的合法性、准确性、完整性和有效性,请根据情况自行判断。
仅用于测试和学习研究,禁止用于商业用途,不得将其用于违反国家、地区、组织等的法律法规或相关规定的其他用途。
使用任何第三方硬件、软件、所造成的一切后果由使用的个人或组织承担,与本文内容无关。
所有直接或间接使用本内容的个人和组织,应 24 小时内完成学习和研究,并及时删除本文内容。
所有基于本内容的源代码,进行的任何修改,为其他个人或组织的自发行为,与本内容没有任何直接或间接的关系,所造成的一切后果亦与本内容和本管理者无关。
本管理者保留随时更改或补充此免责声明的权利。一旦使用、复制、转载、发布、修改了本文内容,则视为您已接受此免责声明。否则后果自负。
本接口无公众号、无盈利、无引流、免费分享给小白使用,请勿轻信他人,谨防上当受骗。
[使用教程见Wiki](https://github.com/jadehh/TVSpider/wiki)
## TVBox互联网发布地址
[TV发布地址](https://github.com/FongMi/Release/tree/main/apk/release)
```bash
https://gh.con.sh/https://raw.githubusercontent.com/jadehh/TVSpider/js/tv_config.json
```
> 配置信息见js分支分支
## CatVodOpen
[CatVodOpen发布地址](https://github.com/catvod/CatVodOpen/releases)
> 注意使用Gitee或Github导入并设置为私有仓库<font color="red">CatVodOpen仅支持私有仓库</font>
V1.1.3版本以上
```bash
gitee://Token@gitee.com/jadehh_743/TVSpider/dist/index.js.md5
```
<font color="red">**改动**</font>
* quickjs改为nodejsproxy设置修改
* 在ios上无法使用local使用db替换local所有方法
* nodejs 的优势在于更加灵活
> 配置信息见dist分支
V1.1.2版本以下
```bash
gitee://Token@gitee.com/jadehh_743/TVSpider/js/open_config.json
```
> 配置信息见js分支分支
## config文件生成
```bash
python build.py --aliToken aliToken
```
> Token如果失效,需要重新获取阿里Token
>
> [阿里Token获取](https://alist.nn.ci/zh/guide/drivers/aliyundrive.html)
>
> nodejs 部分只生成代码需要手动build区分18+
## 直播源生成
> 见[jadehh/LiveSpider](https://github.com/jadehh/LiveSpider)
## 遇到的问题
* 玩偶姐姐播放不了,需要切换VPN节点
* m3u8遇到跨域的问题可以尝试使用代理来进行加载如果没有跨域使用代理会引起死循环
* 虎牙弹幕功能无法实现,现在并不支持WebSocket来监听弹幕
* SP360启用嗅探解析,CatVodOpen目前还不支持嗅探
* CatVodOpen Windows无法预览Jable和Doll图片,需要手动开启代理加载。
* TV影视暂不不支持哔哩哔哩DASH文件播放
* 老版本的CatVodOpen cfg参数类型为:string,TV参数类型为[object],所有需要区分,初始化的时候还是用this.cfgObj
## 特别说明
* 近期CatVodOpen更新移除了quickjs,导致无法使用,请尝试使用旧版本
* 或切换至nodejs目录下编译生成dist目录dist目录发布到dist分支下
* main分支用于代码测试(不包含任何配置信息)js分支发布支持quickjs爬虫配置信息dist分支发布支持nodejs爬虫配置信息
* 所有的配置信息都通过Github Actions发布通过创建tag来生成新的配置信息并自动发布
* fork仓库时去掉仅复制main分支的&#x2714;这样就可以fork所有的分支了
## 赞助
如果觉得此项目有用可以考虑赞助我喝杯咖啡感谢star❤
<img src="./resources/wechat.jpg" alt="微信" width="256" height="256" align="left" />

238
JN/CATJS/js/4kysxz.js Normal file
View File

@ -0,0 +1,238 @@
/*
* @File : 4kysxz.js.js
* @Author : jade
* @Date : 2024/1/24 16:47
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 4k高清网 (已失效)
*/
import {_} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class YSXZSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://4kysxz.top"
}
getAppName() {
return `4K高清网`
}
getName() {
return `🚄┃4K高清网┃🚄`
}
getJSName() {
return "4kysxz"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
}
async parseVodShortListFromDoc($) {
const cards = $('div.row.posts-wrapper >div > article > div.entry-media > div > a')
return _.map(cards, (n) => {
let id = n.attribs['href'];
let name = $($(n).find('img')[0]).attr('alt').replaceAll('<strong>', '').replaceAll('</strong>', '').split(' ')[0];
let pic = $($(n).find('img')[0]).attr('data-src');
return {
vod_id: id, vod_name: name, vod_pic: pic, vod_remarks: '',
};
});
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodElement = $("[class=\"entry-content u-text-format u-clearfix\"]")
let text = "";
for (const vodEle of vodElement) {
text = text + $(vodEle).text().replaceAll("", ":") + "\n"
}
vodDetail.vod_name = $($("[class=\"article-title\"]")).text()
vodDetail.vod_pic = $($("[class=\"entry-content u-text-format u-clearfix\"]")).find("img")[0].attribs["src"]
vodDetail.vod_area = Utils.getStrByRegex(/上映地区(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_director = Utils.getStrByRegex(/导演(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_actor = Utils.getStrByRegex(/主演(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_content = Utils.getStrByRegex(/剧情简介(.*?)\n/, text).replaceAll(":", "").replaceAll("·", "")
let actors = _.map($('div.entry-content.u-text-format.u-clearfix > div:nth-child(10) > div > span > span'), (n) => {
return $(n).text().split(' ')[0];
});
vodDetail.vod_actor = actors.join('/');
let directors = _.map($('div.entry-content.u-text-format.u-clearfix > div:nth-child(6) > div > span'), (n) => {
return $(n).text().split(' ')[0];
});
vodDetail.vod_director = directors.join('/');
vodDetail.vod_name = $('div.site-content > section > div > header > h1').text().trim();
let playUrlStr = '';
let playFromStr = '';
//高清直播
const cards = $('div.entry-content.u-text-format.u-clearfix > custag > ul > li > a');
if (cards.length > 0) {
let playUrls = _.map(cards, (n) => {
let playUrl = n.attribs['href'];
if (playUrl.indexOf('url=') > 0) {
playUrl = playUrl.split('url=')[1].split('&name')[0];
}
return $(n).text() + '$' + playUrl;
});
playUrlStr = playUrls.join('#');
playFromStr = '高清直播';
}
if (!this.catOpenStatus) {
//磁力链接
const tbs = $('loginshow > table');
let playFrom = '';
let nameUrls = [];
for (let i = 0; i < tbs.length; i++) {
if (i % 2 == 0) {
playFrom = $(tbs[i]).find('tbody > tr >td').text().replaceAll('WEB', '磁力');
} else if (i % 2 == 1) {
const tds = $(tbs[i]).find('tbody > tr >td');
let nameUrl = '';
for (let j = 0; j < tds.length; j++) {
if (j % 2 == 0) {
nameUrl = $(tds[j]).text().split('.')[0].split(' ')[0];
} else if (j % 2 == 1) {
nameUrl = nameUrl + '$' + $(tds[j]).text().split('【')[0];
nameUrls.push(nameUrl);
}
}
if (playFromStr.length > 0) {
playFromStr += '$$$';
playUrlStr += '$$$';
}
playFromStr += playFrom;
playUrlStr += nameUrls.join('#');
}
}
}
vodDetail.vod_play_from = playFromStr
vodDetail.vod_play_url = playUrlStr
return vodDetail
}
async setClasses() {
this.classes = []
this.classes.push(this.getTypeDic("首页", "/#"))
}
async getFilter(typeElements) {
let value_list = []
value_list.push({
"n": "全部", "v": "全部",
})
for (const typeElement of typeElements) {
value_list.push({
"n": typeElement.attribs["title"],
"v": typeElement.attribs["href"].split("/").slice(-1)[0].split(".")[0],
})
}
return [{"key": "1", "name": "类型", "value": value_list}]
}
async setFilterObj() {
let $ = await this.getHtml()
let navElements = $("[class=\"navbar-item menu-item-has-children\"]")
let extent_list = []
for (const navElement of navElements) {
let type_name = $($(navElement).find("a")[0]).text()
if (type_name.indexOf("影视") > -1) {
let extend_dic = {"key": "1", "name": type_name, "value": []}
let type_elements = $($(navElement).find("ul")).find("a")
for (const type_element of type_elements) {
extend_dic["value"].push({"n": $(type_element).text(), "v": type_element.attribs["href"]})
}
extent_list.push(extend_dic)
}
}
this.filterObj["/#"] = extent_list
}
async setCategory(tid, pg, filter, extend) {
let url;
if (extend["1"] === undefined) {
url = this.siteUrl + tid
} else {
if (extend["1"].indexOf("category") > -1) {
url = this.siteUrl + extend["1"].split(".")[0] + "_" + pg + ".html"
} else {
url = this.siteUrl + extend["1"]
}
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
const $ = await this.getHtml(id);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + '/search.php?q=' + wd)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
let spider = new YSXZSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

299
JN/CATJS/js/aiyingshi.js Normal file
View File

@ -0,0 +1,299 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/aiyingshi.js
* @Description: 爱影视爬虫类
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class AiYingShiSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://aiyingshis.com';
}
getName() {
return "🚀‍┃爱影视┃🚀"
}
getAppName() {
return "爱影视"
}
getJSName() {
return "aiyingshi"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
let pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src')
if (pic.indexOf("img.php?url=") > 0) {
pic = pic.split("img.php?url=")[1]
}else if (pic.indexOf("https:") === -1 && pic.indexOf("http:") === -1){
pic = "https:" + pic
}
vodShort.vod_pic = pic
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
if (vodShort.vod_name !== undefined){
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($("[class=\"video-cover\"]")).find(".lazyload")[0].attribs["data-src"]
let video_info_list = $($(".video-info-aux")).text().replaceAll("\t","").split("\n")
let type_list = []
for (const video_info of video_info_list){
if (!_.isEmpty(video_info.replaceAll(" ","").replaceAll("/",""))){
type_list.push(video_info.replaceAll(" ","").replaceAll("/",""))
}
}
vodDetail.type_name = type_list.slice(0,2).join("*")
let video_items = $("[class=\"video-info-items\"]")
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const vidoe_info_actor of vidoe_info_actor_list) {
actor_list.push(vidoe_info_actor.children[0].data)
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = type_list[2]
vodDetail.vod_remarks = $($(video_items[3]).find(".video-info-item")).text()
vodDetail.vod_content = $($(video_items[5]).find(".video-info-item")).text()
vodDetail.vod_area = type_list[3]
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "").replaceAll("\t","").replaceAll("\n","")
let playElements = $($("[class=\"module-tab-content\"]")[0]).find("span")
let urlElements = $("[class=\"module-list module-player-list tab-list sort-list \"]")
let form_list = []
for (const playerElement of playElements){
form_list.push($(playerElement).text())
}
let play_url_list = []
for (const urlElement of urlElements){
let playUrlElements = $($(urlElement).find("[class=\"sort-item\"]")).find("a")
let vodItems = []
for (const playUrlElement of playUrlElements){
let name = $(playUrlElement).text()
let url = playUrlElement.attribs["href"]
let play_url = name + "$" + url
vodItems.push(play_url)
}
play_url_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = form_list.join('$$$');
vodDetail.vod_play_url = _.values(play_url_list).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src']
vodShort.vod_remarks = $($(item).find(".video-serial")[0]).text();
vod_list.push(vodShort);
}
return vod_list
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $($("[class=\"nav-menu-items\"]")[0]).find("li")
for (const element of elements.slice(0,6)) {
let type_name = $($(element).find("span")).text()
if (type_name !== "首页"){
let type_id = $(element).find("a")[0].attribs["href"].split("/").slice(-1)[0].split(".")[0]
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
}
async getFilter($) {
let elements = $("[class=\"scroll-content\"]").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
if ($($(elements[i]).find("a")[0]).text() === "全部类型"){
extend_dic["value"].push({"n": $(ele).text(), "v":ele.attribs["href"].split("/").slice(-1)[0].split(".")[0]})
}else{
extend_dic["value"].push({"n": $(ele).text(), "v":$(ele).text()})
}
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/vodshow/id/${type_id}.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
getExtend(value,defaultvalue,key = ""){
if (value !== undefined && value !== "0"){
return key + value
}else{
return defaultvalue
}
}
async getCateUrl(tid,pg,extend){
tid = this.getExtend(extend["1"],tid)
let area = this.getExtend(extend["2"],"","/area/")
let lanuage = this.getExtend(extend["3"],"","/lang/")
let year = this.getExtend(extend["4"],"","/year/")
let letter = this.getExtend(extend["5"],"","/letter/")
let time = this.getExtend(extend['6'],"","/by/")
return this.siteUrl + `/vodshow${time}${area}/id/${tid}${lanuage}${letter}${year}/page/${pg}.html`
}
async setCategory(tid, pg, filter, extend) {
let reqUrl = await this.getCateUrl(tid,pg,extend)
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
let html = await this.fetch(this.siteUrl + id,null,this.getHeader())
if (!_.isEmpty(html)){
let player_str = Utils.getStrByRegex(/<script type="text\/javascript">var player_aaaa=(.*?)<\/script>/,html)
let play_dic = JSON.parse(player_str)
this.playUrl = play_dic["url"]
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/vodsearch/wd/${wd}.html`
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new AiYingShiSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,proxy:proxy
};
}
export {spider}

229
JN/CATJS/js/alipansou.js Normal file
View File

@ -0,0 +1,229 @@
/*
* @File : alipansou.js
* @Author : jade
* @Date : 2024/1/18 13:20
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 猫狸盘搜
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import { detailContent,initCloud,playContent,getHeaders } from "../lib/cloud.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class GitCafeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.alipansou.com"
}
getHeaders(id) {
let headers = this.getHeader()
headers["Referer"] = this.siteUrl + id
headers["_bid"] = "6d14a5dd6c07980d9dc089a693805ad8"
headers["Cookie"] = "_egg=70463dec0ec843b682ce18c36ec9ce91e"
return headers
}
getName() {
return "😸┃阿里猫狸┃😸"
}
getAppName() {
return "阿里猫狸"
}
getJSName() {
return "alipansou"
}
getType() {
return 3
}
getHeader() {
return {
"User-Agent":Utils.CHROME,
"Connection": "keep-alive"
}
}
async getContentHtml() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
return load(html)
}
}
async spiderInit() {
this.content_html = await this.getContentHtml()
}
async init(cfg) {
await this.spiderInit()
await super.init(cfg);
await initCloud(this.cfgObj);
}
async parseClassFromDoc($) {
let tap_elemets = $($("[id=\"app\"]")[0]).find("van-tab")
let index = 0
for (const tap_element of tap_elemets) {
let type_name = tap_element.attribs["title"]
if (type_name.indexOf("热搜") === -1 && type_name !== "游戏" && type_name !== "小说") {
this.classes.push({"type_name": type_name, "type_id": index})
}
index = index + 1
}
}
async parseVodShortListFromDoc(doc) {
let vod_list = []
let elements = this.content_html(doc).find("a")
for (const element of elements) {
let vodShort = new VodShort()
vodShort.vod_id = element.attribs["href"]
vodShort.vod_name = this.content_html(element).text().split(".").slice(-1)[0]
vod_list.push(vodShort)
}
return vod_list
}
async getAliUrl(id) {
let url = this.siteUrl + id.replace("/s/", "/cv/")
let headers = this.getHeaders(id)
let content = await req(url,{postType:"get",headers:headers,redirect:2})
await this.jadeLog.debug(`回复内容为:${JSON.stringify(content)}`)
// let url = await this.fetch(this.siteUrl + id.replace("/s/", "/cv/"), null, headers, true)
return content.headers.location
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail();
vodDetail.vod_name = obj["name"]
vodDetail.vod_remarks = obj["remarks"]
let ali_url = await this.getAliUrl(obj["id"])
await this.jadeLog.debug(`阿里分享链接为:${ali_url}`)
if (!_.isEmpty(ali_url)) {
let playVod = await detailContent([ali_url],vodDetail.type_name)
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let elements = $($($("[id=\"app\"]")[0]).find("van-row")).find("a")
let vod_list = []
for (const element of elements) {
let id = element.attribs["href"]
let matches = id.match(/(\/s\/[^"])/);
if (!_.isEmpty(matches) && id.indexOf("https") === -1) {
let text = $(element).text().replaceAll("\n", "").replaceAll(" ", "")
if (text.indexOf("时间") > -1 && text.indexOf("文件夹") > -1) {
let textList = text.split("时间")
let vodShort = new VodShort()
vodShort.vod_name = textList[0]
vodShort.vod_remarks = textList[1].split("格式")[0].replaceAll(":", "").replaceAll(" ", "").replaceAll("", "").replaceAll(" ", "")
vodShort.vod_id = JSON.stringify({
"name": vodShort.vod_name, "remarks": vodShort.vod_remarks, "id": id
})
vod_list.push(vodShort)
}
}
}
return vod_list
}
async setClasses() {
await this.parseClassFromDoc(this.content_html)
}
async setHomeVod() {
let tap_elemets = this.content_html(this.content_html("[id=\"app\"]")[0]).find("van-tab")
this.homeVodList = await this.parseVodShortListFromDoc(tap_elemets[0])
}
async setDetail(id) {
if (id.indexOf("search") > -1) {
let url = this.siteUrl + "/search"
let params = {"k":decodeURIComponent(id.split("search?k=").slice(-1)[0]) }
let html = await this.fetch(url, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let vod_list = await this.parseVodShortListFromDocBySearch($)
if (vod_list.length > 0) {
id = vod_list[0]["vod_id"]
} else {
id = ""
}
}
}
if (!_.isEmpty(id)) {
let json_content = JSON.parse(id)
this.vodDetail = await this.parseVodDetailfromJson(json_content)
}
}
async setCategory(tid, pg, filter, extend) {
let tap_elemets = this.content_html(this.content_html("[id=\"app\"]")[0]).find("van-tab")
this.vodList = await this.parseVodShortListFromDoc(tap_elemets[parseInt(tid)])
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search"
let params = {"k": wd}
let html = await this.fetch(url, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
let spider = new GitCafeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -0,0 +1,227 @@
/*
* @File : aliyunpanshare.js
* @Author : jade
* @Date : 2024/1/26 13:06
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 阿里云盘分享
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import { detailContent,initCloud,playContent,getHeaders} from "../lib/cloud.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
let remark_list = ["4k", "4K"]
class AliyunpanShare extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.alypw.com';
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj);
}
getName() {
return "🥏‍┃阿里云盘分享┃🥏‍"
}
getAppName() {
return "阿里云盘分享"
}
getJSName() {
return "aliyunpanshare"
}
getType() {
return 3
}
getRemarks(name, title) {
if (_.isEmpty(name)) {
for (const remark of remark_list) {
if (title.indexOf(remark) > -1) {
return remark
}
}
} else {
return name
}
}
parseVodName(name) {
let vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?) /, name)
if (name.indexOf("合集") > -1) {
return ""
}
if (_.isEmpty(vod_name)) {
vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?)/, name)
}
if (vod_name.indexOf("[") > -1) {
vod_name = vod_name.split("[")[0]
}
if (vod_name.indexOf("【") > -1) {
vod_name = vod_name.split("【")[0]
}
if (vod_name === "4K") {
return ""
}
return vod_name
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"hometab\"]").find("[class=\"box\"]")).find("li")
for (const vodElement of vodElements) {
let ele = $(vodElement).find("[class=\"imgr\"]")[0]
let vodShort = new VodShort();
vodShort.vod_id = $(ele).find("a")[0].attribs["href"]
let name = $(ele).find("a")[0].attribs["title"]
vodShort.vod_name = this.parseVodName(name)
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["src"]
vodShort.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let mainElement = $("[class=\"main container\"]")
let vodElements = $($(mainElement).find("[class=\"list\"]")).find("li")
if (vodElements.length === 0) {
vodElements = $(mainElement).find("li")
}
for (const vodElement of vodElements) {
let name = $(vodElement).find("img")[0].attribs["alt"].replaceAll("<strong>", "").replaceAll("</strong>", "")
let vodShort = new VodShort();
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
vodShort.vod_name = this.parseVodName(name)
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["src"]
vodShort.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
if (!_.isEmpty(vodShort.vod_name)) {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let mainElements = $("[class=\"mainl\"]")
let name = $($(mainElements).find("[class=\"title\"]")[0]).text()
let vodDetail = new VodDetail();
vodDetail.vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?) /, name)
vodDetail.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
let articleElement = $(mainElements).find("[class=\"article_content\"]")
vodDetail.vod_pic = $(articleElement).find("p>img")[0].attribs["src"]
let articleElements = $(articleElement).find("p")
let articleContent = ""
for (const articleEle of articleElements) {
articleContent = articleContent + $(articleEle).text() + "\n"
}
let share_ali_url_list = []
let share_url_list = Utils.getStrByRegex(Utils.patternAli, articleContent).split("\n")
for (const share_url of share_url_list) {
let matches = share_url.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_ali_url_list.push(matches[1])
let quarkMatches = share_url.match(Utils.patternQuark);
if (!_.isEmpty(quarkMatches)) share_ali_url_list.push(quarkMatches[1])
}
let playVod = await detailContent([share_ali_url_list])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
vodDetail.type_name = Utils.getStrByRegex(/标签(.*?)\n/, articleContent).replaceAll("", "")
vodDetail.vod_content = Utils.getStrByRegex(/描述(.*?)\n/, articleContent).replaceAll("", "")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let typeElements = $("[id^='navbar-category']").find("a")
let key_list = ["影", "剧", "4K", "视", "音", "演", "动漫"]
for (const typeElement of typeElements) {
let type_name = $(typeElement).text()
let type_id = typeElement.attribs["href"]
let is_show = false
for (const key of key_list) {
if (type_name.indexOf(key) > -1) {
is_show = true
}
}
if (is_show) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let cateUrl = tid.split(".html")[0] + "_" + pg + ".html"
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
async setSearch(wd, quick) {
let url = this.siteUrl + `/search.php?q=${wd}`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new AliyunpanShare()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

183
JN/CATJS/js/asianx.js Normal file
View File

@ -0,0 +1,183 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/asianx.js
* @Description: asianx
*/
import {Spider} from "./spider.js";
import {Crypto, _, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class AsianXSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://cn.asianx.tube/"
}
getName() {
return "🔞┃海外宅┃🔞"
}
getAppName() {
return "海外宅"
}
getJSName() {
return "asianx"
}
getType() {
return 3
}
async getFilter($) {
let navElements = $($("[class=\"menu m-0 mb-2 mb-lg-0\"]")).find("a").slice(6)
let extend_dic = {"key": "1", "name": "分类", "value": [{"n": "全部", "v": "全部"}]}
for (const navElement of navElements) {
let type_name = $($(navElement).find("span")).text()
let type_id = navElement.attribs["href"]
extend_dic["value"].push({"n": type_name, "v": type_id})
}
return [extend_dic]
}
async parseVodShortListFromDoc($,is_home=false) {
let vod_list = []
let vodShortElements;
if (is_home){
vodShortElements = $($("[class=\"gal-box\"]")).slice(12)
}else{
vodShortElements = $($("[class=\"gal-box\"]"))
}
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElements = $(vodShortElement).find("a")
vodShort.vod_id = vodElements[0].attribs["href"]
vodShort.vod_pic = $(vodElements[0]).find("img")[0].attribs["data-src"]
vodShort.vod_name = vodElements[1].attribs["title"]
vodShort.vod_remarks = $($(vodShortElement).find("[class=\"meta text-muted text-truncate\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc(html) {
let vodDetail = new VodDetail();
let content = Utils.getStrByRegex(/<script type="application\/ld\+json">(.*?)<\/script>/,html)
let content_json = JSON.parse(content)
let textList = content_json["name"].split(" ")
vodDetail.vod_name = textList[0]
vodDetail.vod_play_from = ["未加密线路","加密线路"].join("$$$")
let playUrl1 = content_json["contentUrl"]
let playUrl2 = content_json["embedUrl"]
vodDetail.vod_play_url = [`${textList[0]}$${playUrl1}`,`${textList[0]}$${playUrl2}`].join("$$$")
vodDetail.vod_remarks = content_json["uploadDate"]
vodDetail.vod_content = content_json["description"]
return vodDetail
}
async setClasses() {
this.classes = []
this.classes.push({"type_name": "首页", "type_id": "/"})
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let navElements = $($("[class=\"menu m-0 mb-2 mb-lg-0\"]")).find("a").slice(0, 5)
for (const navElement of navElements) {
let type_name = $($(navElement).find("span")).text()
let type_id = navElement.attribs["href"]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
this.filterObj[this.classes[0].type_id] = await this.getFilter($)
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($,true)
}
}
getExtend(pg,extend){
if (extend["1"] !== undefined){
if (extend["1"] === "全部"){
return this.siteUrl
}else{
return this.siteUrl + extend["1"] + "/" + pg
}
}else{
return this.siteUrl
}
}
async setDetail(id) {
let html = await this.fetch(id,null,this.getHeader())
if (!_.isEmpty(html)){
this.vodDetail = await this.parseVodDetailFromDoc(html)
}
}
async setCategory(tid, pg, filter, extend) {
let url;
if (tid === "/") {
url = this.getExtend(pg,extend)
} else {
url = this.siteUrl + tid + "/" + pg
}
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($,false)
}
}
}
let spider = new AsianXSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}

258
JN/CATJS/js/audiomack.js Normal file
View File

@ -0,0 +1,258 @@
/*
* @File : audiomack.js
* @Author : jade
* @Date : 2024/1/31 15:56
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 音乐之声
*/
import {Spider} from "./spider.js";
import {BookShort} from "../lib/book.js";
import {Crypto} from "../lib/cat.js";
function u(e) {
(this._parameters = {}), this._loadParameters(e || {});
}
u.prototype = {
_loadParameters: function (e) {
e instanceof Array ? this._loadParametersFromArray(e) : "object" == typeof e && this._loadParametersFromObject(e);
}, _loadParametersFromArray: function (e) {
var n;
for (n = 0; n < e.length; n++) this._loadParametersFromObject(e[n]);
}, _loadParametersFromObject: function (e) {
var n;
for (n in e) if (e.hasOwnProperty(n)) {
var r = this._getStringFromParameter(e[n]);
this._loadParameterValue(n, r);
}
}, _loadParameterValue: function (e, n) {
var r;
if (n instanceof Array) {
for (r = 0; r < n.length; r++) {
var i = this._getStringFromParameter(n[r]);
this._addParameter(e, i);
}
0 == n.length && this._addParameter(e, "");
} else this._addParameter(e, n);
}, _getStringFromParameter: function (e) {
var n = e || "";
try {
("number" == typeof e || "boolean" == typeof e) && (n = e.toString());
} catch (e) {
}
return n;
}, _addParameter: function (e, n) {
this._parameters[e] || (this._parameters[e] = []), this._parameters[e].push(n);
}, get: function () {
return this._parameters;
},
};
function _decode(e) {
return e ? decodeURIComponent(e) : "";
}
function getNormalizedParams(parameters) {
const sortedKeys = [];
const normalizedParameters = [];
for (let e in parameters) {
sortedKeys.push(_encode(e));
}
sortedKeys.sort();
for (let idx = 0; idx < sortedKeys.length; idx++) {
const e = sortedKeys[idx];
var n, r, i = _decode(e), a = parameters[i];
for (a.sort(), n = 0; n < a.length; n++) (r = _encode(a[n])), normalizedParameters.push(e + "=" + r);
}
return normalizedParameters.join("&");
}
function nonce(e = 10) {
let n = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", r = "";
for (let i = 0; i < e; i++) r += n.charAt(Math.floor(Math.random() * n.length));
return r;
}
function _encode(e) {
return e ? encodeURIComponent(e)
.replace(/[!'()]/g, escape)
.replace(/\*/g, "%2A") : "";
}
function getSignature(method, urlPath, params, secret = "f3ac5b086f3eab260520d8e3049561e6") {
urlPath = urlPath.split("?")[0];
urlPath = urlPath.startsWith("http") ? urlPath : "https://api.audiomack.com/v1" + urlPath;
const r = new u(params).get();
const httpMethod = method.toUpperCase();
const normdParams = getNormalizedParams(r);
const l = _encode(httpMethod) + "&" + _encode(urlPath) + "&" + _encode(normdParams);
return Crypto.HmacSHA1(l, secret + "&").toString(Crypto.enc.Base64);
}
class AudioMackSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.audiomack.com/v1";
}
getName() {
return "🎵┃音声┃🎵"
}
getAppName() {
return "音声"
}
getJSName() {
return "audiomack"
}
getType() {
return 10
}
async parseVodShortListFromJson(obj) {
let books = []
for (const data of obj["results"]["playlists"]) {
let bookShort = new BookShort()
bookShort.book_id = data["id"]
bookShort.book_pic = data["image"]
bookShort.book_name = data["title"]
bookShort.book_remarks = data["description"]
books.push(bookShort)
}
return books
}
async setClasses() {
this.classes = [{"type_name": "推荐榜单", "type_id": "最近更新"}]
const genres = [{
title: "All Genres", url_slug: "null",
}, {
title: "Afrosounds", url_slug: "afrobeats",
}, {
title: "Hip-Hop/Rap", url_slug: "rap",
}, {
title: "Latin", url_slug: "latin",
}, {
title: "Caribbean", url_slug: "caribbean",
}, {
title: "Pop", url_slug: "pop",
}, {
title: "R&B", url_slug: "rb",
}, {
title: "Gospel", url_slug: "gospel",
}, {
title: "Electronic", url_slug: "electronic",
}, {
title: "Rock", url_slug: "rock",
}, {
title: "Punjabi", url_slug: "punjabi",
}, {
title: "Country", url_slug: "country",
}, {
title: "Instrumental", url_slug: "instrumental",
}, {
title: "Podcast", url_slug: "podcast",
},];
for (const genre of genres) {
this.classes.push(this.getTypeDic(genre["title"], genre["url_slug"]))
}
}
/*
* */
async setHomeVod() {
let tag = {id: "34", title: "What's New", url_slug: "whats-new"};
const params = {
featured: "yes",
limit: 20,
oauth_consumer_key: "audiomack-js",
oauth_nonce: nonce(32),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Math.round(Date.now() / 1e3),
oauth_version: "1.0",
page: 1,
slug: tag.url_slug,
};
const oauth_signature = getSignature("GET", "/playlist/categories", params);
let url = this.siteUrl + "/playlist/categories"
let content = await this.fetch(url, Object.assign(Object.assign({}, params), {oauth_signature}), this.getHeader());
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setCategory(tid, pg, filter, extend) {
let partialUrl;
if (tid === "null"){
partialUrl = `/music/page/${pg}`;
}else{
partialUrl = `/music/${tid}/page/${pg}`;
}
const url = `https://api.audiomack.com/v1${partialUrl}`;
const params = {
oauth_consumer_key: "audiomack-js",
oauth_nonce: nonce(32),
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: Math.round(Date.now() / 1e3),
oauth_version: "1.0",
type: "song",
};
const oauth_signature = getSignature("GET", partialUrl, params);
const results = await this.fetch(url, Object.assign(Object.assign({}, params), {oauth_signature}),this.getHeader())
let x = 0
}
}
let spider = new AudioMackSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

View File

@ -0,0 +1,85 @@
/*
* @File : base_spider.js.js
* @Author : jade
* @Date : 2024/1/4 14:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {JadeLogging} from "../lib/log.js";
import {Result, SpiderInit} from "../lib/spider_object.js";
const JadeLog = new JadeLogging(getAppName(), "DEBUG")
let result = new Result()
let CatOpenStatus = false
function getName() {
return `🍥┃基础┃🍥`
}
function getAppName() {
return `基础`
}
async function init(cfg) {
let obj = await SpiderInit(cfg)
CatOpenStatus = obj.CatOpenStatus
// 读取缓存
}
async function home(filter) {
await JadeLog.info("正在解析首页类别", true)
try{
await JadeLog.debug(`首页类别内容为:${result.home()}`)
await JadeLog.info("首页类别解析完成", true)
return result.homeVod()
}catch (e){
await this.jadeLog.error(`首页内容解析失败,失败原因为:{e}`)
}
}
async function homeVod() {
let vod_list = []
if (!CatOpenStatus) {
await JadeLog.info("正在解析首页内容")
}
await JadeLog.debug(`首页内容为:${JSON.stringify({"list": vod_list})}`)
return JSON.stringify({"list": vod_list})
}
async function category(tid, pg, filter, extend) {
let url = ""
await JadeLog.info(`正在解析分类页面,tid = ${tid},pg = ${pg},filter = ${filter},extend = ${JSON.stringify(extend)},url = ${url}`)
}
async function detail(id) {
return JSON.stringify({})
}
async function play(flag, id, flags) {
return JSON.stringify({});
}
async function search(wd, quick) {
let url = ""
await JadeLog.info(`正在解析搜索页面,关键词为 = ${wd},quick = ${quick},url = ${url}`)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}

571
JN/CATJS/js/bilibili.js Normal file
View File

@ -0,0 +1,571 @@
/*
* @File : bilibili.js
* @Author : jade
* @Date : 2024/4/3 9:27
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 哔哩哔哩
*/
import {Spider} from "./spider.js";
import * as Utils from "../lib/utils.js";
import {Crypto, _, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class BilibiliSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.bilibili.com"
this.apiUrl = "https://api.bilibili.com"
this.cookie = ""
this.bili_jct = '';
this.is_login = false
this.is_vip = false
this.vod_audio_id = {
30280: 192000,
30232: 132000,
30216: 64000,
};
this.vod_codec = {
// 13: 'AV1',
12: 'HEVC',
7: 'AVC',
};
this.play_url_obj = {
80: "1080P 高清",
64: "720P 高清",
32: "420P 清晰",
16: "360P 流畅"
}
}
getHeader() {
const headers = super.getHeader();
if (!_.isEmpty(this.cookie)) {
headers["cookie"] = this.cookie;
}
return headers;
}
initCookie(cookie) {
this.cookie = cookie
if (cookie.includes('bili_jct')) {
this.bili_jct = cookie.split('bili_jct=')[1].split(";")[0];
}
}
async spiderInit(Req) {
this.is_login = await this.checkLogin()
if (this.is_login) {
await this.jadeLog.info("哔哩哔哩登录成功", true)
} else {
await this.jadeLog.error("哔哩哔哩登录失败", true)
}
if (Req === null) {
// dash mpd 代理
this.js2Base = await js2Proxy(true, this.siteType, this.siteKey, 'dash/', this.getHeader());
} else {
this.js2Base = await js2Proxy(Req, "dash", this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.initCookie(this.cfgObj["cookie"])
await this.spiderInit(null)
this.danmuStaus = true
}
getName() {
return "🏰┃哔哩哔哩┃🏰"
}
getAppName() {
return "哔哩哔哩"
}
getJSName() {
return "bilibili"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"channel-items__left\"]").find("a")
for (const navElement of navElements) {
this.classes.push(this.getTypeDic($(navElement).text(), $(navElement).text()))
}
if (!_.isEmpty(this.bili_jct) && this.is_login) {
this.classes.push(this.getTypeDic("历史记录", "历史记录"))
}
}
async getFilter($) {
return [
{
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'},
],
},
];
}
async setFilterObj() {
for (const typeDic of this.classes) {
let type_id = typeDic["type_name"]
if (type_id !== "最近更新" && type_id !== "历史记录") {
this.filterObj[type_id] = await this.getFilter()
}
}
}
getFullTime(numberSec) {
let totalSeconds = '';
try {
let timeParts = numberSec.split(":");
let min = parseInt(timeParts[0]);
let sec = parseInt(timeParts[1]);
totalSeconds = min * 60 + sec;
} catch (e) {
totalSeconds = parseInt(numberSec);
}
if (isNaN(totalSeconds)) {
return '无效输入';
}
if (totalSeconds >= 3600) {
const hours = Math.floor(totalSeconds / 3600);
const remainingSecondsAfterHours = totalSeconds % 3600;
const minutes = Math.floor(remainingSecondsAfterHours / 60);
const seconds = remainingSecondsAfterHours % 60;
return `${hours}小时 ${minutes}分钟 ${seconds}`;
} else {
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}分钟 ${seconds}`;
}
}
removeTags(input) {
return input.replace(/<[^>]*>/g, '');
}
async parseVodShortListFromJson(objList) {
let vod_list = []
for (const vodData of objList) {
let vodShort = new VodShort()
vodShort.vod_id = vodData["bvid"]
if (vodData.hasOwnProperty("rcmd_reason")) {
vodShort.vod_remarks = vodData["rcmd_reason"]["content"]
} else {
vodShort.vod_remarks = this.getFullTime(vodData["duration"])
}
vodShort.vod_name = this.removeTags(vodData["title"])
let imageUrl = vodData["pic"];
if (imageUrl.startsWith('//')) {
imageUrl = 'https:' + imageUrl;
}
vodShort.vod_pic = imageUrl
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj, bvid) {
let cd = this.getFullTime(obj["duration"]);
const aid = obj.aid;
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["title"]
vodDetail.vod_pic = obj["pic"]
vodDetail.type_name = obj["tname"]
vodDetail.vod_remarks = cd
vodDetail.vod_content = obj["desc"]
let params = {"avid": aid, "cid": obj["cid"], "qn": "127", "fnval": 4048, "fourk": 1}
let playUrlDatas = JSON.parse(await this.fetch(this.apiUrl + "/x/player/playurl", params, this.getHeader()));
let playUrldDataList = playUrlDatas["data"];
const accept_quality = playUrldDataList["accept_quality"];
const accept_description = playUrldDataList["accept_description"];
const qualityList = [];
const descriptionList = [];
for (let i = 0; i < accept_quality.length; i++) {
if (!this.is_vip) {
if (this.is_login) {
if (accept_quality[i] > 80) continue;
} else {
if (accept_quality[i] > 32) continue;
}
}
descriptionList.push(Utils.base64Encode(accept_description[i]));
qualityList.push(accept_quality[i]);
}
let treeMap = {};
const jSONArray = obj["pages"];
let playList = [];
for (let j = 0; j < jSONArray.length; j++) {
const jSONObject6 = jSONArray[j];
const cid = jSONObject6.cid;
const playUrl = j + '$' + aid + '+' + cid + '+' + qualityList.join(':') + '+' + descriptionList.join(':');
playList.push(playUrl);
}
if (this.catOpenStatus) {
for (let quality of qualityList) {
treeMap[`dash - ${this.play_url_obj[quality]}`] = playList.join("#")
}
} else {
await this.jadeLog.warning("TV暂不支持Dash播放")
}
for (let quality of qualityList) {
treeMap[`mp4 - ${this.play_url_obj[quality]}`] = playList.join("#")
}
let relatedParams = {"bvid": bvid}
const relatedData = JSON.parse(await this.fetch(this.apiUrl + "/x/web-interface/archive/related", relatedParams, this.getHeader())).data;
playList = [];
for (let j = 0; j < relatedData.length; j++) {
const jSONObject6 = relatedData[j];
const cid = jSONObject6.cid;
const title = jSONObject6.title;
const aaid = jSONObject6.aid;
const playUrl = title + '$' + aaid + '+' + cid + '+' + qualityList.join(':') + '+' + descriptionList.join(':');
playList.push(playUrl);
}
if (this.catOpenStatus) {
for (let quality of qualityList) {
treeMap["相关" + ` - ${this.play_url_obj[quality]}`] = playList.join("#")
}
} else {
await this.jadeLog.warning("TV暂不支持相关播放")
}
vodDetail.vod_play_from = Object.keys(treeMap).join("$$$");
vodDetail.vod_play_url = Object.values(treeMap).join("$$$");
return vodDetail
}
async setHomeVod() {
let params = {"ps": 20}
let content = await this.fetch(this.apiUrl + "/x/web-interface/popular", params, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content)["data"]["list"])
}
async setDetail(id) {
const detailUrl = this.apiUrl + "/x/web-interface/view";
let params = {"bvid": id}
const detailData = JSON.parse(await this.fetch(detailUrl, params, this.getHeader())).data
// 记录历史
if (!_.isEmpty(this.bili_jct)) {
const historyReport = this.apiUrl + '/x/v2/history/report';
let dataPost = {
aid: detailData.aid,
cid: detailData.cid,
csrf: this.bili_jct,
}
await this.post(historyReport, dataPost, this.getHeader(), "form");
}
this.vodDetail = await this.parseVodDetailfromJson(detailData, id)
}
findKeyByValue(obj, value) {
for (const key in obj) {
if (obj[key] === value) {
return key;
}
}
return null;
}
async setPlay(flag, id, flags) {
const ids = id.split('+');
const aid = ids[0];
const cid = ids[1];
let quality_name = flag.split(" - ")[1]
let quality_id = this.findKeyByValue(this.play_url_obj, quality_name)
this.danmuUrl = this.apiUrl + '/x/v1/dm/list.so?oid=' + cid;
this.result.header = this.getHeader()
if (flag.indexOf("dash") > -1 || flag.indexOf('相关') > -1) {
// dash mpd 代理
if (this.catOpenStatus) {
this.playUrl = this.js2Base + Utils.base64Encode(aid + '+' + cid + '+' + quality_id)
}
} else if (flag.indexOf('mp4') > -1) {
// 直链
const url = this.apiUrl + `/x/player/playurl`;
let params = {"avid": aid, "cid": cid, "qn": parseInt(quality_id), "fourk": "1"}
const resp = JSON.parse(await this.fetch(url, params, this.getHeader()));
const data = resp.data;
this.playUrl = data["durl"][0].url;
} else {
// 音频外挂
let urls = [];
let audios = [];
const url = this.siteUrl + "/x/player/playurl"
let params = {"avid": aid, "cid": cid, "qn": quality_id, "fnval": 4048, "fourk": 1};
let resp = JSON.parse(await this.fetch(url, params, this.getHeader()));
const dash = resp.data.dash;
const video = dash.video;
const audio = dash.audio;
for (let j = 0; j < video.length; j++) {
const dashjson = video[j];
if (dashjson.id === quality_id) {
for (const key in this.vod_codec) {
if (dashjson["codecid"] === key) {
urls.push(Utils.base64Decode(quality_id) + ' ' + this.vod_codec[key], dashjson["baseUrl"]);
}
}
}
}
if (audios.length === 0) {
for (let j = 0; j < audio.length; j++) {
const dashjson = audio[j];
for (const key in this.vod_audio_id) {
if (dashjson.id === key) {
audios.push({
title: _.floor(parseInt(this.vod_audio_id[key]) / 1024) + 'Kbps',
bit: this.vod_audio_id[key],
url: dashjson["baseUrl"],
});
}
}
}
audios = _.sortBy(audios, 'bit');
}
this.playUrl = urls
this.extra = {"audio": audios}
}
}
async checkLogin() {
let result = JSON.parse(await this.fetch('https://api.bilibili.com/x/web-interface/nav', null, this.getHeader()));
this.is_vip = result["data"]["vipStatus"]
return result["data"]["isLogin"]
}
async setCategory(tid, pg, filter, extend) {
let page;
if (parseInt(pg) < 1) {
page = 1;
} else {
page = parseInt(pg)
}
if (Object.keys(extend).length > 0 && extend.hasOwnProperty('tid') && extend['tid'].length > 0) {
tid = extend['tid'];
}
let url = '';
url = this.apiUrl + `/x/web-interface/search/type?search_type=video&keyword=${encodeURIComponent(tid)}`;
if (Object.keys(extend).length > 0) {
for (const k in extend) {
if (k === 'tid') {
continue;
}
url += `&${encodeURIComponent(k)}=${encodeURIComponent(extend[k])}`;
}
}
url += `&page=${encodeURIComponent(page)}`;
if (tid === "历史记录") {
url = this.apiUrl + "/x/v2/history?pn=" + page;
}
const data = JSON.parse(await this.fetch(url, null, this.getHeader())).data;
let items = data.result;
if (tid === "历史记录") {
items = data;
}
this.vodList = await this.parseVodShortListFromJson(items)
}
async setSearch(wd, quick, pg) {
const ext = {
duration: '0',
};
let page = parseInt(pg)
const limit = 20
let resp = JSON.parse(await this.category(wd, page, true, ext));
this.vodList = resp["list"]
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
getDashMedia(dash) {
try {
let qnid = dash.id;
const codecid = dash["codecid"];
const media_codecs = dash["codecs"];
const media_bandwidth = dash["bandwidth"];
const media_startWithSAP = dash["startWithSap"];
const media_mimeType = dash.mimeType;
const media_BaseURL = dash["baseUrl"].replace(/&/g, '&amp;');
const media_SegmentBase_indexRange = dash["SegmentBase"]["indexRange"];
const media_SegmentBase_Initialization = dash["SegmentBase"]["Initialization"];
const mediaType = media_mimeType.split('/')[0];
let media_type_params = '';
if (mediaType === 'video') {
const media_frameRate = dash.frameRate;
const media_sar = dash["sar"];
const media_width = dash.width;
const media_height = dash.height;
media_type_params = `height='${media_height}' width='${media_width}' frameRate='${media_frameRate}' sar='${media_sar}'`;
} else if (mediaType === 'audio') {
for (const key in this.vod_audio_id) {
if (qnid === key) {
const audioSamplingRate = this.vod_audio_id[key];
media_type_params = `numChannels='2' sampleRate='${audioSamplingRate}'`;
}
}
}
qnid += '_' + codecid;
return `<AdaptationSet lang="chi">
<ContentComponent contentType="${mediaType}"/>
<Representation id="${qnid}" bandwidth="${media_bandwidth}" codecs="${media_codecs}" mimeType="${media_mimeType}" ${media_type_params} startWithSAP="${media_startWithSAP}">
<BaseURL>${media_BaseURL}</BaseURL>
<SegmentBase indexRange="${media_SegmentBase_indexRange}">
<Initialization range="${media_SegmentBase_Initialization}"/>
</SegmentBase>
</Representation>
</AdaptationSet>`;
} catch (e) {
// Handle exceptions here
}
}
getDash(ja, videoList, audioList) {
const duration = ja.data.dash["duration"];
const minBufferTime = ja.data.dash["minBufferTime"];
return `<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" type="static" mediaPresentationDuration="PT${duration}S" minBufferTime="PT${minBufferTime}S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
<Period duration="PT${duration}S" start="PT0S">
${videoList}
${audioList}
</Period>
</MPD>`;
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'dash') {
const ids = url.split('+');
const aid = ids[0];
const cid = ids[1];
const str5 = ids[2];
const urls = this.apiUrl + `/x/player/playurl?avid=${aid}&cid=${cid}&qn=${str5}&fnval=4048&fourk=1`;
let videoList = '';
let audioList = '';
let content = await this.fetch(urls, null, headers);
let resp = JSON.parse(content)
const dash = resp.data.dash;
const video = dash.video;
const audio = dash.audio;
for (let i = 0; i < video.length; i++) {
// if (i > 0) continue; // 只取一个
const dashjson = video[i];
if (dashjson.id.toString() === str5) {
videoList += this.getDashMedia(dashjson);
}
}
for (let i = 0; i < audio.length; i++) {
// if (i > 0) continue;
const ajson = audio[i];
for (const key in this.vod_audio_id) {
if (ajson.id.toString() === key) {
audioList += this.getDashMedia(ajson);
}
}
}
let mpd = this.getDash(resp, videoList, audioList);
return JSON.stringify({
code: 200,
content: mpd,
headers: {
'Content-Type': 'application/dash+xml',
},
});
}
return JSON.stringify({
code: 500,
content: '',
});
}
}
let spider = new BilibiliSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

152
JN/CATJS/js/bookan.js Normal file
View File

@ -0,0 +1,152 @@
/*
* @File : bookan.js
* @Author : jade
* @Date : 2024/1/31 13:44
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import {Spider} from "./spider.js";
function formatPlayUrl(name) {
return name
.trim()
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
class BooKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.bookan.com.cn";
}
getName() {
return "🎵┃看书┃🎵"
}
getAppName() {
return "看书"
}
getJSName() {
return "bookan"
}
getType() {
return 10
}
async parseVodShortListFromJson(obj) {
let books = [];
for (const book of obj.list) {
books.push({
book_id: book.id, book_name: book.name, book_pic: book.cover, book_remarks: book.extra.author,
});
}
return books
}
async setClasses() {
{
this.classes = [{type_id: '1305', type_name: '少年读物'}, {
type_id: '1304', type_name: '儿童文学'
}, {type_id: '1320', type_name: '国学经典'}, {type_id: '1306', type_name: '文艺少年'}, {
type_id: '1309', type_name: '育儿心经'
}, {type_id: '1310', type_name: '心理哲学'}, {type_id: '1307', type_name: '青春励志'}, {
type_id: '1312', type_name: '历史小说'
}, {type_id: '1303', type_name: '故事会'}, {type_id: '1317', type_name: '音乐戏剧'}, {
type_id: '1319', type_name: '相声评书'
},]
}
}
async setCategory(tid, pg, filter, extend) {
let content = await this.fetch(`${this.siteUrl}/voice/book/list?instance_id=25304&page=${pg}&category_id=${tid}&num=24`, null, this.getHeader());
let data = JSON.parse(content).data;
this.vodList = await this.parseVodShortListFromJson(data)
}
async parseVodDetailfromJson(obj) {
let book = {
audio: 1,
type_name: '',
book_year: '',
book_area: '',
book_remarks: '',
book_actor: '',
book_director: '',
book_content: '',
};
let us = _.map(obj.list, function (b) {
return formatPlayUrl(b.title) + '$' + b.file;
}).join('#');
book.volumes = '书卷';
book.urls = us;
return book
}
async setDetail(id) {
let content = await this.fetch(`${this.siteUrl}/voice/album/units?album_id=${id}&page=1&num=200&order=1`, null, this.getHeader());
let data = JSON.parse(content).data;
this.vodDetail = await this.parseVodDetailfromJson(data)
this.vodDetail.book_id = id
}
async play(flag, id, flags) {
return JSON.stringify({
parse: 0, url: id,
});
}
async setSearch(wd, quick) {
let content = await this.fetch(`https://es.bookan.com.cn/api/v3/voice/book?instanceId=25304&keyword=${wd}&pageNum=1&limitNum=20`,null,this.getHeader());
let data = JSON.parse(content).data;
this.vodList = await this.parseVodShortListFromJson(data)
}
}
let spider = new BooKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}

268
JN/CATJS/js/bqg_open.js Normal file
View File

@ -0,0 +1,268 @@
/*
* @File : bqg_open.js.js
* @Author : jade
* @Date : 2024/1/30 15:38
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class BQQSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://m.13bqg.com"
}
getAppName() {
return "笔趣阁"
}
getJSName() {
return "bqg_open"
}
getType() {
return 10
}
getName() {
return "📚︎┃笔趣阁┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $("[class=\"block\"]")
for (const bookElement of $(bookElements[0]).find("li")) {
let bookShort = new BookShort()
let bookShortElements = $(bookElement).find("span")
bookShort.book_remarks = $(bookShortElements[0]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = $(bookShortElements[1]).find("a")[0].attribs.href
bookShort.book_pic = this.jsBase + Utils.base64Encode(bookShort.book_id)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let books = [];
for (const item of $('div.item')) {
let bookShort = new BookShort()
bookShort.book_id = $(item).find('a:first')[0].attribs.href;
const img = $(item).find('img:first')[0];
bookShort.book_name = img.attribs.alt
bookShort.book_pic = img.attribs.src
bookShort.book_remarks = $(item).find('span:first')[0].children[0].data.trim();
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let bookDetail = new BookDetail()
bookDetail.book_name = $('[property$=book_name]')[0].attribs.content
bookDetail.book_year = $('[property$=update_time]')[0].attribs.content
bookDetail.book_director = $('[property$=author]')[0].attribs.content
bookDetail.book_content = $('[property$=description]')[0].attribs.content
bookDetail.book_pic = $($("[class=\"cover\"]")).find("img")[0].attribs.src
bookDetail.book_id = id
let playBook = {}
if (id !== undefined) {
$ = await this.getHtml(this.siteUrl + id + `list.html`);
let urls = [];
const links = $('dl>dd>a[href*="/html/"]');
for (const l of links) {
const name = $(l).text().trim();
const link = l.attribs.href;
urls.push(name + '$' + link);
}
playBook["最新章节"] = urls.slice(-10).join('#');
playBook["目录"] = urls.join('#');
}
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
for (const a of $('div.nav > ul > li > a[href!="/"]')) {
this.classes.push({
type_id: a.attribs.href.replace(/\//g, ''), type_name: a.children[0].data.trim(), tline: 2,
});
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + `/${tid}/${pg}.html`);
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
try {
let content = '';
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += $('#chaptercontent')
.html()
.replace(/<br>|请收藏.*?<\/p>/g, '\n')
.trim();
id = $('a.Readpage_down')[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content":content + '\n\n'}
} catch (e) {
this.playUrl = {"content":""}
}
}
async search(wd, quick) {
const cook = await req(`${this.siteUrl}/user/hm.html?q=${encodeURIComponent(wd)}`, {
headers: {
accept: 'application/json',
'User-Agent': Utils.MOBILEUA,
Referer: `${this.siteUrl}/s?q=${encodeURIComponent(wd)}`,
},
});
const set_cookie = _.isArray(cook.headers['set-cookie']) ? cook.headers['set-cookie'].join(';;;') : cook.headers['set-cookie'];
const cks = set_cookie.split(';;;');
const cookie = {};
for (const c of cks) {
const tmp = c.trim();
const idx = tmp.indexOf('=');
const k = tmp.substr(0, idx);
cookie[k] = tmp.substr(idx + 1, tmp.indexOf(';') - idx - 1);
}
const resp = await req(`${this.siteUrl}/user/search.html?q=${encodeURIComponent(wd)}&so=undefined`, {
headers: {
accept: 'application/json',
'User-Agent': Utils.MOBILEUA,
cookie: 'hm=' + cookie['hm'],
Referer: `${this.siteUrl}/s?q=${encodeURIComponent(wd)}`,
},
});
let data = JSON.parse(resp.content);
let books = [];
for (const book of data) {
books.push({
book_id: book["url_list"],
book_name: book["articlename"],
book_pic: book["url_img"],
book_remarks: book["author"],
});
}
return {
tline: 2, list: books,
};
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'img') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + url)
let bookDetail = await this.parseVodDetailFromDoc($)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new BQQSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

333
JN/CATJS/js/changzhang.js Normal file
View File

@ -0,0 +1,333 @@
/*
* @File : changzhang.js
* @Author : jade
* @Date : 2024/2/2 16:02
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import { aliName, detailContent,initCloud,playContent, quarkName } from "../lib/cloud.js";
function cryptJs(text, key, iv, type) {
let key_value = Crypto.enc.Utf8.parse(key || 'PBfAUnTdMjNDe6pL');
let iv_value = Crypto.enc.Utf8.parse(iv || 'sENS6bVbwSfvnXrj');
let content
if (type) {
content = Crypto.AES.encrypt(text, key_value, {
iv: iv_value, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7
})
} else {
content = Crypto.AES.decrypt(text, key_value, {
iv: iv_value, padding: Crypto.pad.Pkcs7
}).toString(Crypto.enc.Utf8)
}
return content
}
class ChangZhangSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.czys.top"
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj);
}
getName() {
return "🏭️┃厂长直连┃🏭️"
}
getAppName() {
return "厂长直连"
}
getJSName() {
return "changzhang"
}
getType() {
return 3
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
let response = await this.fetch(url, null, headers,false,true);
let html = response["content"]
if (!_.isEmpty(html) && html.indexOf("人机验证")===-1) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
getSearchHeader() {
return {
"Cookie": "cf_clearance=otYZbHg1safCIxkCtZfy9DPKbf1Gs_zUskkVDc0MVKM-1707026063-1-ATOpKnTLv9+pv171YE/rzxN/nmvGN9Mucx7vpwp0kW2vZb/cbtz5e2md2/ym7EE+9dT7pPBV+kQOg9vJx2v8cks=;myannoun=1;PHPSESSID=73386nobqugs7r3pb2ljcsp5q4",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/100.0.4896.77 Mobile/15E148 Safari/604.1",
"Connection":"keep-alive",
"Host":"www.czzy55.com"
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort()
let imgElement = $($(element).find("a")).find("img")[0]
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_pic = imgElement.attribs["data-original"]
vodShort.vod_remarks = $($($(element).find("[class='hdinfo']")).find("span")).text()
vodShort.vod_id = $(element).find("a")[0].attribs.href
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let aList = $($("[class=\"mi_cont\"]").find("ul")).find("li")
for (const a of aList) {
vod_list.push(this.parseVodShortFromElement($, a))
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let aList = $($("[class=\"mi_cont \"]").find("ul")).find("li")
for (const a of aList) {
vod_list.push(this.parseVodShortFromElement($, a))
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let nodeElement = $("[class='dyxingq']")
vodDetail.vod_pic = $(nodeElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(nodeElement).find("h1")[0]).text()
vodDetail.vod_content = $($($("[class='yp_context']")).find("p")).text()
let infoArray = $(nodeElement).find("[class='moviedteail_list']").find("li")
let x = $(infoArray).text()
for (const info of infoArray) {
let content = $(info).text()
if (content.indexOf("类型") > -1) {
vodDetail.type_name = content.replaceAll("类型", "").replaceAll("", "")
} else if (content.indexOf("年份") > -1) {
vodDetail.vod_year = content.replaceAll("年份", "").replaceAll("", "")
} else if (content.indexOf("地区") > -1) {
vodDetail.vod_area = content.replaceAll("地区", "").replaceAll("", "")
} else if (content.indexOf("豆瓣") > -1) {
vodDetail.vod_remarks = content.replaceAll("豆瓣", "").replaceAll("", "")
} else if (content.indexOf("主演") > -1) {
vodDetail.vod_actor = content.replaceAll("主演", "").replaceAll("", "")
} else if (content.indexOf("导演") > -1) {
vodDetail.vod_director = content.replaceAll("导演", "").replaceAll("", "")
} else if (content.indexOf("剧情") > -1) {
vodDetail.vod_content = content.replaceAll("剧情", "").replaceAll("", "")
}
}
let vod_play_from_list = ["厂长资源"]
let vodPlayList = $("[class='paly_list_btn']")
let vod_play_list = []
for (const v1 of vodPlayList) {
let vodItems = []
let aList = $(v1).find("a")
for (const tA of aList) {
let episodeUrl = tA.attribs.href
let episodeName = $(tA).text().replaceAll("立即播放  (", "").replaceAll(")", "")
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
let valify_formt_list = ["磁力链接", aliName]
let otherPlayList = $("[class=\"ypbt_down_list\"]").find("li")
let playVod = {}
for (const otherPlay of otherPlayList) {
let form_name = $(otherPlay).text()
let is_valify = false
for (const valify_format_name of valify_formt_list) {
if (form_name.indexOf(valify_format_name) > -1) {
is_valify = true
if (form_name.indexOf(aliName) === -1) {
vod_play_from_list.push(valify_format_name)
}
}
}
if (is_valify) {
let vodItems = []
for (const ciliPlayUrl of $(otherPlay).find("a")) {
let episodeUrl = ciliPlayUrl.attribs.href
if ($(otherPlay).text().indexOf(aliName)) {
playVod = await detailContent([episodeUrl])
} else {
let episodeName = Utils.getStrByRegex(/\[(.*?)]/, $(ciliPlayUrl).text())
vodItems.push(episodeName + "$" + episodeUrl)
playVod["磁力链接"] = (vodItems.join("#"))
}
}
}
}
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
const items = $('div.search_list > ul > li');
return _.map(items, (item) => {
const img = $(item).find('img:first')[0];
const a = $(item).find('a:first')[0];
const hdinfo = $($(item).find('div.hdinfo')[0]).text().trim();
const jidi = $($(item).find('div.jidi')[0]).text().trim();
return {
vod_id: a.attribs.href,
vod_name: img.attribs.alt,
vod_pic: img.attribs['data-original'],
vod_remarks: jidi || hdinfo || '',
};
})
}
async setClasses() {
const $ = await this.getHtml(this.siteUrl + '/movie_bt');
const series = $('div#beautiful-taxonomy-filters-tax-movie_bt_series > a[cat-url*=movie_bt_series]');
const tags = $('div#beautiful-taxonomy-filters-tax-movie_bt_tags > a');
let tag = {
key: 'tag', name: '类型', value: _.map(tags, (n) => {
let v = n.attribs['cat-url'] || '';
v = v.substring(v.lastIndexOf('/') + 1);
return {n: n.children[0].data, v: v};
}),
};
tag['init'] = tag.value[0].v;
let classes = _.map(series, (s) => {
let typeId = s.attribs['cat-url'];
typeId = typeId.substring(typeId.lastIndexOf('/') + 1);
this.filterObj[typeId] = [tag];
return {
type_id: typeId, type_name: s.children[0].data,
};
});
const sortName = ['电影', '电视剧', '国产剧', '美剧', '韩剧', '日剧', '海外剧(其他)', '华语电影', '印度电影', '日本电影', '欧美电影', '韩国电影', '动画', '俄罗斯电影', '加拿大电影'];
let sort_classes = _.sortBy(classes, (c) => {
const index = sortName.indexOf(c.type_name);
return index === -1 ? sortName.length : index;
});
for (const sort_class of sort_classes){
let type_name = sort_class["type_name"]
if (type_name!=="会员专区" && type_name !== "站长推荐"){
this.classes.push(sort_class)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0) pg = 1;
const tag = extend.tag || '';
const link = this.siteUrl + '/movie_bt' + (tag.length > 0 ? `/movie_bt_tags/${tag}` : '') + '/movie_bt_series/' + tid + (pg > 1 ? `/page/${pg}` : '');
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
const $ = await this.getHtml(this.siteUrl + '/xssearch?q=' + wd,this.getSearchHeader());
let html = $.html()
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf(aliName) > -1 || flag.indexOf(quarkName) > -1) {
this.playUrl = await playContent(flag, id, flags)
this.result.setHeader(getHeaders(flag))
} else {
if (id.indexOf("magnet") > -1) {
this.playUrl = id
} else {
let $ = await this.getHtml(id)
const iframe = $('body iframe[src*=https]');
if (iframe.length > 0) {
const iframeHtml = (await req(iframe[0].attribs.src, {
headers: {
Referer: id, 'User-Agent': Utils.CHROME,
},
})).content;
let player = Utils.getStrByRegex(/var player = "(.*?)"/, iframeHtml)
let rand = Utils.getStrByRegex(/var rand = "(.*?)"/, iframeHtml)
let content = JSON.parse(cryptJs(player, "VFBTzdujpR9FWBhe", rand))
this.playUrl = content["url"]
} else {
const js = $('script:contains(window.wp_nonce)').html();
const group = js.match(/(var.*)eval\((\w*\(\w*\))\)/);
const md5 = Crypto;
const result = eval(group[1] + group[2]);
this.playUrl = result.match(/url:.*?['"](.*?)['"]/)[1];
}
}
}
}
}
let spider = new ChangZhangSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

191
JN/CATJS/js/ciliduo.js Normal file
View File

@ -0,0 +1,191 @@
/*
* @File : ciliduo.js
* @Author : jade
* @Date : 2024/3/1 13:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 磁力多
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class CiliDuoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://of.cilido.top"
this.apiUrl = ""
this.vodShortObj = {}
}
getName() {
return "🔞┃磁力多BT┃🔞"
}
getAppName() {
return "磁力多BT"
}
getJSName() {
return "ciliduo"
}
getType() {
return 3
}
getProxy(src) {
return Utils.base64Decode(src)
}
async home(filter) {
try {
await this.jadeLog.info("正在解析首页类别", true)
let $ = await this.getHtml()
let proxy_src = Utils.getStrByRegex(/var proxy = atob\('(.*?)'\)/, $.html())
this.apiUrl = this.getProxy(proxy_src)
let params = `/?host=${Utils.getHost(this.siteUrl).split("://").slice(-1)[0]}&v=1`
let homeContent = await this.fetch(this.apiUrl, params, this.getHeader())
return await this.parseVodShortListFromDoc(load(homeContent))
} catch (e) {
await this.jadeLog.error(`首页解析失败,失败原因为:${e}`)
}
}
async parseVodShortListFromDoc($) {
let rootElemet = $("[class=\"htab\"]")
let navElements = rootElemet.find("a")
let vodElements = $("[class=\"hotwords\"]").find("ul")
for (let i = 0; i < navElements.length; i++) {
let navElement = navElements[i]
if (i !== navElements.length - 1) {
let type_name = $(navElement).text()
if (type_name === "热门") {
type_name = "最近更新"
}
this.classes.push(this.getTypeDic(type_name, type_name))
let vodElement = vodElements[i]
let vod_list = []
for (const vodShorElement of $(vodElement).find("a")) {
let vodShort = new VodShort()
vodShort.vod_id = vodShorElement.attribs.href
vodShort.vod_name = $(vodShorElement).html()
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vod_list.push(vodShort)
}
this.vodShortObj[type_name] = vod_list
}
}
return this.result.home(this.classes, [], this.filterObj)
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"ssbox\"]")
for (const vodElement of vodElements.slice(0, -1)) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = $($(vodElement).find("a")[0]).text()
vodShort.vod_remarks = $($(vodElement).find("span")[0]).text()
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let html = $.html()
let vodDetail = new VodDetail()
vodDetail.vod_name = $($("[class=\"bt_title\"]")).text()
vodDetail.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vodDetail.vod_remarks = Utils.getStrByRegex(/<br>收录时间:<span>(.*?)<\/span>/, $.html())
vodDetail.vod_content = "下载速度:" + Utils.getStrByRegex(/下载速度:<span>(.*?)<\/span>/, $.html())
vodDetail.vod_play_from = ["磁力连接"].join("$$$")
let vodItems = []
let contentElement = $("[class=\"content\"]").find("span")[0]
let episodeUrl = contentElement.attribs.href;
let episodeName = contentElement.attribs.title;
vodItems.push(episodeName + "$" + episodeUrl);
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setHomeVod() {
this.homeVodList = this.vodShortObj["最近更新"]
}
async setCategory(tid, pg, filter, extend) {
this.vodList = this.vodShortObj[tid]
}
async setDetail(id) {
if (id.indexOf("search") > -1) {
let content = await this.fetch(this.apiUrl + id, null, this.getHeader())
let vod_list = await this.parseVodShortListFromDocBySearch(load(content))
id = vod_list[0].vod_id
}
await this.jadeLog.debug(id)
let detailUrl = this.apiUrl + id
let detailContent = await this.fetch(detailUrl, null, this.getHeader())
this.vodDetail = await this.parseVodDetailFromDoc(load(detailContent))
}
async setSearch(wd, quick) {
let searchUrl = this.apiUrl + `search?word=${wd}`
let content = await this.fetch(searchUrl, null, this.getHeader())
this.vodList = await this.parseVodShortListFromDocBySearch(load(content))
}
}
let spider = new CiliDuoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

253
JN/CATJS/js/cilixiong.js Normal file
View File

@ -0,0 +1,253 @@
/*
* @File : cilixiong.js
* @Author : jade
* @Date : 2024/4/13 14:52
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js"
class CiliXiongSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.cilixiong.com"
this.cateObj = {"/movie/": "1", "/drama/": "2"}
}
getAppName() {
return "磁力熊"
}
getName() {
return "🐻┃磁力熊┃🐻"
}
getJSName() {
return "cilixiong"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0\"]").find("li")
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
if (type_name !== "首页" && type_name !== "榜单" && type_name !== "留言") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let extend_list = []
let filerElements = $("[class=\"nav small\"]")
let i = 1
for (const filetElement of filerElements) {
let extend_name = $($(filetElement).find("li")[0]).text().replaceAll("", "")
let extend_dic = {"key": (i).toString(), "name": extend_name, "value": []}
for (const typeElement of $(filetElement).find("li").slice(1)) {
let element = $(typeElement).find("a")[0]
let type_id = element.attribs.href.split("-")[i]
extend_dic["value"].push({"n": $(element).text(), "v": type_id})
}
i = i + 1
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"col\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_pic = Utils.getStrByRegex(/background-image: url\('(.*?)'\)/, $(vodElement).find("[class=\"card-img\"]")[0].attribs["style"])
vodShort.vod_name = $($(vodElement).find("h2")).text()
let remarks = $($(vodElement).find("[class=\"rank bg-success p-1\"]")).text()
vodShort.vod_remarks = "评分:" + remarks
if (remarks !== "AD") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"card card-cover h-100 overflow-hidden text-bg-dark rounded-4 shadow-lg position-relative\"]")
for (const vodElement of vodElements){
let vodShort= new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = $($(vodElement).find("[class=\"pt-5 lh-1 pb-2 h4\"]")).text()
vodShort.vod_pic = Utils.getStrByRegex(/background-image: url\('(.*?)'\)/,$(vodElement).find("[class=\"card-img\"]")[0].attribs.style)
vodShort.vod_remarks = "评分:" + $($(vodElement).find("[class=\"rank bg-success p-1\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodDetailElement = $("[class=\"row row-cols-1 row-cols-lg-3 align-items-stretch g-4 p-5 text-white\"]")
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(vodDetailElement).find("h1")).text()
let vodContentElements = $(vodDetailElement).find("[class=\"mb-2\"]").slice(1)
for (const contentElement of vodContentElements) {
let name = $(contentElement).text()
if (name.indexOf("豆瓣评分") > -1) {
vodDetail.vod_remarks = name
}
if (name.indexOf("类型") > -1) {
vodDetail.type_name = name.replaceAll("", "").replace("类型", "").replaceAll(":", "")
}
if (name.indexOf("上映地区") > -1) {
vodDetail.vod_area = name.replaceAll("", "").replace("上映地区", "").replaceAll(":", "")
}
if (name.indexOf("主演") > -1) {
vodDetail.vod_actor = name.replaceAll("", "").replace("主演", "").replaceAll(":", "")
}
if (name.indexOf("上映日期") > -1){
vodDetail.vod_year = name.replaceAll("", "").replace("上映日期", "").replaceAll(":", "")
}
}
vodDetail.vod_content = $($(vodDetailElement).find("[class=\"mv_card_box\"]")).text()
let playerMap = {}
let emebedVideoElements = $("[class=\"row col-md-12 embed_video\"]")
let index = 1
for (const emebedVideoElement of emebedVideoElements){
let vodItems = []
let playUrl = $($(emebedVideoElement).find("iframe"))[0].attribs["src"]
vodItems.push("播放" + "$" + playUrl);
playerMap["在线播放" + index.toString()+ "第一集在线播放预览"] = vodItems.join("#")
index = index + 1
}
let mangetIndex = 1
let mangetElements = $("[class=\"row col-md-12 text-white p-3 pt-1\"]").find("[class=\"container\"]")
for (const mangenment of mangetElements){
let vodItems = []
let playElement = $($(mangenment).find("a"))[0]
let playUrl = playElement.attribs.href
let playName = $(playElement).text()
if (playUrl.startsWith("magnet")){
vodItems.push(playName + "$" + playUrl);
}
if (vodItems.length > 0){
playerMap["磁力链接" + "-" + mangetIndex] = vodItems.join("#")
mangetIndex = mangetIndex + 1
}
}
vodDetail.vod_play_from = Object.keys(playerMap).join("$$$");
vodDetail.vod_play_url = Object.values(playerMap).join("$$$");
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let type = extend["1"] ?? "0"
let area = extend["2"] ?? "0"
let page = parseInt(pg) - 1
let url = this.siteUrl + "/" + this.cateObj[tid] + `-${type}-${area}-${page}.html`
await this.jadeLog.debug(`分类URL:${url}`)
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("在线播放") > -1){
let $ = await this.getHtml(this.siteUrl + id)
this.playUrl = Utils.getStrByRegex(/const source = '(.*?)'/,$.html())
}else{
this.playUrl = id
}
}
async setSearch(wd, quick) {
let params = {"classid":"1,2","show":"title","tempid":"1","keyboard":wd}
let response = await this.post(this.siteUrl + "/e/search/index.php",params,this.getHeader())
let $ = load(response)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new CiliXiongSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

364
JN/CATJS/js/cntv.js Normal file
View File

@ -0,0 +1,364 @@
/*
* @File : cntv.js
* @Author : jade
* @Date : 2024/4/25 10:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class CNTVSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://tv.cctv.com/m/index.shtml"
this.apiUrl = "https://api.app.cctv.com"
this.liveJsonUrl = "https://gh.con.sh/https://github.com/jadehh/LiveSpider/blob/main/json/live.json"
}
getName() {
return "🤵‍♂️┃中央影视┃🤵‍♂️"
}
getAppName() {
return "中央影视"
}
getJSName() {
return "cntv"
}
getType() {
return 3
}
async spiderInit() {
await super.spiderInit();
this.liveJson = JSON.parse(await this.fetch(this.liveJsonUrl, null, null))
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit()
}
async getFilterByLive(dataList) {
let extend_list = []
let extend_dic = {"key": "live", "name": "直播", "value": []}
for (const data of dataList) {
if (data["appBarTitle"] !== "最近常看") {
extend_dic["value"].push({"n": data["appBarTitle"], "v": data["pageId"]})
}
}
extend_list.push(extend_dic)
return extend_list
}
arrayIsinclude(str, items) {
let isInclude = false
for (const data of items) {
if (str === data["title"]) {
return true
}
}
return isInclude
}
async getFilterByTv(dataList) {
let extend_list = []
for (const data of dataList) {
let add_year_status = false
let extend_dic = {"key": data["classname"], "name": data["title"], "value": []}
for (const extendData of data["items"]) {
if (data["classname"] === "nianfen") {
if (!this.arrayIsinclude("2024", data["items"]) && extendData["title"] !== "全部" && !add_year_status) {
extend_dic["value"].push({"n": "2024", "v": "2024"})
add_year_status = true
}
}
extend_dic["value"].push({"n": extendData["title"], "v": extendData["title"]})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let liveTypeId = "cctvlive"
let liveApi = this.apiUrl + `/api/navigation/iphone/AppStore/7.9.4/${liveTypeId}`
let liveJson = JSON.parse(await this.fetch(liveApi, null, this.getHeader()))
let extend_list = await this.getFilterByLive(liveJson["data"]["templates"])
let defaultLiveId = extend_list[0]["value"][0]["v"]
this.classes.push(this.getTypeDic("直播", defaultLiveId))
this.filterObj[defaultLiveId] = extend_list
let tvApi = "https://cbox.cctv.com/cboxpcvip/online2022/yxg/data1.jsonp?=pk"
let tvContent = await this.fetch(tvApi, null, this.getHeader())
let tvJSon = JSON.parse(tvContent.replaceAll("pk(", "").replaceAll(")", ""))
for (const data of tvJSon["data"]) {
let typeName = data["title"]
this.classes.push(this.getTypeDic(typeName, typeName))
this.filterObj[typeName] = await this.getFilterByTv(data["templates"])
}
}
parseVodShortByJson(items) {
let vod_list = []
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_pic = item["img1"]
if (_.isEmpty(vodShort.vod_pic)) {
vodShort.vod_pic = item["epgHorizontalPic"]
vodShort.vod_id = "live-" + item["epgChnlChar"] + "-" + vodShort.vod_pic
} else {
vodShort.vod_id = "play-" + item["playid"] + "-" + vodShort.vod_pic
vodShort.vod_pic = item["img1"]
}
vodShort.vod_name = item["title"]
vod_list.push(vodShort)
}
return vod_list
}
parseVodShortByTvJson(items) {
let vod_list = []
for (const item of items) {
let vodShort = new VodShort()
//关键是如何获取GUID 2d3224585904496ea837f682da0c4aa6
vodShort.vod_id = "url-" + item["vsetid"]
vodShort.vod_name = item["title"]
vodShort.vod_pic = item["image"]
vodShort.vod_remarks = item["sc"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(objList) {
let vod_list = []
let top_status = false
for (const data of objList) {
if (data["title"] === "今日热点") {
top_status = true
} else if (!_.isEmpty(data["title"])) {
if (top_status) {
break
}
}
if (top_status) {
vod_list = [...vod_list, ...this.parseVodShortByJson(data["items"])]
}
}
return vod_list
}
async getLiveUrl(channel_id, obj) {
let liveApiUrl = `https://vdn.live.cntv.cn/api2/live.do?channel=pd://cctv_p2p_hd${channel_id}&client=iosapp`
let liveResponse = await req(liveApiUrl, {"headers": this.getHeader()})
let liveJson = JSON.parse(liveResponse["content"])
let playList = {}
let channelName = obj["channelName"].split(" ")[0].replaceAll("-", "").toLowerCase()
let liveUrl = this.liveJson[channelName] ?? liveJson["hls_url"]["hls2"]
playList["直播"] = ["点击播放$" + liveUrl]
await this.jadeLog.info(`liveJson:${JSON.stringify(liveJson)}`)
let vod_items = []
if (this.liveJson[channelName] !== undefined) {
} else {
for (const data of obj["program"]) {
let episodeName = data["showTime"] + "-" + data["t"]
let episodeUrl = liveUrl + `?begintimeabs=${data["st"] * 1000}&endtimeabs=${data["et"] * 1000}`
vod_items.push(episodeName + "$" + episodeUrl)
}
}
if (vod_items.length > 0){
playList["点播"] = vod_items.join("#")
}
return playList
}
async getVideoUrl(guid) {
return {"中央影视": ['点击播放' + '$' + guid].join("#")}
}
async parseVodDetailfromJson(id, obj, pic) {
let vodDetail = new VodDetail()
let $;
let guid;
if (obj["url"] !== undefined) {
vodDetail.vod_name = obj["title"]
vodDetail.vod_pic = obj["img"]
vodDetail.type_name = obj["tags"]
vodDetail.vod_year = obj["time"]
vodDetail.vod_content = obj["vset_brief"]
vodDetail.vod_director = obj["vset_title"]
$ = await this.getHtml(obj["url"])
} else {
if (_.isEmpty(obj["lvUrl"])) {
vodDetail.vod_name = obj["channelName"]
vodDetail.vod_pic = pic
} else {
$ = await this.getHtml(obj["lvUrl"])
vodDetail.vod_name = $('[property$=title]')[0].attribs.content
vodDetail.vod_content = $('[property$=description]')[0].attribs.content
let pic = $('[property$=image]')[0].attribs.content
if (!pic.startsWith("http")) {
pic = "https:" + pic
}
vodDetail.vod_pic = pic
}
}
if (!_.isEmpty($)) {
guid = Utils.getStrByRegex(/var guid = "(.*?)"/, $.html())
}
let playlist
if (_.isEmpty(guid) && obj["url"] === undefined) {
playlist = await this.getLiveUrl(id, obj)
} else {
playlist = await this.getVideoUrl(guid)
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async parseVodDetailFromJsonByTv(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["videoSetInfo"]["title"]
vodDetail.type_name = obj["videoSetInfo"]["sc"]
vodDetail.vod_pic = obj["videoSetInfo"]["image"]
vodDetail.vod_content = obj["videoSetInfo"]["brief"]
vodDetail.vod_area = obj["videoSetInfo"]["area"]
let playlist = {}
let vodItems = []
for (const data of obj["videoRoughCut"]) {
let title = data["title"].split("》").slice(-1)[0]
vodItems.push(title + "$" + data["guid"])
}
playlist["中央影视"] = vodItems.join("#")
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setHomeVod() {
let resJson = JSON.parse(await this.fetch(this.apiUrl + "/api/page/iphone/HandheldApplicationSink/7.0.0/158", null, this.getHeader()))
this.homeVodList = await this.parseVodShortListFromJson(resJson["data"]["templates"])
}
getExtendValue(extend, key) {
if (extend[key] !== undefined && extend[key] !== "全部") {
return extend[key]
}
return ""
}
async setCategory(tid, pg, filter, extend) {
if (Utils.isNumeric(tid)) {
tid = extend["live"] ?? tid
let url = this.apiUrl + `/api/page/iphone/HandheldApplicationSink/7.0.0/${tid}`
let response = JSON.parse(await this.fetch(url, null, this.getHeader()))
this.vodList = this.parseVodShortByJson(response["data"]["templates"][0]["items"])
} else {
let letter = this.getExtendValue(extend, "zimu")
let area = this.getExtendValue(extend, "diqu")
let type = this.getExtendValue(extend, "leixing")
let year = this.getExtendValue(extend, "nianfen")
const limit = 12
let url = "https://api.cntv.cn" + `/newVideoset/getCboxVideoAlbumList`
let params = {
"channelid": "",
"sc": type,
"fc": tid,
"p": pg,
"n": limit,
"fl": letter,
"area": area,
"year": year,
"serviceId": "cbox"
}
let resJson = JSON.parse(await this.fetch(url, params, this.getHeader()))
this.vodList = this.parseVodShortByTvJson(resJson["data"]["list"])
}
}
async setDetail(id) {
//区分直播还是点播
let aList = id.split("-")
let playType = aList[0]
let pic = aList[2]
id = aList[1]
if (playType === "play") {
let resJson = JSON.parse(await this.fetch(`https://api.cntv.cn/video/videoinfoByGuid?serviceId=cbox&guid=${id}`, null, this.getHeader()))
this.vodDetail = await this.parseVodDetailfromJson(id, resJson, pic)
} else if (playType === "url") {
let url = `https://api.app.cctv.com/api/getVideoPageDetail?videoSetContentId=${id}`
let resJson = JSON.parse(await this.fetch(url, null, this.getHeader()))
this.vodDetail = await this.parseVodDetailFromJsonByTv(resJson["data"])
} else {
let content = (await this.fetch(`https://api.cntv.cn/epg/epginfo3?serviceId=shiyi&c=${id}&cb=LiveTileShow.prototype.getEpg`, null, this.getHeader())).replaceAll("LiveTileShow.prototype.getEpg(", "").replaceAll(");", "")
this.vodDetail = await this.parseVodDetailfromJson(id, JSON.parse(content)[id], pic)
}
}
async setSearch(wd, quick, pg) {
}
async setPlay(flag, id, flags) {
if (id.startsWith("http")) {
this.playUrl = id
let headers = this.getHeader()
headers["Referer"] = "https://tv.cctv.com/"
this.result.header = headers
} else {
this.playUrl = 'https://hls.cntv.myhwcdn.cn/asp/hls/2000/0303000a/3/default/' + id + '/2000.m3u8'
}
}
}
let spider = new CNTVSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, CNTVSpider}

233
JN/CATJS/js/copymanga.js Normal file
View File

@ -0,0 +1,233 @@
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
import {Crypto} from "../lib/cat.js";
class CopyManhuaSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.copymanga.tv';
}
getName() {
return "🧑‍🎨|拷贝漫画|🧑‍🎨"
}
getAppName() {
return "拷贝漫画"
}
getJSName() {
return "copymanga"
}
getType() {
return 20
}
async setClasses() {
this.classes.push(this.getTypeDic("全部", "c1"))
}
async getFilter($) {
let region = {
key: 'region', name: '地區', init: '',
};
let regionValues = [];
regionValues.push({n: '全部', v: ''});
regionValues.push({n: '日漫', v: '0'});
regionValues.push({n: '韓漫', v: '1'});
regionValues.push({n: '美漫', v: '2'});
region['value'] = regionValues;
let ordering = {
key: 'ordering', name: '排序', init: '-datetime_updated',
};
let orderingValues = [];
orderingValues.push({n: '更新時間↓', v: '-datetime_updated'});
orderingValues.push({n: '更新時間↑', v: 'datetime_updated'});
orderingValues.push({n: '熱門↓', v: '-popular'});
orderingValues.push({n: '熱門↑', v: 'popular'});
ordering['value'] = orderingValues;
let status = {
key: 'sort', name: '狀態', init: '',
};
let statusValues = [];
statusValues.push({n: '全部', v: ''});
statusValues.push({n: '連載中', v: '0'});
statusValues.push({n: '已完結', v: '1'});
statusValues.push({n: '短篇', v: '2'});
status['value'] = statusValues;
let extend_list = []
let themeValues = [{n: '全部', v: ''}];
for (const a of $('div.classify-right>a[href*="theme="]')) {
themeValues.push({
n: $(a).text().trim(), v: a.attribs.href.match(/.*?theme=(.*)&/)[1],
});
}
extend_list.push({
key: 'theme', name: '', init: '', wrap: 1, value: themeValues,
});
extend_list.push(region);
extend_list.push(status);
extend_list.push(ordering);
return extend_list
}
async setFilterObj() {
let $ = await this.getHtml(this.siteUrl + '/comics');
this.filterObj['c1'] = await this.getFilter($);
}
parseVodShortFromJson(obj) {
let bookShort = new BookShort()
bookShort.book_id = obj["path_word"]
bookShort.book_name = obj["name"]
bookShort.book_pic = obj["cover"]
bookShort.book_remarks = obj.author ? obj.author[0].name : '';
return bookShort
}
async parseVodShortListFromDocByCategory($) {
const list = eval($('div[class="row exemptComic-box"]')[0].attribs.list);
let books = [];
for (const book of list) {
let bookShort = this.parseVodShortFromJson(book)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDoc($) {
let vodElements = $("[class=\"container edit\"]").find("[class=\"col-auto\"]")
let books = []
for (const vodElement of vodElements) {
let bookShort = new BookShort()
bookShort.book_id = $(vodElement).find("a")[0].attribs.href.split("/comic/")[1]
bookShort.book_pic = $(vodElement).find("img")[0].attribs["data-src"]
bookShort.book_name = $($(vodElement).find("p")).text()
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let bookDetail = new BookDetail()
bookDetail.book_pic = $("[class=\"comicParticulars-left-img loadingIcon\"]").find("img")[0].attribs["data-src"]
bookDetail.book_name = $('h6').text().trim()
bookDetail.book_director = $('span.comicParticulars-right-txt>a[href*="/author/"]')
.map((_, a) => $(a).text().trim())
.get()
.join('/')
bookDetail.book_content = $('p.intro').text().trim()
let data = JSON.parse(await this.fetch(this.siteUrl + `/comicdetail/${id}/chapters`, null, this.getHeader()))["results"]
let key = Crypto.enc.Utf8.parse('xxxmanga.woo.key');
let iv = Crypto.enc.Utf8.parse(data.substr(0, 16));
let src = Crypto.enc.Hex.parse(data.substr(16));
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
const groups = JSON.parse(dst).groups;
let urls = groups.default["chapters"]
.map((c) => {
return c.name + '$' + id + '|' + c.id;
})
.join('#');
bookDetail.volumes = '默認';
bookDetail.urls = urls;
bookDetail.book_id = id
return bookDetail
}
async parseVodShortListFromJson(obj) {
const books = [];
for (const book of obj) {
books.push(this.parseVodShortFromJson(book))
}
return books
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let page = pg || 1;
if (page === 0) page = 1;
let link = this.siteUrl + `/comics?theme=${extend.theme || ''}&region=${extend.region || ''}&status=${extend.status || ''}&ordering=${extend.ordering || '-datetime_updated'}`;
if (page > 1) {
link += '&offset=' + (page - 1) * 50 + '&limit=50';
}
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `/comic/${id}`)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setPlay(flag, id, flags) {
let info = id.split('|');
let $ = await this.getHtml(this.siteUrl + `/comic/${info[0]}/chapter/${info[1]}`);
const data = $('div.imageData')[0].attribs["contentkey"];
let key = Crypto.enc.Utf8.parse('xxxmanga.woo.key');
let iv = Crypto.enc.Utf8.parse(data.substr(0, 16));
let src = Crypto.enc.Hex.parse(data.substr(16));
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
const list = JSON.parse(dst);
let content = [];
for (let index = 0; index < list.length; index++) {
const element = list[index];
content[index] = element.url;
}
this.playUrl = {
"content": content,
}
}
async setSearch(wd, quick) {
let page = 1
const link = `${this.siteUrl}/api/kb/web/searcha/comics?offset=${page > 1 ? ((page - 1) * 12).toString() : ''}&platform=2&limit=12&q=${wd}&q_type=`;
let list = JSON.parse(await this.fetch(link, null, this.getHeader()))["results"]["list"]
this.vodList = await this.parseVodShortListFromJson(list)
}
}
let spider = new CopyManhuaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

View File

@ -0,0 +1,215 @@
/*
* @File : dj0898_book_open.js.js
* @Author : jade
* @Date : 2023/12/22 17:00
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import {Spider} from "./spider.js";
import {BookShort} from "../lib/book.js";
class DJ0898Spider extends Spider {
constructor() {
super();
this.siteUrl = "http://m.dj0898.com";
}
getName() {
return "🎵┃世纪DJ音乐网┃🎵"
}
getAppName() {
return "世纪DJ音乐网"
}
getJSName() {
return "dj0898_book_open"
}
getType() {
return 10
}
async parseVodShortListFromDoc($) {
let books = []
const list = $("ul.djddv_djList > li");
for (const it of list) {
let bookShort = new BookShort();
const a = $(it).find("a")[1];
bookShort.book_id = a.attribs.href
bookShort.book_pic = $(it).find("img:first")[0].attribs.src;
const tt = $(it).find("strong:first")[0];
bookShort.book_name = tt.children[0].data
bookShort.book_remarks = "🎵" + $(it).find("font")[5].children[0].data || ""
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
const list = $("ul.djddv_djList > li");
let videos = _.map(list, (it) => {
const a = $(it).find("a")[1];
const img = $(it).find("img:first")[0];
const tt = $(it).find("strong:first")[0];
const remarks = $(it).find("font")[5];
return {
book_id: a.attribs.href,
book_name: tt.children[0].data,
book_pic: img.attribs["src"],
book_remarks: "🎵" + remarks.children[0].data || "",
};
});
const hasMore = $("ul.page_link > li > a:contains(\u00a0)").length > 0;
this.page = hasMore ? parseInt(this.page) + 1 : parseInt(this.page);
return videos
}
async parseVodShortListFromDocBySearch($) {
const list = $("ul.djddv_djList > li");
return _.map(list, (it) => {
const a = $(it).find("a")[1];
const img = $(it).find("img:first")[0];
const tt = $(it).find("strong:first")[0];
const remarks = $(it).find("font:first")[0];
return {
book_id: a.attribs.href,
book_name: tt.children[0].data,
book_pic: img.attribs["src"],
book_remarks: "🎵" + remarks.children[0].data || "",
};
})
}
async parseVodDetailFromDoc(id) {
const vod = {
book_id: id,
audio: 1,
type_name: '',
book_year: '',
book_area: '',
book_remarks: '',
book_actor: '',
book_director: '',
book_content: '',
};
const playlist = ["点击播放" + "$" + vod.book_id];
vod.volumes = "世纪DJ音乐网";
vod.urls = playlist.join("#");
return vod
}
async setClasses() {
this.classes = [{type_id: 1, type_name: "🎧串烧舞曲"}, {type_id: 2, type_name: "🎧外文舞曲"}, {
type_id: 3,
type_name: "🎧早场暖场"
}, {type_id: 4, type_name: "🎧中文舞曲"}, {type_id: 5, type_name: "🎧其他舞曲"}, {
type_id: 6,
type_name: "🎧国外电音"
}, {type_id: 8, type_name: "🎧慢歌连版"}, {type_id: 9, type_name: "🎧酒吧潮歌"}, {
type_id: 10,
type_name: "🎧中文串烧"
}, {type_id: 11, type_name: "🎧外文串烧"}, {type_id: 12, type_name: "🎧中外串烧"}, {
type_id: 13,
type_name: "🎧车载串烧"
}, {type_id: 14, type_name: "🎧越鼓串烧"}, {type_id: 40, type_name: "🎧3D/环绕"}, {
type_id: 45,
type_name: "🎧口水旋律"
}, {type_id: 46, type_name: "🎧精品收藏"}, {type_id: 47, type_name: "🎧开场舞曲"}, {
type_id: 48,
type_name: "🎧印度舞曲"
}, {type_id: 49, type_name: "🎧编排套曲"}, {type_id: 20, type_name: "🎧DuTch"}, {
type_id: 21,
type_name: "🎧Mash up"
}, {type_id: 22, type_name: "🎧ClubHouse"}, {type_id: 23, type_name: "🎧ElectroHouse"}, {
type_id: 24,
type_name: "🎧越南鼓Dj"
}, {type_id: 30, type_name: "🎧Funky"}, {type_id: 31, type_name: "🎧Reggae"}, {
type_id: 32,
type_name: "🎧Rnb"
}, {type_id: 33, type_name: "🎧Hip Hop"}, {type_id: 34, type_name: "🎧Dubstep"}, {
type_id: 8017,
type_name: "🎧Hardstyle"
}, {type_id: 8018, type_name: "🎧Hands Up"}];
}
async setFilterObj() {
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl + "/dance/lists/id/10/1")
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
const link = this.siteUrl + "/dance/lists/id/" + tid + "/" + pg;
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailFromDoc(id);
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(id)
const audio = $("body audio[src*=http]");
this.playUrl = audio[0].attribs.src
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + "/index.php/dance/so/key?key=" + wd + "&cid=0&p=1")
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new DJ0898Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

246
JN/CATJS/js/doll.js Normal file
View File

@ -0,0 +1,246 @@
/*
* @File : doll.js
* @Author : jade
* @Date : 2024/1/4 14:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : doll
*/
import {Spider} from "./spider.js";
import {Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class Doll extends Spider {
constructor() {
super();
this.siteUrl = "https://hongkongdollvideo.com"
}
getImgHeader(){
let headers = this.getHeader()
headers["Proxy"] = true
return headers
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getImgHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getImgHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
return super.getHtml(url, true, headers);
}
getName() {
return "🔞┃玩偶姐姐┃🔞"
}
getAppName() {
return "玩偶姐姐"
}
getJSName() {
return "doll"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"row\"]").find("[class=\"video-detail\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
let videoInfoElements = $($(vodElement).find("[class=\"video-info\"]")).find("a")
vodShort.vod_name = videoInfoElements[0].attribs["title"]
vodShort.vod_remarks = $(videoInfoElements[1]).text()
let pic = $(vodElement).find("img")[0].attribs["data-src"]
// if (this.catOpenStatus) {
// vodShort.vod_pic = this.jsBase + Utils.base64Encode(pic)
// } else {
// vodShort.vod_pic = pic
// }
vodShort.vod_pic = pic
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($, key) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"container-fluid\"]")
vodDetail.vod_name = $($(vodElement).find("[class=\"page-title\"]")[0]).text()
vodDetail.vod_remarks = $(vodElement).find("[class=\"tag my-1 text-center\"]")[0].attribs["href"].replaceAll("/", "")
let pic = $(vodElement).find("video")[0].attribs["poster"]
// if (this.catOpenStatus) {
// vodDetail.vod_pic = this.jsBase + Utils.base64Encode(pic)
// } else {
// vodDetail.vod_pic = pic
// }
vodDetail.vod_pic = pic
let html = $.html()
let voteTag = Utils.getStrByRegex(/var voteTag="(.*?)";/g, html)
// let videoInfoStr = Utils.getStrByRegex(/<script type="application\/ld\+json">(.*?)<\/script>/g, html)
// let videoInfo = JSON.parse(videoInfoStr)
//
// try {
// let play_url_1 = await this.fetch(videoInfo["contentUrl"], null, this.getHeader())
// await this.jadeLog.debug(`播放链接为:${play_url_1}`)
// } catch (e) {
// await this.jadeLog.error(e)
// }
voteTag = Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(voteTag))
let code = []
for (let i = 0; i < voteTag.length; i++) {
let k = i % key.length;
code.push(String.fromCharCode(voteTag.charCodeAt(i) ^ key.charCodeAt(k)))
}
let play_url_2 = decodeURIComponent(Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(code.join(""))))
vodDetail.vod_play_from = "玩偶姐姐"
vodDetail.vod_play_url = "玩偶姐姐" + "$" + play_url_2
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"list-unstyled topnav-menu d-flex d-lg-block align-items-center justify-content-center flex-fill topnav-menu-left m-0\"]").find("li")
let index = 1
let class_id = index.toString()
this.classes = []
this.classes.push({"type_name": "首页", "type_id": "1"})
this.filterObj[class_id] = []
for (const navElement of navElements) {
let type_list = $(navElement).text().split("\n")
let valueElements = $(navElement).find("a")
let valueList = [{"n": "全部", "v": class_id}]
let type_id = index.toString()
for (const valueElement of valueElements) {
let title = $(valueElement).text().replaceAll("\n", "")
let href = valueElement.attribs["href"]
if (href !== undefined) {
valueList.push({"n": title, "v": href})
}
}
type_list = type_list.filter(element => element !== "");
this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": valueList})
//下面这段是为了切割使用
// let new_value_list = []
// for (let i = 0; i < valueList.length; i++) {
// new_value_list.push(valueList[i])
// if (i % 8 === 0 && i !== 0) {
// this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": new_value_list})
// new_value_list = []
// }
// }
// this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": new_value_list})
}
let menuElements = $("[id=\"side-menu\"]").find("li")
for (const menuElement of menuElements) {
let type_id = $(menuElement).find("a")[0].attribs["href"]
if (type_id !== undefined && type_id.indexOf(this.siteUrl) > -1) {
let type_dic = {
"type_name": $(menuElement).text(), "type_id": type_id
}
this.classes.push(type_dic)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (extend["1"] !== undefined) {
if (extend["1"] !== "1") {
tid = extend[1]
}
}
await this.jadeLog.info(`tid = ${tid}`)
let cateUrl = ""
if (tid.indexOf(this.siteUrl) > -1) {
cateUrl = tid + pg.toString() + ".html"
} else {
cateUrl = this.siteUrl
}
this.limit = 36
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
let key = Utils.getStrByRegex(/video\/(\w+).html/, id)
this.vodDetail = await this.parseVodDetailFromDoc($, key)
}
async setPlay(flag, id, flags) {
this.playUrl = id
this.playHeader = {}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + "search/" + encodeURIComponent(wd)
let $ = await this.getHtml(searchUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async proxy(segments, headers) {
return super.proxy(segments, headers);
}
}
let spider = new Doll()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

636
JN/CATJS/js/douban.js Normal file
View File

@ -0,0 +1,636 @@
/*
* @File : nivod.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
import {_, Crypto} from "../lib/cat.js";
class DoubanSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://frodo.douban.com/api/v2'
this.apiKey = "0ac44ae016490db2204ce0a042db2916"
this.UserAgents = ["api-client/1 com.douban.frodo/7.22.0.beta9(231) Android/23 product/Mate 40 vendor/HUAWEI model/Mate 40 brand/HUAWEI rom/android network/wifi platform/AndroidPad", "api-client/1 com.douban.frodo/7.18.0(230) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.1.0(205) Android/29 product/perseus vendor/Xiaomi model/Mi MIX 3 rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
}
getHeader() {
return {
"Host": "frodo.douban.com",
"Connection": "Keep-Alive",
"Referer": "https://servicewechat.com/wx2f9b06c1de1ccfca/84/page-frame.html",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat"
}
}
getSearchHeader() {
let randomNumber = Math.floor(Math.random() * this.UserAgents.length); // 生成一个介于0到9之间的随机整数
return {
'User-Agent': this.UserAgents[randomNumber]
}
}
getName() {
return "🍥┃豆瓣┃🍥"
}
getAppName() {
return "豆瓣"
}
getJSName() {
return "douban"
}
getType() {
return 3
}
async setClasses() {
let classes = [{
"type_name": "热门电影", "type_id": "hot_gaia"
}, {
"type_name": "热播剧集", "type_id": "tv_hot"
}, {
"type_name": "热播综艺", "type_id": "show_hot"
}, {
"type_name": "电影筛选", "type_id": "movie"
}, {
"type_name": "电视筛选", "type_id": "tv"
}, {
"type_name": "电影榜单", "type_id": "rank_list_movie"
}, {
"type_name": "电视剧榜单", "type_id": "rank_list_tv"
}]
for (const class_dic of classes) {
this.classes.push({"type_name": class_dic["type_name"], "type_id": class_dic["type_id"]})
}
}
async setFilterObj() {
this.filterObj = {
"hot_gaia": [{
"key": "sort", "name": "排序", "value": [{
"n": "热度", "v": "recommend"
}, {
"n": "最新", "v": "time"
}, {
"n": "评分", "v": "rank"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": "全部"
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}]
}], "tv_hot": [{
"key": "type", "name": "分类", "value": [{
"n": "综合", "v": "tv_hot"
}, {
"n": "国产剧", "v": "tv_domestic"
}, {
"n": "欧美剧", "v": "tv_american"
}, {
"n": "日剧", "v": "tv_japanese"
}, {
"n": "韩剧", "v": "tv_korean"
}, {
"n": "动画", "v": "tv_animation"
}]
}], "show_hot": [{
"key": "type", "name": "分类", "value": [{
"n": "综合", "v": "show_hot"
}, {
"n": "国内", "v": "show_domestic"
}, {
"n": "国外", "v": "show_foreign"
}]
}], "movie": [{
"key": "类型", "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": "短片"
}]
}, {
"key": "地区", "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": "丹麦"
}]
}, {
"key": "sort", "name": "排序", "value": [{
"n": "近期热度", "v": "T"
}, {
"n": "首映时间", "v": "R"
}, {
"n": "高分优先", "v": "S"
}]
}, {
"key": "年代", "name": "年代", "value": [{
"n": "全部年代", "v": ""
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2010年代", "v": "2010年代"
}, {
"n": "2000年代", "v": "2000年代"
}, {
"n": "90年代", "v": "90年代"
}, {
"n": "80年代", "v": "80年代"
}, {
"n": "70年代", "v": "70年代"
}, {
"n": "60年代", "v": "60年代"
}, {
"n": "更早", "v": "更早"
}]
}], "tv": [{
"key": "类型", "name": "类型", "value": [{
"n": "不限", "v": ""
}, {
"n": "电视剧", "v": "电视剧"
}, {
"n": "综艺", "v": "综艺"
}]
}, {
"key": "电视剧形式", "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": "音乐"
}]
}, {
"key": "综艺形式", "name": "综艺形式", "value": [{
"n": "不限", "v": ""
}, {
"n": "真人秀", "v": "真人秀"
}, {
"n": "脱口秀", "v": "脱口秀"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "歌舞", "v": "歌舞"
}]
}, {
"key": "地区", "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": "澳大利亚"
}]
}, {
"key": "sort", "name": "排序", "value": [{
"n": "近期热度", "v": "T"
}, {
"n": "首播时间", "v": "R"
}, {
"n": "高分优先", "v": "S"
}]
}, {
"key": "年代", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2010年代", "v": "2010年代"
}, {
"n": "2000年代", "v": "2000年代"
}, {
"n": "90年代", "v": "90年代"
}, {
"n": "80年代", "v": "80年代"
}, {
"n": "70年代", "v": "70年代"
}, {
"n": "60年代", "v": "60年代"
}, {
"n": "更早", "v": "更早"
}]
}, {
"key": "平台", "name": "平台", "value": [{
"n": "全部", "v": ""
}, {
"n": "腾讯视频", "v": "腾讯视频"
}, {
"n": "爱奇艺", "v": "爱奇艺"
}, {
"n": "优酷", "v": "优酷"
}, {
"n": "湖南卫视", "v": "湖南卫视"
}, {
"n": "Netflix", "v": "Netflix"
}, {
"n": "HBO", "v": "HBO"
}, {
"n": "BBC", "v": "BBC"
}, {
"n": "NHK", "v": "NHK"
}, {
"n": "CBS", "v": "CBS"
}, {
"n": "NBC", "v": "NBC"
}, {
"n": "tvN", "v": "tvN"
}]
}], "rank_list_movie": [{
"key": "榜单", "name": "榜单", "value": [{
"n": "实时热门电影", "v": "movie_real_time_hotest"
}, {
"n": "一周口碑电影榜", "v": "movie_weekly_best"
}, {
"n": "豆瓣电影Top250", "v": "movie_top250"
}]
}], "rank_list_tv": [{
"key": "榜单", "name": "榜单", "value": [{
"n": "实时热门电视", "v": "tv_real_time_hotest"
}, {
"n": "华语口碑剧集榜", "v": "tv_chinese_best_weekly"
}, {
"n": "全球口碑剧集榜", "v": "tv_global_best_weekly"
}, {
"n": "国内口碑综艺榜", "v": "show_chinese_best_weekly"
}, {
"n": "国外口碑综艺榜", "v": "show_global_best_weekly"
}]
}]
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const item of obj) {
let vod_short = new VodShort()
vod_short.vod_id = "msearch:" + item["id"]
if (item["title"] === undefined) {
vod_short.vod_name = item["target"]["title"]
} else {
vod_short.vod_name = item["title"]
}
if (item["pic"] === undefined) {
vod_short.vod_pic = item["target"]["cover_url"]
} else {
vod_short.vod_pic = item["pic"]["normal"]
}
if (item["rating"] === undefined) {
vod_short.vod_remarks = "评分:" + item["target"]["rating"]["value"].toString()
} else {
vod_short.vod_remarks = "评分:" + item["rating"]["value"].toString()
}
vod_list.push(vod_short);
}
return vod_list
}
get_tags(extend) {
let tag_list = []
for (const key of Object.keys(extend)) {
if (key !== "sort") {
tag_list.push(extend[key])
}
}
return tag_list.join(",")
}
sign(url, ts, method = 'GET') {
let _api_secret_key = "bf7dddc7c9cfe6f7"
let url_path = "%2F" + url.split("/").slice(3).join("%2F")
let raw_sign = [method.toLocaleUpperCase(), url_path, ts.toString()].join("&")
return Crypto.HmacSHA1(raw_sign, _api_secret_key).toString(Crypto.enc.Base64)
}
async setHomeVod() {
let url = this.siteUrl + "/subject_collection/subject_real_time_hotest/items"
let content = await this.fetch(url, {"apikey": this.apiKey}, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let items = content_json["subject_collection_items"]
this.homeVodList = await this.parseVodShortListFromJson(items)
}
}
async setCategory(tid, pg, filter, extend) {
let sort = extend["sort"] ?? "show_hot";
let tag_str = this.get_tags(extend)
this.count = 0
this.limit = 20;
this.total = 0;
let start = 0
if (parseInt(pg) > 1) {
start = (parseInt(pg) - 1) * this.limit
}
let cateUrl = ""
let params = {"start": start.toString(), "count": this.limit.toString()}
let itemKey = "items"
switch (tid) {
case "hot_gaia":
sort = extend["sort"] ?? "recommend"
let area = extend["area"] ?? "全部"
params["sort"] = sort
params["area"] = area
cateUrl = "/movie/hot_gaia"
break
case "tv_hot":
let type = extend["type"] ?? "tv_hot"
cateUrl = "/subject_collection/" + type + "/items"
itemKey = "subject_collection_items"
break
case "show_hot":
let showType = extend["type"] ?? "show_hot"
cateUrl = "/subject_collection/" + showType + "/items"
itemKey = "subject_collection_items";
break
case "movie":
params["sort"] = sort
params["tags"] = tag_str
cateUrl = "/movie/recommend"
break
case "tv":
params["sort"] = sort
params["tags"] = tag_str
cateUrl = "/tv/recommend"
break
case "rank_list_movie":
let rankMovieType = extend["榜单"] ?? "movie_real_time_hotest"
cateUrl = "/subject_collection/" + rankMovieType + "/items"
itemKey = "subject_collection_items"
break
case "rank_list_tv":
let rankTVType = extend["榜单"] ?? "tv_real_time_hotest"
cateUrl = "/subject_collection/" + rankTVType + "/items"
itemKey = "subject_collection_items"
break
default:
break
}
params["apikey"] = this.apiKey
let content = await this.fetch(this.siteUrl + cateUrl, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let items = content_json[itemKey]
this.vodList = await this.parseVodShortListFromJson(items)
}
}
async setSearch(wd, quick, pg) {
let _api_url = "https://frodo.douban.com/api/v2"
let _api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
let url = _api_url + "/search/movie"
let date = new Date()
let ts = date.getFullYear().toString() + ('0' + (date.getMonth() + 1)).slice(-2).toString() + date.getDate().toString()
const limit = 20
let params = {
'_sig': this.sign(url, ts),
'_ts': ts,
'apiKey': _api_key,
'count': limit,
'os_rom': 'android',
'q': encodeURIComponent(wd),
'start': parseInt(pg)
}
let content = await this.fetch(url, params, this.getSearchHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
this.vodList = await this.parseVodShortListFromJson(content_json["items"])
const page = parseInt(pg);
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
}
}
let spider = new DoubanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

75
JN/CATJS/js/dubo.js Normal file
View File

@ -0,0 +1,75 @@
/*
* @File : dubo.js
* @Author : jade
* @Date : 2024/4/16 18:46
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {TianTianSpider} from "./tiantian.js"
class DuboSpider extends TianTianSpider {
constructor() {
super();
this.siteUrl = "http://v.rbotv.cn"
this.cookie = ""
this.extendObj = {"extend": "类型", "area": "地区", "year": "年代"}
this.parseMap = {};
}
getName() {
return "🛶┃独播影视┃🛶"
}
getAppName() {
return "独播影视"
}
getJSName() {
return "dubo"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = false
}
}
let spider = new DuboSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

280
JN/CATJS/js/dygangs.js Normal file
View File

@ -0,0 +1,280 @@
/*
* @File : dygangs.js
* @Author : jade
* @Date : 2024/2/21 15:06
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 电影港
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {_, load} from "../lib/cat.js";
class MoviePortSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.dygangs.org"
}
getAppName() {
return "电影港"
}
getName() {
return "🏖️┃电影港┃🏖️"
}
getJSName() {
return "dygangs"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"top-nav\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = navElement.attribs.href.replaceAll(this.siteUrl, "")
let type_name = $(navElement).text()
if (type_id !== "/") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($, index) {
let element = $("[class=\"nav-down-2 clearfix\"]")[index]
let extend_list = []
if (element !== undefined) {
let name = "按类型"
let extend_dic = {"key": name, "name": name, "value": []}
extend_dic["name"] = name
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(element).find("a")) {
let type_name = $(ele).html()
let type_id = ele.attribs.href.split("/").slice(-2)[0]
extend_dic["value"].push({"n": type_name, "v": type_id})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
let index = 0
for (const type_dic of this.classes.slice(1, 5)) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `${type_id}`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($, index)
}
index = index + 1
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $(element).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(element).find("i")[0]).text().replaceAll(" ", "").replaceAll("\n", "")
if (_.isEmpty(vodShort.vod_pic)){
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dygang.jpg"
}
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"index-tj-l\"]").find("li")
for (const vodElement of vodElements) {
let vodShortElement = $(vodElement).find("a")[0]
let vodShort = this.parseVodShortFromElement($, vodShortElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"index-area clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShortElement = $(vodElement).find("a")[0]
let vodShort = this.parseVodShortFromElement($, vodShortElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodDetailElement = $("[ class=\"ct mb clearfix\"]")
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs["src"]
vodDetail.vod_name = Utils.getStrByRegex(/◎片  名 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_area = Utils.getStrByRegex(/◎产  地 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_year = Utils.getStrByRegex(/◎年  代 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.type_name = Utils.getStrByRegex(/◎类  别 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_remarks = Utils.getStrByRegex(/◎集  数 (.*?)<br>/, $(vodDetailElement).html())
let content = Utils.getStrByRegex(/   (.*?)<\/p>/s, $(vodDetailElement).html())
if (_.isEmpty(content)) {
content = Utils.getStrByRegex(/   (.*?)<\/p>/s, $(vodDetailElement).html())
}
let actor_list = []
for (const actor of content.split("\n")) {
actor_list.push(actor.replaceAll("    &nbsp;  ", "").replaceAll("<br>", "").replaceAll("     ", ""))
}
vodDetail.vod_actor = actor_list.join("/")
vodDetail.vod_director = Utils.getStrByRegex(/◎导  演 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_content = Utils.getStrByRegex(/  <\/p>(.*?)<br>/s, $(vodDetailElement).html()).replaceAll("<p>", "").replaceAll("\n", "")
if (_.isEmpty(vodDetail.vod_content)) {
vodDetail.vod_content = Utils.getStrByRegex(/  <br>(.*?)<\/p>/s, $(vodDetailElement).html()).replaceAll("<p>", "").replaceAll("\n", "")
}
let vod_play_from_list = []
let vod_play_list = []
let playFormatElements = $("[class=\"playfrom tab8 clearfix\"]")
let playUrlElements = $("[class=\"videourl clearfix\"]")
for (let i = 0; i < playFormatElements.length; i++) {
let playFormatElement = playFormatElements[i]
let format_name = $($(playFormatElement).find("li")).html()
vod_play_from_list.push(format_name.replaceAll("<i class=\"playerico ico-Azhan\"></i> ", ""))
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = playUrlElement.attribs.title
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
let playFormatElement = $($(vodDetailElement).find("span")[0]).find("span")
if (playFormatElement.length > 0) {
let format_name = $(playFormatElement).html()
vod_play_from_list.push(Utils.getStrByRegex(/【(.*?)】/, format_name.replaceAll("下载地址", "磁力链接")))
let vodItems = []
for (const playUrlElement of $($($(vodDetailElement).find("tbody")).find("tr")).find("a")) {
let episodeName = $(playUrlElement).html().replaceAll(".mp4", "")
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid
if (extend["按类型"] !== undefined && extend["按类型"] !== "0") {
url = url + `${extend["按类型"]}/`
}
if (parseInt(pg) > 1) {
url = url + `index_${pg}.html`
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/e/search/index.php"
let params = {"keyboard": wd, "submit": "搜 索", "show": "title,zhuyan", "tempid": "1"}
let resp = await this.post(url, params, this.getHeader())
let $ = load(resp)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
if (id.indexOf("http") > -1) {
let $ = await this.getHtml(id)
let url = Utils.getStrByRegex(/url: '(.*?)',/, $.html())
if (_.isEmpty(url)) {
let videoUrl = $($("[class=\"video\"]")[0]).find("iframe")[0].attribs["src"]
let html = await this.fetch(videoUrl, null, {"User-Agent": Utils.CHROME})
this.playUrl = Utils.getStrByRegex(/url: '(.*?)',/, html)
if (_.isEmpty(this.playUrl)){
let urlHost = Utils.getHost(videoUrl)
this.playUrl = urlHost + Utils.getStrByRegex(/var main = "(.*?)";/, html)
}
} else {
this.playUrl = url
}
} else {
this.playUrl = id
}
}
}
let spider = new MoviePortSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

214
JN/CATJS/js/dyttbt.js Normal file
View File

@ -0,0 +1,214 @@
/*
* @File : freeok.js
* @Author : jade
* @Date : 2024/1/19 10:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 电影天堂(已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class DyttSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.dy2018.com"
this.dyttReconnectTimes = 0
}
getName() {
return `👼┃电影天堂BT┃👼`
}
getAppName() {
return "电影天堂BT"
}
getJSName() {
return "dyttbt"
}
getType() {
return 3
}
// getHeader() {
// return {"User-Agent": "PostmanRuntime/7.36.1", "Host":"www.dy2018.com"};
// }
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
try {
let buffer = await this.fetch(url, null, headers, false, false, 1)
let html = Utils.decode(buffer, "gb2312")
if (!_.isEmpty(html) && Utils.getStrByRegex(/<script src="(.*?)"><\/script>/, html) !== "/_guard/auto.js") {
return load(html)
} else {
if (this.dyttReconnectTimes < this.maxReconnectTimes) {
Utils.sleep(2)
this.dyttReconnectTimes = this.dyttReconnectTimes + 1
return await this.getHtml(url, headers)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
} catch (e) {
await this.jadeLog.error(`获取html出错,出错原因为${e}`)
}
}
async setFilterObj() {
}
async setClasses() {
let $ = await this.getHtml()
let vodShortElements = $("[class=\"title_all\"]")
for (const vodShortElement of vodShortElements) {
let spanElement = $(vodShortElement).find("span")[0]
let aElement = $(vodShortElement).find("a")[0]
let type_name = $(spanElement).text()
let type_id = aElement.attribs["href"]
if (type_id.indexOf("https:") === -1 && type_id.indexOf("http:") === -1) {
type_id = this.siteUrl + type_id
}
this.classes.push(this.getTypeDic(type_name, type_id))
}
let containElements = $($("[id=\"menu\"]").find("[class=\"contain\"]")).find("a").slice(0, -3)
for (const contaElement of containElements) {
let type_name = $(contaElement).text()
let type_id = contaElement.attribs["href"]
if (type_id.indexOf("https:") === -1 && type_id.indexOf("http:") === -1) {
type_id = this.siteUrl + type_id
}
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodShortElements = $($("[class=\"co_content8\"]")[0]).find("tbody")
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElements = $(vodShortElement).find("tr")
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/, $(vodElements[1]).text())
vodShort.vod_id = $(vodElements[1]).find("a").slice(-1)[0].attribs.href
vodShort.vod_remarks = "日期:" + Utils.getStrByRegex(/日期:(.*?) /, $(vodElements[2]).text()) + " 热度:" + Utils.getStrByRegex(/点击:(.*?) /, $(vodElements[2]).text())
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dytt.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodShortElements = $($("[class=\"co_area2\"]")[0]).find("li").slice(1)
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElement = $(vodShortElement).find("a")[0]
vodShort.vod_id = vodElement.attribs["href"]
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/, vodElement.attribs["title"])
vodShort.vod_remarks = $($(vodShortElement).find("span")).text().replaceAll("", "")
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dytt.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = Utils.getStrByRegex(/《(.*?)》/, Utils.getStrByRegex(/<title>(.*?)<\/title>/, $.html()))
let zoomElement = $("[id=\"Zoom\"]")
vodDetail.vod_pic = $(zoomElement).find("img")[0].attribs.src
let content = $(zoomElement).text()
vodDetail.vod_year = Utils.getStrByRegex(/年  代 (.*?)◎/, content)
vodDetail.type_name = Utils.getStrByRegex(/类  别 (.*?)◎/, content)
vodDetail.vod_area = Utils.getStrByRegex(/产  地 (.*?)◎/, content)
vodDetail.vod_director = Utils.getStrByRegex(/导  演 (.*?)◎/, content)
vodDetail.vod_content = Utils.getStrByRegex(/简  介 (.*?)◎/, content)
vodDetail.vod_actor = Utils.getStrByRegex(/主  演(.*?)◎/, content).replaceAll("      ", "*")
vodDetail.vod_remarks = Utils.getStrByRegex(/豆瓣评分 (.*?)\//, content)
vodDetail.vod_play_from = "磁力链接"
let playList = $(zoomElement).find("[class=\"player_list\"]").find("a")
let vodItems = []
for (const playEle of playList) {
vodItems.push($(playEle).text() + "$" + playEle.attribs.href);
}
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let cateUrl = tid
if (tid.indexOf("index") > -1){
cateUrl = tid.split(".html")[0] + "_" + pg + ".html"
}
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
let spider = new DyttSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

96
JN/CATJS/js/feifan.js Normal file
View File

@ -0,0 +1,96 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 非凡资源
*/
import {VodSpider} from "./vodSpider.js";
class FeiFanSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = true
this.type_id_18 = 34
}
getAppName() {
return "非凡资源"
}
getName() {
return "🥗┃非凡资源┃🥗"
}
getJSName() {
return "feifan"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new FeiFanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

96
JN/CATJS/js/feifan18.js Normal file
View File

@ -0,0 +1,96 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 非凡资源
*/
import {VodSpider} from "./vodSpider.js";
class FeiFan18Spider extends VodSpider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = false
this.type_id_18 = 34
}
getAppName() {
return "非凡资源18+"
}
getName() {
return "🔞┃非凡资源18+┃🔞"
}
getJSName() {
return "feifan18"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new FeiFan18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

333
JN/CATJS/js/freeok.js Normal file
View File

@ -0,0 +1,333 @@
/*
* @File : freeok.js
* @Author : jade
* @Date : 2024/1/19 10:26
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : OK资源网 已失效
*/
import {_} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {player} from "../lib/freeok_setttings.js";
const OCR_API = 'https://api.nn.ci/ocr/b64/text';//ocr在线识别接口
class OkSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.freeok.vip"
}
getName() {
return `🆗┃OK资源网┃🆗`
}
getAppName() {
return `OK资源网`
}
getJSName() {
return "freeok"
}
getType() {
return 3
}
async init(cfg) {
this.cookie = await this.load_cache()
await super.init(cfg);
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"module\"]")).find("a").slice(0, 12)
for (const vodElement of vodElements) {
vod_list.push(this.parseVodShortFromElement($, vodElement))
}
return vod_list
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_name = element.attribs["title"]
vodShort.vod_id = element.attribs["href"]
vodShort.vod_remarks = $($(element).find("[class=\"module-item-note\"]")).text()
vodShort.vod_pic = $(element).find("[class=\"lazy lazyload\"]")[0].attribs["data-original"]
return vodShort
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let itemElements = $($("[class=\"module-items module-poster-items-base \"]")).find("a")
for (const itemElement of itemElements) {
vod_list.push(this.parseVodShortFromElement($, itemElement))
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const result of obj["Data"]["result"]){
let vodShort = new VodShort()
vodShort.vod_id = result["vod_url"].replaceAll(this.siteUrl,"")
vodShort.vod_pic = result["vod_pic"]
vodShort.vod_name = result["vod_name"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByHot($) {
let vod_list = []
let itemElement = $($("[class=\"module-items module-card-items\"]"))[0]
let titleElements = $(itemElement).find("[class=\"module-card-item-title\"]").find("a")
let infoElements = $(itemElement).find("[class=\"module-card-item-info\"]")
let picElements = $(itemElement).find("[class=\"module-item-pic\"]").find("img")
for (let i = 0; i < titleElements.length; i++) {
let vodShort = new VodShort();
vodShort.vod_id = titleElements[i].attribs["href"]
vodShort.vod_name = $(titleElements[i]).text()
vodShort.vod_pic = picElements[i].attribs["data-original"]
vodShort.vod_remarks = $($(infoElements[i])).text().split("\n")[5]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let moudleElements = $("[class=\"module-info-tag-link\"]").find("a")
let mobilePlay = $("[class=\"module-mobile-play\"]").find("a")[0]
vodDetail.vod_name = mobilePlay.attribs["title"].replaceAll("立刻播放", "")
vodDetail.vod_content = $($("[class=\"module-info-introduction-content\"]")).text().replaceAll("\n", "").replaceAll(" ", "")
let type_list = []
for (const moudleElement of moudleElements.slice(2)) {
type_list.push($(moudleElement).text())
}
vodDetail.type_name = type_list.join("/")
vodDetail.vod_year = $(moudleElements[0]).text()
vodDetail.vod_area = $(moudleElements[1]).text()
let itemElements = $("[class=\"module-info-item\"]")
let itemText = ""
for (const itemElement of itemElements) {
itemText = itemText + $(itemElement).text().replaceAll("\n", "").replaceAll("", ":") + "\n"
}
vodDetail.vod_pic = $("[class=\"module-item-pic\"]").find("img")[0].attribs["data-original"]
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?)\n/, itemText)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?)\n/, itemText)
vodDetail.vod_year = Utils.getStrByRegex(/上映:(.*?)\n/, itemText)
vodDetail.vod_remarks = Utils.getStrByRegex(/备注:(.*?)\n/, itemText)
if (_.isEmpty(vodDetail.vod_remarks)) {
vodDetail.vod_remarks = Utils.getStrByRegex(/集数:(.*?)\n/, itemText)
}
let playElements = $($("[class=\"module-tab-items-box hisSwiper\"]")).find("span")
let play_from_list = []
let playUrlElements = $("[class=\"module-list sort-list tab-list his-tab-list\"]")
let play_url_list = []
for (let i = 0; i < playElements.length; i++) {
let text = $(playElements[i]).text()
if (text.indexOf("夸克") === -1) {
let playDetailElements = $(playUrlElements[i]).find("a")
let vodItems = []
for (const playDetailElement of playDetailElements) {
let play_name = playDetailElement.attribs["title"].replaceAll("播放", "").replaceAll(vodDetail.vod_name, "")
let play_url = playDetailElement.attribs["href"]
vodItems.push(`${play_name}$${play_url}`)
}
play_url_list.push(vodItems.join("#"))
play_from_list.push($(playElements[i]).text())
}
}
vodDetail.vod_play_from = play_from_list.join("$$$")
vodDetail.vod_play_url = play_url_list.join("$$$")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl, this.getHeader())
let navElements = $($("[class=\"navbar-items swiper-wrapper\"]")).find("a")
let type_name = $(navElements.slice(0, 8).slice(-1)[0]).text().replaceAll("\n", "")
let type_id = navElements.slice(0, 8).slice(-1)[0].attribs["href"]
this.classes.push({"type_name": type_name, "type_id": type_id})
for (const navElement of navElements.slice(0, 8)) {
let type_name = $(navElement).text().replaceAll("\n", "")
if (type_name !== "首页" && type_name !== "热榜") {
let type_id = navElement.attribs["href"].split("/").slice(-1)[0].split(".")[0]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
}
}
async getFilter($) {
let titleElements = $("[class=\"module-item-title\"]")
let boxElements = $("[class=\"module-item-box\"]")
let extend_list = []
let type_id_dic = {"类型": 1, "剧情": 4, "地区": 2, "语言": 5, "年份": 12, "排序": 3}
for (let i = 0; i < titleElements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": $(titleElements[i]).text(), "value": []}
let typeElements = $(boxElements[i]).find("a")
for (let j = 0; j < typeElements.length; j++) {
let type_name = $(typeElements[j]).text()
let type_id = decodeURIComponent(typeElements[j].attribs["href"].split("-")[type_id_dic[$(titleElements[i]).text()]]).replaceAll(".html", "")
extend_dic["value"].push({"n": type_name, "v": $(titleElements[i]).text() + "-" + type_id})
}
extend_list.push(extend_dic)
}
return extend_list;
}
async setFilterObj() {
for (const class_dic of this.classes) {
if (class_dic["type_name"] !== "最近更新" && class_dic["type_name"] !== "热榜") {
let cateUrl = this.siteUrl + `/vod-show/${class_dic["type_id"]}--------1---.html`
let $ = await this.getHtml(cateUrl, this.getHeader())
this.filterObj[class_dic["type_id"]] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl, this.getHeader())
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getCateUrl(tid, pg, extend) {
let value_list = Object.values(extend)
let type_id_dic = {"类型": 1, "剧情": 3, "地区": 1, "语言": 4, "年份": 11, "排序": 2}
let urlParams = [tid.toString(), "", "","","", "", "", "", "", "", "",""]
urlParams[8] = pg.toString()
for (const value of value_list) {
if (value.split("-")[0] === "类型") {
urlParams[0] = value.split("-")[1].split("show/")[1].toString()
} else {
let type_index = type_id_dic[value.split("-")[0]]
urlParams[type_index] = value.split("-")[1]
}
}
return this.siteUrl + `/vod-show/` + urlParams.join("-") + ".html"
}
async setCategory(tid, pg, filter, extend) {
let cateUrl
if (tid.indexOf(".html") > -1) {
cateUrl = this.siteUrl + tid
let $ = await this.getHtml(cateUrl, this.getHeader());
this.vodList = await this.parseVodShortListFromDocByHot($)
} else {
cateUrl = this.getCateUrl(tid, pg, extend)
let $ = await this.getHtml(cateUrl, this.getHeader());
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
async setSearch(wd, quick) {
let url = `http://123.207.150.253/zxapi/public/?service=App.F.Fetch&req_p=${wd}&type=okys`
let content = await this.fetch(url,null,this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async refreshCookie() {
let passUrl = this.siteUrl + "/index.php/verify/index.html?"
let passHtml = await this.fetch(passUrl,null,this.getHeader(),false,true)
let response2 = await this.post(OCR_API,passHtml["content"],this.getHeader())
this.cookie = Utils.getStrByRegex(/(.*?);/,passHtml["cookie"])
let verifyUrl = this.siteUrl + "/index.php/ajax/verify_check?type=search&verify=5286"
let headers = this.getHeader()
headers["cookie"] = this.cookie
let response = await this.post(verifyUrl,null,headers)
await this.write_cache()
}
async load_cache() {
try {
return await local.get("freeok_cookie", "cookie")
} catch (e) {
return ""
}
}
async write_cache() {
await local.set("freeok_cookie", "cookie", JSON.stringify(this.cookie))
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id, this.getHeader())
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id, this.getHeader())
const js = JSON.parse($('script:contains(player_)').html().replace('var player_aaaa=', ''));
let url = this.siteUrl + "/okplayer/"
let params = {
"url": decodeURIComponent(js.url), "next": decodeURIComponent(js.url_next), "title": js.vod_data.vod_name
}
let playHtml = await this.fetch(url, params, this.getHeader());
let view_port_id = Utils.getStrByRegex(/<meta name="viewport"(.*?)>/, playHtml).split("id=\"")[1].replaceAll("now_", "")
let player_id = Utils.getStrByRegex(/meta charset="UTF-8" id="(.*?)">/, playHtml).replaceAll("now_", "")
let player_url = Utils.getStrByRegex(/"url": "(.*?)",/, playHtml)
this.playUrl = player(player_url, view_port_id, player_id)
}
}
let spider = new OkSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

231
JN/CATJS/js/gitcafe.js Normal file
View File

@ -0,0 +1,231 @@
/*
* @File : gitcafe.js
* @Author : jade
* @Date : 2024/1/18 9:56
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 阿里纸条
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import { detailContent,initCloud,playContent,getHeaders} from "../lib/cloud.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class GitCafeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://ali.gitcafe.ink"
}
getName() {
return "🦊┃阿里纸条┃🦊"
}
getAppName() {
return "阿里纸条"
}
getJSName() {
return "gitcafe"
}
getType() {
return 3
}
async getApiUrl() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let paper_js_url = Utils.getStrByRegex(/<script src='(.*?)'><\/script>/, html)
let paper_js_content = await this.fetch(paper_js_url, null, this.getHeader())
return {
"api": "https:" + Utils.getStrByRegex(/ return '(.*?)' \+ /, paper_js_content) + new Date().getTime(),
"search_api": Utils.getStrByRegex(/const SEARCH_API = '(.*?)';/, paper_js_content)
}
}
}
async getContentJson() {
let url_json = await this.getApiUrl()
let content = await this.fetch(url_json["api"], null, this.getHeader())
this.search_api = url_json["search_api"]
if (!_.isEmpty(content)) {
return JSON.parse(content)
}
}
async spiderInit() {
this.content_json = await this.getContentJson()
this.token_dic = await this.load_cache()
}
async init(cfg) {
await this.spiderInit()
await super.init(cfg);
await initCloud(this.cfgObj);
}
async parseClassFromJson(obj) {
let data_list = Object.keys(obj["data"]).slice(0, 19)
for (const data_key of data_list) {
this.classes.push({"type_name": obj["data"][data_key]["name"], "type_id": data_key})
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
let class_id_list = this.getClassIdList()
for (const data_obj of obj) {
let vodShort = new VodShort()
if (class_id_list.includes(data_obj["cat"])) {
vodShort.vod_id = JSON.stringify(data_obj)
vodShort.vod_name = data_obj["title"]
vodShort.vod_remarks = data_obj["date"]
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let classNamesList = this.getClassNameList()
let classIdList = this.getClassIdList()
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["title"]
vodDetail.vod_remarks = obj["creatime"] ?? obj["date"]
vodDetail.type_name = classNamesList[classIdList.indexOf(obj["cat"])]
vodDetail.vod_content = obj["des"]
let ali_url = "https://www.aliyundrive.com/s/" + obj["alikey"]
let playVod = await detailContent([ali_url],vodDetail.type_name)
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setClasses() {
await this.parseClassFromJson(this.content_json)
}
async setHomeVod() {
this.homeVodList = await this.parseVodShortListFromJson(this.content_json["info"]["new"])
}
async setDetail(id) {
let content_json = JSON.parse(id)
this.vodDetail = await this.parseVodDetailfromJson(content_json)
}
async setCategory(tid, pg, filter, extend) {
this.vodList = await this.parseVodShortListFromJson(this.content_json["data"][tid]["catdata"])
}
async setSearch(wd, quick) {
await this.refreshToken();
let params = {
"action": "search", "from": "web", "token": this.token_dic["token"], "keyword": wd
}
let content = await this.post(this.search_api, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
this.vodList = await this.parseVodShortListFromJson(content_json["data"])
}
}
async refreshToken() {
let this_time = new Date().getTime()
if (_.isEmpty(this.token_dic["token"])) {
await this.get_token()
await this.jadeLog.debug("Token为空,刷新Token")
} else if (this_time - parseInt(this.token_dic["date"]) > 24 * 60 * 60 * 1000) {
await this.jadeLog.debug(`Token到期,上次获取Token时间为:${this_time},当前时间为:${parseInt(this.token_dic["date"])},刷新Token`)
await this.get_token()
} else {
await this.jadeLog.debug(`Token仍然有效,无需刷新`, true)
}
}
async get_token() {
try {
let params = {
"action": "get_token", "from": "web",
}
let content = await this.post(this.search_api, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let this_time = new Date().getTime()
this.token_dic["token"] = content_json["data"]
this.token_dic["date"] = this_time.toString()
await this.write_cache()
}
} catch (e) {
await this.jadeLog.error("获取Token失败,失败原因为:" + e)
}
}
async write_cache() {
await local.set("gitcafe_token", "token", JSON.stringify(this.token_dic))
}
async load_cache() {
try {
let str = await local.get("gitcafe_token", "token")
return JSON.parse(str)
} catch (e) {
return {"token": "", "date": ""}
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
let spider = new GitCafeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

156
JN/CATJS/js/haiwaikan.js Normal file
View File

@ -0,0 +1,156 @@
/*
* @File : haiwaikan.js
* @Author : jade
* @Date : 2024/04/02 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 海外看
*/
import {VodSpider} from "./vodSpider.js";
class HaiWaiKanSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://haiwaikan.com"
this.remove18 = true
this.type_id_18 = 0
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getAppName() {
return "海外看"
}
getName() {
return "☕┃海外看┃☕墙"
}
getJSName() {
return "haiwaikan"
}
getType() {
return 3
}
async setClasses() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const class_dic of content_json["class"]) {
if (class_dic["type_id"] < 26 ) {
this.classes.push(this.getTypeDic(class_dic["type_name"], class_dic["type_id"].toString()))
}
}
this.content_json = content_json
}
async getFilter(type_id,obj) {
let extend_list = []
let extend_dic = {"key": "1", "name": "全部类别", "value": [{"n":"全部类别","v":type_id.toString()}]}
for (const type_dic of obj["class"]){
let a_type_id = type_dic["type_id"]
let max_type_id = 0
let min_type_id = 0
if (type_id === 20){
max_type_id = 50
min_type_id = 27
}
if (type_id === 21){
max_type_id = 128
min_type_id = 100
}
if (type_id === 22){
max_type_id = 143
min_type_id = 134
}
if (type_id === 23){
max_type_id = 135
min_type_id = 127
}
if (a_type_id < max_type_id && a_type_id > min_type_id){
extend_dic["value"].push({"n":type_dic["type_name"],"v":a_type_id.toString()})
}
}
if (extend_dic["value"].length > 1){
extend_list.push(extend_dic)
return extend_list
}else{
return null
}
}
async setFilterObj() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const type_dic of this.classes){
let type_id = type_dic["type_id"]
if (type_id !== "最近更新"){
let extend_list = await this.getFilter(parseInt(type_id),content_json)
if (extend_list !== null){
this.filterObj[type_id] = extend_list
}
}
}
}
}
let spider = new HaiWaiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

625
JN/CATJS/js/hanxiucao.js Normal file
View File

@ -0,0 +1,625 @@
/*
* @File : hanxiucao.js
* @Author : jade
* @Date : 2024/04/13 19:38
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, Crypto} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {Spider} from "./spider.js";
import * as Utils from "../lib/utils.js";
function He(e, {key: t, iv: s} = {}) {
let VITE_APP_AES_KEY = "B77A9FF7F323B5404902102257503C2F"
let VITE_APP_AES_IV = "B77A9FF7F323B5404902102257503C2F"
var o = Crypto.enc.Utf8.parse(e)
, A = Crypto.AES.encrypt(o, Crypto.enc.Utf8.parse(t || VITE_APP_AES_KEY), {
iv: Crypto.enc.Utf8.parse(s || VITE_APP_AES_IV),
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
});
return Crypto.enc.Base64.stringify(A.ciphertext)
}
function Kt() {
const e = new Date;
return He(parseInt(e.getTime() / 1e3) + e.getTimezoneOffset() * 60 + -1)
}
function bt(e) {
const wA = "46cc793c53dc451b"
let t = Crypto.enc.Utf8.parse(wA)
, s = Crypto.AES.decrypt(e, t, {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7
});
return Crypto.enc.Utf8.stringify(s).toString()
}
class HanXiuCaoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.qianyuewenhua.xyz"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "imgBt", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'imgBt/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.spiderInit(null)
}
getAppName() {
return "含羞草"
}
getName() {
return "🔞┃含羞草┃🔞"
}
getJSName() {
return "hanxiucao"
}
getType() {
return 3
}
getParams(params) {
return {"endata": He(JSON.stringify(params)), "ents": Kt()}
}
async setClasses() {
let params = this.getParams({"channel": "pc"})
let response = await this.post(this.siteUrl + "/panel/list", params, this.getHeader(), "")
let resJson = JSON.parse(response)
for (const data of resJson["data"]["list"]) {
let type_id = data["panelId"]
let type_name = data["panelName"]
if (type_name !== "首页") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter(Layouts) {
let extend_list = []
for (const data of Layouts) {
let layoutObj = JSON.parse(data["layoutContent"])
for (const layout of layoutObj["sortKeys"]) {
let extend_dic = {}
if (layout["label"] !== "综合排序") {
extend_dic = {"key": "sorts", "name": layout["label"].toString(), value: []}
extend_dic["value"].push({"n": "升序", "v": layout["value"].toString() + "-" + "升序"})
extend_dic["value"].push({"n": "降序", "v": layout["value"].toString() + "-" + "降序"})
} else {
extend_dic = {"key": "sorts", "name": "排序", value: []}
extend_dic["value"].push({"n": layout["label"].toString(), "v": layout["value"].toString()})
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async getNvYouFilter(Layouts) {
let extend_list = []
let params = {
"uids": [],
"page": 1,
"length": 20
}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
let layoutObj = JSON.parse(data["layoutContent"])
params["uids"] = layoutObj["list"]
let resJson = JSON.parse(await this.post(this.siteUrl + "/user/getUpList", this.getParams(params), this.getHeader(), ""))
let extend_dic = {"key": `tags`, "name": data["layoutName"], value: []}
for (const layout of resJson["data"]["list"]) {
extend_dic["value"].push({"n": layout["user_nicename"], "v": JSON.stringify(layout)})
}
extend_list.push(extend_dic)
}
let sort_list = [
{
"key": "sorts",
"name": "发布时间",
"value": [
{
"n": "升序",
"v": "1-升序"
},
{
"n": "降序",
"v": "1-降序"
}
]
},
{
"key": "sorts",
"name": "点赞数量",
"value": [
{
"n": "升序",
"v": "5-升序"
},
{
"n": "降序",
"v": "5-降序"
}
]
},
{
"key": "sorts",
"name": "收藏数量",
"value": [
{
"n": "升序",
"v": "6-升序"
},
{
"n": "降序",
"v": "6-降序"
}
]
}
]
return [...extend_list, ...sort_list]
}
async getZhuanTiFilter(Layouts) {
let extend_list = []
let params = {
"page": 1,
"length": 36,
"subjectIds": []
}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
let layoutObj = JSON.parse(data["layoutContent"])
params["subjectIds"] = layoutObj["list"]
let resJson = JSON.parse(await this.post(this.siteUrl + "/subject/list", this.getParams(params), this.getHeader(), ""))
let extend_dic = {"key": `tags`, "name": data["layoutName"], value: []}
for (const layout of resJson["data"]["list"]) {
extend_dic["value"].push({"n": layout["name"], "v": JSON.stringify(layout)})
}
extend_list.push(extend_dic)
}
let sort_dic = {
"key": "sorts",
"name": "排序",
"value": [
{
"n": "推荐",
"v": "8"
},
{
"n": "最新",
"v": "1"
},
{
"n": "最热",
"v": "2"
}
]
}
extend_list.push(sort_dic)
return extend_list
}
async getChuanMeiFilter(Layouts) {
let extend_list = []
let extend_dic = {"key": `tags`, "name": "传媒", value: []}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
extend_dic["value"].push({"n": data["layoutName"], "v": data["layoutContent"]})
}
extend_list.push(extend_dic)
for (const layout of JSON.parse(Layouts[0]["layoutContent"])["moreOrderType"]) {
extend_dic = {"key": "sorts", "name": layout["label"].toString(), value: []}
extend_dic["value"].push({"n": "升序", "v": layout["value"].toString() + "-" + "升序"})
extend_dic["value"].push({"n": "降序", "v": layout["value"].toString() + "-" + "降序"})
extend_list.push(extend_dic)
}
extend_list.push(extend_dic)
return extend_list
}
async getHeJiFilter(Layouts) {
let extend_list = []
let params = {
"page": 1,
"length": 24,
"gatherType": 1,
"gatherIds": []
}
let extend_dic = {"key": `tags`, "name": "合集", value: []}
let resJson = JSON.parse(await this.post(this.siteUrl + "/gather/getList", this.getParams(params), this.getHeader(), ""))
for (const data of resJson["data"]["list"]) {
extend_dic["value"].push({"n": data["name"], "v": data["gatherId"].toString()})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (let i = 0; i < this.classes.length; i++) {
let type_dic = this.classes[i]
let type_id = type_dic["type_id"]
let type_name = type_dic["type_name"]
let filterList = []
if (type_id !== "最近更新") {
type_id = parseInt(type_id)
let params = this.getParams({"panelId": type_id})
let response = await this.post(this.siteUrl + "/panel/get", params, this.getHeader(), "")
let resJson = JSON.parse(response)
let layoutList = resJson["data"]["info"]["Layouts"]
let layOutObj = JSON.parse(resJson["data"]["info"]["Layouts"][0]["layoutContent"])
if (type_id > 174 && type_id < 181) {
let layOutObj = JSON.parse(resJson["data"]["info"]["Layouts"][0]["layoutContent"])
type_id = type_id + "$" + JSON.stringify(layOutObj)
filterList = await this.getFilter(layoutList)
} else {
switch (type_id) {
case 172:
filterList = await this.getHeJiFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
case 173:
filterList = await this.getChuanMeiFilter(layoutList)
type_id = type_id + "$" + JSON.stringify(layOutObj)
break
case 182:
filterList = await this.getNvYouFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
case 209:
filterList = await this.getZhuanTiFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
default:
break
}
}
this.classes[i] = this.getTypeDic(type_name, type_id)
this.filterObj[type_id] = filterList
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["coverImgUrl"])
if (data["hot"] === undefined) {
vodShort.vod_remarks = "观看:" + (data["seeCount"] / 10000).toFixed(1).toString() + "W"
} else {
vodShort.vod_remarks = "热度:" + (data["hot"] / 1000).toFixed(1).toString() + "K"
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromGatherJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["gatherId"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["coverImgUrl"])
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc(detailObj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = detailObj["name"]
vodDetail.vod_year = detailObj["addTime"]
vodDetail.vod_pic = this.jsBase + Utils.base64Encode(detailObj["coverImgUrl"])
vodDetail.type_name = detailObj["typeName"]
vodDetail.vod_content = detailObj["tags"]
let vodItems = []
let params = {
"videoId": detailObj["id"]
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/videos/getPreUrl", this.getParams(params), this.getHeader(), ""))
let playList = resJson["data"]["url"].split("?")
let playUrl = playList[0] + "?sign" + playList[1].split("&sign").slice(-1)[0]
vodItems.push(vodDetail.vod_name + "$" + playUrl)
let playObj = {"线路1": vodItems.join("#")}
vodDetail.vod_play_url = _.values(playObj).join('$$$');
vodDetail.vod_play_from = _.keys(playObj).join('$$$');
return vodDetail
}
async getHomeVod(params) {
let params_str = this.getParams(params)
let response = await this.post(this.siteUrl + "/videos/getList", params_str, this.getHeader(), "")
return await this.parseVodShortListFromJson(JSON.parse(response)["data"]["list"])
}
async setHomeVod() {
let vod_list1 = await this.getHomeVod({
"page": 1,
"length": 16,
"offset": 0,
"typeIds": [],
"orderType": 1,
"payType": [3, 4]
})
let vod_list2 = await this.getHomeVod({
"page": 1,
"length": 16,
"offset": 0,
"typeIds": [],
"orderType": 3,
"payType": [
1
]
})
let vod_list3 = await this.getHomeVod({
"page": 1,
"length": 32,
"offset": 0,
"typeIds": [],
"orderType": 1,
"payType": [
3
]
})
this.homeVodList = [...vod_list1, ...vod_list2, ...vod_list3];
}
getSortParams(params, extend) {
let orderTypeStr = extend["sorts"] ?? ""
if (!_.isEmpty(orderTypeStr)) {
let orderType = orderTypeStr.split("-")[0]
params["orderType"] = parseInt(orderType)
let orderModeStr = orderTypeStr.split("-")[1]
let orderMode = 0
if (orderModeStr === "升序") {
orderMode = "1"
} else {
orderMode = "0"
}
params["orderMode"] = parseInt(orderMode)
}
return params
}
getTopParams(type_id, layOutObj, pg, extend) {
let defaultOderType
if (type_id === 180) {
defaultOderType = "1"
} else {
defaultOderType = "7"
}
let orderMode = "1"
let orderType
let orderTypeStr = extend["sorts"] ?? defaultOderType
let isOrderModel = false
if (orderTypeStr.indexOf("-") > -1) {
orderType = orderTypeStr.split("-")[0]
let orderModeStr = orderTypeStr.split("-")[1]
if (orderModeStr === "升序") {
orderMode = "1"
} else {
orderMode = "0"
}
isOrderModel = true
} else {
orderType = defaultOderType
}
let params = {
"orderType": parseInt(orderType), //或者7
"tags": [],
"length": 11,
"page": parseInt(pg),
"typeIds": layOutObj["classs"],
"payType": layOutObj["payType"],
}
if (isOrderModel) {
params["orderMode"] = parseInt(orderMode)
}
return params
}
getChuanMeiParams(layOutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layOutObj
}
let params = {
"page": parseInt(pg),
"length": 32,
"offset": 32 * parseInt(pg - 1),
"tag": obj["videoLables"].join(","),
"typeIds": obj["classs"],
"orderType": obj["orderType"],
"payType": obj["payType"]
}
params = this.getSortParams(params, extend)
return params
}
getNvYouParams(layoutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layoutObj
}
let params = {"videoSort": 1, "touid": obj["id"], "page": parseInt(pg), "length": 12, "orderType": 1}
params = this.getSortParams(params, extend)
return params
}
getZhuantiParams(layoutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layoutObj
}
let orderType = extend["sorts"] ?? "8"
return {
"page": parseInt(pg),
"length": 12,
"offset": 12 * (parseInt(pg) - 1),
"orderType": parseInt(orderType),
"subjectId": obj["id"]
}
}
async setCategory(tid, pg, filter, extend) {
let tid_list = tid.split("$")
let type_id = parseInt(tid_list[0])
let layOutObj = JSON.parse(tid_list[1])
let params = {}
let url = "/videos/getList"
if (type_id > 174 && type_id < 181) {
params = this.getTopParams(type_id, layOutObj, pg, extend)
} else {
switch (type_id) {
case 173:
params = this.getChuanMeiParams(layOutObj, pg, extend)
break
case 182:
params = this.getNvYouParams(layOutObj, pg, extend)
url = "/user/getSpaceVideo"
break
case 209:
params = this.getZhuantiParams(layOutObj, pg, extend)
break
case 172:
let gatherId = extend["tags"] ?? layOutObj
params = {
"gatherId": parseInt(gatherId)
}
url = "/gather/getDetail"
break
default:
break
}
}
let resJson = JSON.parse(await this.post(this.siteUrl + url, this.getParams(params), this.getHeader(), ""))
if (type_id === 172) {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["info"]["videos"])
} else {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
}
}
async setDetail(id) {
let params = {
"videoId": parseInt(id),
"videoSort": 1
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/videos/getInfo", this.getParams(params), this.getHeader(), ""))
this.vodDetail = await this.parseVodDetailFromDoc(resJson["data"]["info"])
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'imgBt') {
let response = await req(url, {buffer: 0});
return JSON.stringify({
code: 200,
buffer: 2,
content: bt(response.content).replaceAll("data:image/jpeg;base64,", "").replaceAll("data:image/jpg;base64,", "").replaceAll("data:image/png;base64", ""),
headers: headers,
});
}
}
async setSearch(wd, quick, pg) {
let params = {
"page": parseInt(pg),
"length": 12,
"type": 1,
"key": wd
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/base/globalSearch", this.getParams(params), this.getHeader(), ""))
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["infos"])
this.result.setPage(parseInt(pg), resJson["data"]["count"] / 12, 12, resJson["data"]["count"])
}
}
let spider = new HanXiuCaoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider, bt}

273
JN/CATJS/js/haoxi.js Normal file
View File

@ -0,0 +1,273 @@
/*
* @File : haoxi.js
* @Author : jade
* @Date : 2024/2/7 14:24
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 好戏追剧 已失效
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class HaoXiSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://haoxi.vip"
}
getAppName() {
return `好戏追剧`
}
getName() {
return `🌿┃好戏追剧┃🌿`
}
getJSName() {
return "haoxi"
}
getType() {
return 3
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_id = $(element).find("a")[0].attribs.href
vodShort.vod_name = $(element).find("a")[0].attribs.title
if (vodShort.vod_name === undefined) {
vodShort.vod_name = $($($(element).find("[class=\"thumb-txt cor4 hide\"]")).find("a")).html()
}
vodShort.vod_pic = $(element).find("img")[0].attribs["data-src"]
vodShort.vod_remarks = $($(element).find("[class=\"public-list-prb hide ft2\"]")).html()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"flex bottom4\"]").find("[class=\"public-list-box public-pic-a [swiper]\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"public-list-box public-pic-b [swiper]\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"public-list-box search-box flex rel\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetailElement = $("[class=\"vod-detail style-detail rel cor1 hader0\"]")
let vodDetail = new VodDetail();
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(vodDetailElement).find("[class=\"slide-info-title hide\"]")).html()
let elements = $(vodDetailElement).find("[class=\"slide-info hide\"]")
vodDetail.vod_year = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[0]).find("a")[0]).html()
vodDetail.vod_area = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[1]).find("a")[0]).html()
vodDetail.type_name = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[2]).find("a")[0]).html()
vodDetail.vod_remarks = $(elements[1]).text().replaceAll("备注 :", "")
vodDetail.vod_director = $(elements[2]).text().replaceAll("导演 :", "")
vodDetail.vod_actor = $(elements[3]).text().replaceAll("演员 :", "")
vodDetail.vod_content = $($("[class=\"text cor3\"]")).text()
let playElements = $("[class=\"box-width cor5\"]")
let playFormatElements = playElements.find("[class=\"swiper-slide\"]")
let playUrlElements = playElements.find("[class=\"anthology-list-box none\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElements.length; i++) {
let playFormatElement = playFormatElements[i]
let format_name = playFormatElement.children[1].data
format_name = format_name.replaceAll(" ", "")
vod_play_from_list.push(format_name)
let vodItems = []
if (format_name === "http下载") {
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
if (episodeName !== "复制地址") {
vodItems.push(episodeName + "$" + episodeUrl)
}
}
} else {
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"head flex between no-null header_nav0\"]").find("li")
for (const navElement of navElements) {
let type_name = $($(navElement).find("a")).text()
let type_id = Utils.getStrByRegex(/\/vodtype\/(.*?)\//, $(navElement).find("a")[0].attribs.href)
if (Utils.isNumeric(type_id)) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let elements = $("[class=\"nav-swiper rel\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
let name = $($($(elements[i]).find("[class=\"filter-text bj cor5\"]")[0]).find("span")).html()
if (name !== "已选" && name !== "频道") {
extend_dic["name"] = name
for (const ele of $(elements[i]).find("li")) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
}
}
let sortElments = $("[class=\"site-tabs b-b br\"]")
let extend_dic = {"key": (elements.length + 1).toString(), "name": "排序", "value": []}
extend_dic["value"].push({"n": "全部", "v": "/"})
for (const ele of $(sortElments).find("a")) {
let type_id_list = ele.attribs.href.split("-")
extend_dic["value"].push({"n": $(ele).text(), "v": type_id_list[2]})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (Utils.isNumeric(type_id)) {
let url = this.siteUrl + `/vodshow/${type_id}-----------`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
get_extend_sort_dic(tid) {
return {
"3": 3, "4": 1, "5": 11, "6": 4, "9": 5, "10": 2,
}
}
async setCategory(tid, pg, filter, extend) {
// "1-大陆-hits-Netflix-英语-A----正片--2023/version/4K/"
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
if (extend[key] !== "全部") {
urlParams[extend_dic[key]] = extend[key]
}
}
}
let reqUrl = this.siteUrl + '/vodshow/' + urlParams.join("-");
if (extend[7] !== undefined && extend[7] !== "全部") {
reqUrl = reqUrl + `/version/${extend[7]}/`
}
await this.jadeLog.debug(`分类URL:${reqUrl}`)
let $ = await this.getHtml(reqUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + `/vodsearch/-------------/?wd=${wd}`)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
if (flag !== "http下载") {
let $ = await this.getHtml(this.siteUrl + id)
let playConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/, $.html()))
this.playUrl = playConfig['url']
} else {
this.playUrl = id
}
}
}
let spider = new HaoXiSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

153
JN/CATJS/js/hscangku.js Normal file
View File

@ -0,0 +1,153 @@
/*
* @File : hscangku.js
* @Author : jade
* @Date : 2024/01/03 19:19
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class HsCangkuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://hsck12.shop/"
}
getName() {
return "🔞┃黄色仓库┃🔞"
}
getAppName() {
return "黄色仓库"
}
getJSName() {
return "hscangku"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"stui-vodlist clearfix\"]").find("li")
for (const vod_element of vodElements) {
let vodShort = new VodShort()
let vodElement = $(vod_element).find("a")[0]
vodShort.vod_id = vodElement.attribs["href"]
vodShort.vod_name = vodElement.attribs["title"]
vodShort.vod_pic = vodElement.attribs["data-original"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let element = $($("[class=\"stui-pannel__head clearfix\"]")[1]).find("h3")
let stui_pannel_bd_element = $("div.stui-pannel-bd > div")
let video_element = stui_pannel_bd_element.find("video")[0]
vodDetail.vod_name = element.text()
vodDetail.vod_pic = video_element.attribs["poster"]
vodDetail.vod_play_from = "黄色仓库"
vodDetail.vod_play_url = $(video_element).find("source")[0].attribs["src"]
return vodDetail
}
async setClasses() {
this.classes = [
{
"type_name": "国产视频",
"type_id": "?type=gc"
},
{
"type_name": "国产新片",
"type_id": "?type=ycgc"
},
{
"type_name": "无码中文字幕",
"type_id": "?type=wz"
},
{
"type_name": "有码中文字幕",
"type_id": "?type=yz"
},
{
"type_name": "日本无码",
"type_id": "?type=rw"
}
]
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid + "&p=" + pg.toString()
let html = await this.fetch(url, null,this.getHeader())
this.limit = 40;
if (html !== null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
this.total = parseInt($("[class=\"active\"]").find("span").text())
}
}
async setDetail(id) {
let url = this.siteUrl + id
let html = await this.fetch(url,null,this.getHeader())
if (html !== null) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
this.playHeader = {}
}
}
let spider = new HsCangkuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}

709
JN/CATJS/js/huya.js Normal file
View File

@ -0,0 +1,709 @@
/*
* @File : huya.js
* @Author : jade
* @Date : 2024/3/7 9:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class HuyaSpider extends Spider {
constructor() {
super();
this.isJustLive = false
this.dataFrom = ""
this.customArea = ""
this.huYaPlayForamtObj = {"AL": "蓝光8M", "TX": "蓝光4M", "HW": "超清", "HS": "流畅"}
this.livePlayForamtObj = {"HD": "蓝光8M", "LD": "蓝光4M", "SD": "超清", "OD": "流畅"}
}
getName() {
return "🐯┃虎牙直播┃🐯"
}
getAppName() {
return "虎牙直播"
}
getJSName() {
return "huya"
}
getType() {
return 3
}
async spiderInit() {
if (this.cfgObj.hasOwnProperty('custom')) {
this.customArea = this.cfgObj.custom;
}
if (this.cfgObj.hasOwnProperty('from')) {
this.dataFrom = this.cfgObj.from;
}
if (this.dataFrom !== 'justlive') {
this.siteUrl = 'https://www.huya.com';
} else {
this.siteUrl = 'http://live.yj1211.work';
this.isJustLive = true;
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit()
}
getHeader() {
let header = super.getHeader();
header["User-Agent"] = Utils.MOBILEUA
return header
}
async setClasses() {
this.classes = [{
"type_id": "1", "type_name": "网游"
}, {"type_id": "2", "type_name": "单机"}, {"type_id": "3", "type_name": "手游"}, {
"type_id": "8", "type_name": "娱乐"
}]
}
async setFilterObj() {
this.filterObj = {
"1": [{
"key": "cateId",
"name": "分类",
"init": "1",
"value": [{"n": "英雄联盟", "v": "1"}, {"n": "CS2", "v": "862"}, {
"n": "穿越火线", "v": "4"
}, {"n": "lol云顶之弈", "v": "5485"}, {"n": "无畏契约", "v": "5937"}, {
"n": "CFHD", "v": "6079"
}, {"n": "逆战", "v": "135"}, {"n": "炉石传说", "v": "393"}, {"n": "DOTA2", "v": "7"}, {
"n": "地下城与勇士", "v": "2"
}, {"n": "魔兽世界", "v": "8"}, {"n": "坦克世界", "v": "802"}, {"n": "DOTA1", "v": "6"}, {
"n": "梦三国", "v": "489"
}, {"n": "魔兽争霸3", "v": "4615"}, {"n": "问道", "v": "107"}, {
"n": "命运方舟", "v": "3058"
}, {"n": "QQ飞车", "v": "9"}, {"n": "星际争霸", "v": "5"}, {
"n": "网游竞技", "v": "100023"
}, {"n": "射击综合游戏", "v": "100141"}, {"n": "暴雪专区", "v": "100043"}, {
"n": "彩虹岛Online", "v": "683"
}, {"n": "剑灵", "v": "897"}, {"n": "军事游戏", "v": "100133"}, {
"n": "冒险岛", "v": "2243"
}, {"n": "暗黑破坏神", "v": "1123"}, {"n": "诛仙3", "v": "1646"}, {
"n": "热血江湖", "v": "387"
}, {"n": "英魂之刃", "v": "1830"}, {"n": "武林外传一世琴缘", "v": "1661"}, {
"n": "起凡:群雄逐鹿", "v": "1612"
}, {"n": "神武4电脑版", "v": "3227"}, {"n": "龙之谷", "v": "15"}, {
"n": "炉石战棋", "v": "5751"
}, {"n": "御龙在天", "v": "675"}, {"n": "逆水寒", "v": "2952"}, {
"n": "千年3", "v": "878"
}, {"n": "永恒之塔", "v": "446"}, {"n": "体育游戏", "v": "100135"}, {
"n": "寻仙", "v": "734"
}, {"n": "战舰世界", "v": "1947"}, {"n": "QQ三国", "v": "1090"}, {
"n": "流放之路", "v": "427"
}, {"n": "反恐精英Online", "v": "1918"}, {"n": "反恐行动online", "v": "861"}, {
"n": "征途", "v": "2715"
}, {"n": "战争雷霆", "v": "624"}, {"n": "丝路传说2", "v": "1026"}, {
"n": "星际战甲", "v": "627"
}, {"n": "NBA2KOL系列", "v": "3959"}, {"n": "九阴真经", "v": "1009"}, {
"n": "跑跑卡丁车", "v": "162"
}, {"n": "诛仙世界", "v": "7749"}, {"n": "QQ华夏", "v": "1878"}, {
"n": "天涯明月刀", "v": "1219"
}, {"n": "大话西游:归来", "v": "8239"}, {"n": "荒野行动PC版", "v": "3185"}, {
"n": "新剑侠情缘", "v": "586"
}, {"n": "剑网3", "v": "900"}, {"n": "生死狙击2", "v": "6091"}, {
"n": "全球使命", "v": "939"
}, {"n": "梦想世界3", "v": "486"}, {"n": "枪神纪", "v": "496"}, {
"n": "新天龙八部", "v": "5671"
}, {"n": "铁甲雄兵", "v": "2765"}, {"n": "神泣", "v": "2531"}, {
"n": "斗战神", "v": "591"
}, {"n": "造梦西游OL", "v": "6815"}, {"n": "天堂", "v": "1966"}, {
"n": "大话西游2", "v": "2975"
}, {"n": "使命召唤:战区", "v": "5911"}, {"n": "希望OL", "v": "1161"}, {
"n": "极光世界 弑神传", "v": "514"
}, {"n": "守望先锋归来", "v": "2174"}, {"n": "QQ自由幻想", "v": "1862"}, {
"n": "命运2", "v": "2942"
}, {"n": "奇迹世界2", "v": "766"}, {"n": "坦克大战", "v": "4359"}, {
"n": "生死狙击", "v": "2471"
}, {"n": "天翼决", "v": "779"}, {"n": "QQ幻想", "v": "2419"}, {
"n": "新飞飞(FlyFF)", "v": "1582"
}, {"n": "刀剑英雄", "v": "915"}, {"n": "FIFA Online系列", "v": "100079"}, {
"n": "全球使命3", "v": "2953"
}, {"n": "完美端游系列", "v": "3034"}, {"n": "战意", "v": "2599"}, {
"n": "泡泡堂", "v": "440"
}, {"n": "赛尔号", "v": "2755"}, {"n": "大唐无双零", "v": "1584"}, {
"n": "QQ炫舞", "v": "2440"
}, {"n": "007传奇", "v": "1135"}, {"n": "天下", "v": "1597"}, {
"n": "天谕", "v": "1899"
}, {"n": "新倩女幽魂", "v": "1579"}, {"n": "传世无双", "v": "984"}, {
"n": "剑侠世界", "v": "903"
}, {"n": "Warhaven", "v": "9053"}, {"n": "诺亚传说", "v": "190"}, {
"n": "新挑战", "v": "583"
}, {"n": "超激斗梦境", "v": "5691"}, {"n": "QQ音速", "v": "1085"}, {"n": "征途2", "v": "677"}, {
"n": "征程", "v": "678"
}, {"n": "蜀门", "v": "4711"}, {"n": "完美世界:诸神之战", "v": "7217"}, {
"n": "战之刃:幸存者", "v": "8627"
}, {"n": "黎明之光", "v": "41"}, {"n": "天命西游", "v": "1086"}, {
"n": "炫舞时代", "v": "3353"
}, {"n": "荣誉空间", "v": "225"}, {"n": "卡拉彼丘", "v": "9073"}, {
"n": "成吉思汗怀旧版", "v": "640"
}, {"n": "英雄年代3", "v": "1232"}, {"n": "天书奇谈", "v": "2225"}, {
"n": "劲舞团", "v": "2420"
}, {"n": "远征Online梦想版", "v": "142"}, {"n": "奇迹:传奇", "v": "3917"}, {
"n": "封印者", "v": "2294"
}, {"n": "上古世纪", "v": "1046"}, {"n": "梦幻诛仙2", "v": "488"}, {
"n": "TERA Online", "v": "1072"
}, {"n": "倚天Ⅱ", "v": "959"}, {"n": "街头篮球", "v": "206"}, {
"n": "永恒轮回:无限", "v": "7847"
}, {"n": "火线精英", "v": "2550"}, {"n": "忍者村大战2", "v": "2369"}, {
"n": "领地人生", "v": "2282"
}, {"n": "仙侠世界", "v": "995"}, {"n": "洛奇英雄传", "v": "432"}, {
"n": "KARDS", "v": "8261"
}, {"n": "无限法则", "v": "3189"}, {"n": "全面战争:竞技场", "v": "5901"}, {
"n": "自由篮球", "v": "243"
}, {"n": "FC Online4", "v": "3683"}, {"n": "战地之王", "v": "618"}, {
"n": "古剑奇谭OL", "v": "1892"
}, {"n": "QQ仙侠传", "v": "2291"}, {"n": "300英雄", "v": "1132"}]
}], "2": [{
"key": "cateId",
"name": "分类",
"init": "2793",
"value": [{"n": "天天吃鸡", "v": "2793"}, {"n": "永劫无间", "v": "6219"}, {
"n": "主机游戏", "v": "100032"
}, {"n": "猛兽派对", "v": "6165"}, {"n": "互动点播", "v": "5907"}, {
"n": "我的世界", "v": "1732"
}, {"n": "方舟", "v": "1997"}, {"n": "单机热游", "v": "100002"}, {
"n": "怀旧游戏", "v": "100125"
}, {"n": "逃离塔科夫", "v": "3493"}, {"n": "俄罗斯钓鱼4", "v": "5495"}, {
"n": "部落:上升", "v": "1318"
}, {"n": "Dark and Darker", "v": "7905"}, {"n": "The Front", "v": "9497"}, {
"n": "Apex英雄", "v": "5011"
}, {"n": "生化危机4重制版", "v": "8013"}, {"n": "DayZ独立版", "v": "1125"}, {
"n": "星空", "v": "7857"
}, {"n": "互动剧游", "v": "6919"}, {"n": "艾尔登法环", "v": "5801"}, {
"n": "恐惧之间", "v": "6679"
}, {"n": "SCUM", "v": "4245"}, {"n": "Dread Hunger", "v": "7601"}, {
"n": "塞尔达传说:王国之泪", "v": "7883"
}, {"n": "欧洲卡车模拟", "v": "475"}, {"n": "洛克王国", "v": "2864"}, {
"n": "卧龙:苍天陨落", "v": "7859"
}, {"n": "无人深空", "v": "2566"}, {"n": "帝国神话", "v": "6821"}, {
"n": "饥荒", "v": "74"
}, {"n": "森林之子", "v": "7943"}, {"n": "星球大战系列", "v": "554"}, {
"n": "极限竞速:地平线", "v": "2634"
}, {"n": "最终幻想16", "v": "7869"}, {"n": "Among Us", "v": "6163"}, {
"n": "怪物猎人:崛起", "v": "6479"
}, {"n": "怪物猎人物语", "v": "7101"}, {"n": "骑马与砍杀系列", "v": "4783"}, {
"n": "荒野大镖客2", "v": "4319"
}, {"n": "太荒初境", "v": "7685"}, {"n": "罗布乐思", "v": "5771"}, {
"n": "只狼:影逝二度", "v": "4505"
}, {"n": "双人成行", "v": "6737"}, {"n": "重生边缘", "v": "6201"}, {
"n": "海贼王 寻秘世界", "v": "5097"
}, {"n": "战神:诸神黄昏", "v": "7771"}, {"n": "恐鬼症", "v": "6205"}, {
"n": "鬼谷八荒", "v": "6571"
}, {"n": "霍格沃茨之遗", "v": "7881"}, {"n": "全面战争", "v": "3521"}, {
"n": "仁王2", "v": "5795"
}, {"n": "奥拉星", "v": "2846"}, {"n": "甜蜜之家", "v": "6739"}, {
"n": "仙剑奇侠传七", "v": "6509"
}, {"n": "消逝的光芒2", "v": "7581"}, {"n": "渡神记", "v": "6231"}, {
"n": "归家异途", "v": "2949"
}, {"n": "博德之门3", "v": "6147"}, {"n": "看门狗:军团", "v": "6155"}, {
"n": "使命召唤系列", "v": "100137"
}, {"n": "育碧游戏", "v": "100139"}, {"n": "帝国时代4", "v": "4835"}, {
"n": "英灵神殿", "v": "6609"
}, {"n": "蛮荒志异:起源", "v": "9709"}, {"n": "岛", "v": "3019"}, {
"n": "沙盒与副本", "v": "9151"
}, {"n": "扫雷", "v": "2349"}, {"n": "街机游戏", "v": "5999"}, {
"n": "幽灵线:东京", "v": "7669"
}, {"n": "怪物猎人世界", "v": "3519"}, {"n": "盗贼之海", "v": "3641"}, {
"n": "纸人", "v": "5257"
}, {"n": "黑色像素人", "v": "28"}, {"n": "对马岛之魂", "v": "6039"}, {
"n": "瑞奇与叮当", "v": "2455"
}, {"n": "港诡实录", "v": "5853"}, {"n": "剑士", "v": "1467"}, {
"n": "魔法门之英雄无敌系列", "v": "2096"
}, {"n": "星露谷物语", "v": "2443"}, {"n": "仙剑奇侠传四", "v": "1659"}, {
"n": "伤害世界", "v": "2337"
}, {"n": "禁闭求生", "v": "6065"}, {"n": "真三国无双", "v": "1599"}, {
"n": "恐怖黎明", "v": "3435"
}, {"n": "其他单机", "v": "3069"}, {"n": "幽灵行动:荒野", "v": "2794"}, {
"n": "边缘", "v": "151"
}, {"n": "阿凡达", "v": "106"}, {"n": "全面战争:三国", "v": "3004"}, {
"n": "黎明之星", "v": "40"
}, {"n": "翼星求生", "v": "7463"}, {"n": "黎明传说", "v": "39"}, {
"n": "恶魔之魂", "v": "6151"
}, {"n": "艾兰岛", "v": "3855"}, {"n": "龙与地下城秘影历代记HD", "v": "17"}, {
"n": "龙与地下城:匕首谷", "v": "18"
}, {"n": "沙石镇时光", "v": "7687"}, {"n": "三国志曹操传", "v": "2592"}, {
"n": "FIFA足球", "v": "1888"
}, {"n": "最终幻想7重制版", "v": "5809"}, {"n": "四海兄弟", "v": "5995"}, {
"n": "最终幻想:起源", "v": "7653"
}, {"n": "摔跤城大乱斗", "v": "7773"}, {"n": "音乐游戏", "v": "2761"}, {
"n": "精灵与萤火意志", "v": "5895"
}, {"n": "桥梁建造师", "v": "3275"}, {"n": "哈迪斯", "v": "6153"}, {
"n": "小缇娜的奇幻之地", "v": "7647"
}, {"n": "宝可梦:剑盾", "v": "5715"}, {"n": "边境", "v": "4779"}, {
"n": "人类一败涂地", "v": "3289"
}, {"n": "糖豆人:终极淘汰赛", "v": "6083"}, {"n": "精灵宝可梦Let's Go", "v": "4375"}, {
"n": "战锤40K暗潮", "v": "3016"
}, {"n": "石油骚动", "v": "2585"}, {"n": "紫塞秋风", "v": "6045"}, {
"n": "阿尔比恩", "v": "8115"
}, {"n": "猎人:荒野的召唤", "v": "2906"}, {"n": "FIFA 23", "v": "7789"}, {
"n": "都市:天际线", "v": "2201"
}, {"n": "乐高大电影:游戏版", "v": "1439"}, {"n": "全面战争:阿提拉", "v": "2383"}, {
"n": "斩妖行", "v": "6105"
}, {"n": "马里奥赛车8", "v": "5947"}, {"n": "复仇者联盟", "v": "6121"}, {"n": "霓虹深渊", "v": "5743"}]
}], "3": [{
"key": "cateId",
"name": "分类",
"init": "2336",
"value": [{"n": "王者荣耀", "v": "2336"}, {"n": "和平精英", "v": "3203"}, {
"n": "英雄联盟手游", "v": "6203"
}, {"n": "CF手游", "v": "2413"}, {"n": "金铲铲之战", "v": "7185"}, {
"n": "三国杀", "v": "1669"
}, {"n": "原神", "v": "5489"}, {"n": "棋牌桌游", "v": "100036"}, {
"n": "综合手游", "v": "100029"
}, {"n": "劲乐幻想", "v": "7691"}, {"n": "新游广场", "v": "100052"}, {
"n": "崩坏:星穹铁道", "v": "7349"
}, {"n": "火影忍者手游", "v": "2429"}, {"n": "第五人格", "v": "3115"}, {
"n": "问道手游", "v": "2477"
}, {"n": "暗区突围", "v": "7209"}, {"n": "QQ飞车手游", "v": "2928"}, {
"n": "球球大作战", "v": "2411"
}, {"n": "明日之后", "v": "3483"}, {"n": "皇室战争", "v": "2439"}, {
"n": "COD手游", "v": "4769"
}, {"n": "手游休闲", "v": "100004"}, {"n": "二次元手游", "v": "100091"}, {
"n": "摸了个鱼", "v": "9283"
}, {"n": "MMORPG", "v": "100273"}, {"n": "动作游戏", "v": "100197"}, {
"n": "战争冲突", "v": "7449"
}, {"n": "王者模拟战", "v": "5699"}, {"n": "逆水寒手游", "v": "7725"}, {
"n": "幻塔", "v": "6437"
}, {"n": "欢乐斗地主", "v": "1749"}, {"n": "神武4手游", "v": "3135"}, {
"n": "阴阳师", "v": "2598"
}, {"n": "DNF手游", "v": "4921"}, {"n": "欢乐麻将", "v": "1751"}, {
"n": "英雄联盟电竞经理", "v": "7177"
}, {"n": "狼人杀手游", "v": "100049"}, {"n": "新天龙八部手游", "v": "6945"}, {
"n": "中国象棋", "v": "1671"
}, {"n": "天天象棋", "v": "4997"}, {"n": "传奇世界3D", "v": "3961"}, {
"n": "御龙在天手游", "v": "2568"
}, {"n": "高能英雄", "v": "8359"}, {"n": "天龙八部手游", "v": "2852"}, {
"n": "三国志战略版", "v": "5619"
}, {"n": "忍者必须死3", "v": "4041"}, {"n": "SKY光遇", "v": "3719"}, {
"n": "虎牙领主争霸", "v": "7529"
}, {"n": "云上城之歌", "v": "5977"}, {"n": "晶核", "v": "7279"}, {
"n": "仙境传说RO", "v": "2675"
}, {"n": "天天狼人", "v": "2774"}, {"n": "JJ棋牌", "v": "3841"}, {
"n": "奇迹MU觉醒", "v": "3116"
}, {"n": "指尖四川麻将", "v": "7215"}, {"n": "部落冲突", "v": "1797"}, {
"n": "新剑侠情缘手游", "v": "6259"
}, {"n": "萌宠远征", "v": "9385"}, {"n": "暗黑破坏神:不朽", "v": "6385"}, {
"n": "英雄杀", "v": "2688"
}, {"n": "热血江湖手游", "v": "2817"}, {"n": "蛋仔派对", "v": "6909"}, {
"n": "完美世界手游", "v": "4237"
}, {"n": "巅峰战舰", "v": "2502"}, {"n": "狼人杀", "v": "2785"}, {
"n": "斗罗大陆:魂师对决", "v": "6745"
}, {"n": "武侠乂手游", "v": "4929"}, {"n": "诛仙手游", "v": "2647"}, {
"n": "斗破苍穹手游", "v": "4337"
}, {"n": "迷你世界", "v": "2683"}, {"n": "风云", "v": "3061"}, {
"n": "妄想山海", "v": "6007"
}, {"n": "曙光英雄", "v": "6169"}, {"n": "三国战纪2", "v": "6049"}, {
"n": "梦幻新诛仙", "v": "5975"
}, {"n": "黎明觉醒:生机", "v": "6131"}, {"n": "远征", "v": "7837"}, {
"n": "航海王:燃烧意志", "v": "3943"
}, {"n": "火炬之光:无限", "v": "6399"}, {"n": "巅峰极速", "v": "6979"}, {
"n": "圣境之塔", "v": "7055"
}, {"n": "魔力宝贝", "v": "2891"}, {"n": "香肠派对", "v": "3639"}, {
"n": "创造与魔法", "v": "2931"
}, {"n": "JJ斗地主", "v": "6271"}, {"n": "永恒纪元:戒", "v": "2646"}, {
"n": "天涯明月刀手游", "v": "5115"
}, {"n": "狼人杀官方", "v": "3679"}, {"n": "混沌起源", "v": "5985"}, {
"n": "多多自走棋", "v": "5133"
}, {"n": "梦幻诛仙手游", "v": "2672"}, {"n": "鸿图之下", "v": "6027"}, {
"n": "新笑傲江湖", "v": "5669"
}, {"n": "凡人修仙传:人界篇", "v": "8297"}, {"n": "多乐棋牌", "v": "6209"}, {
"n": "口袋觉醒", "v": "5953"
}, {"n": "跑跑卡丁车手游", "v": "2620"}, {"n": "奶块", "v": "2775"}, {
"n": "月圆之夜", "v": "4339"
}, {"n": "率土之滨", "v": "2691"}, {"n": "征途2手游", "v": "2811"}, {
"n": "英魂之刃口袋版", "v": "2760"
}, {"n": "精灵盛典:黎明", "v": "6123"}, {"n": "方舟手游", "v": "4035"}, {
"n": "掼蛋", "v": "6225"
}, {"n": "绝世仙王", "v": "6619"}, {"n": "流星群侠传", "v": "3927"}, {
"n": "寻仙手游", "v": "2979"
}, {"n": "一梦江湖", "v": "3082"}, {"n": "Lost Light萤火突击国际服", "v": "6859"}, {
"n": "弹幕云游戏", "v": "7001"
}, {"n": "猎魂觉醒", "v": "3071"}, {"n": "冒险岛:枫之传说", "v": "8005"}, {
"n": "征途手游", "v": "2556"
}, {"n": "海岛奇兵", "v": "2624"}, {"n": "倩女幽魂手游", "v": "2503"}, {
"n": "超凡先锋", "v": "6507"
}, {"n": "龙之谷2手游", "v": "2736"}, {"n": "崩坏3", "v": "2639"}, {
"n": "猫和老鼠", "v": "2758"
}, {"n": "七人传奇:光与暗之交战", "v": "8125"}, {"n": "JJ麻将", "v": "9487"}, {
"n": "拉轰西游", "v": "9543"
}, {"n": "三国战纪", "v": "6047"}, {"n": "自由幻想手游", "v": "4015"}, {
"n": "秦时明月世界", "v": "5279"
}, {"n": "新斗罗大陆", "v": "6657"}, {"n": "新神魔大陆", "v": "5939"}, {
"n": "逃跑吧!少年", "v": "4137"
}, {"n": "太古神王2", "v": "6649"}, {"n": "剑侠世界3", "v": "7183"}, {
"n": "天天吃鸡手机版", "v": "4341"
}, {"n": "时空猎人3", "v": "6411"}, {"n": "合金弹头:觉醒", "v": "6931"}, {
"n": "明日方舟", "v": "4925"
}, {"n": "原始征途", "v": "7713"}, {"n": "奇迹:最强者", "v": "3215"}, {
"n": "天天酷跑", "v": "1715"
}, {"n": "FC 足球世界", "v": "3873"}, {"n": "万国觉醒", "v": "6159"}, {
"n": "机动都市阿尔法", "v": "5411"
}, {"n": "航海王热血航线", "v": "6181"}, {"n": "幻世九歌", "v": "7199"}, {
"n": "植物大战僵尸", "v": "485"
}, {"n": "无悔华夏", "v": "7063"}, {"n": "时空猎人", "v": "1742"}, {
"n": "荒野乱斗", "v": "4613"
}, {"n": "拳皇98终极之战OL", "v": "2687"}, {"n": "蛇蛇争霸", "v": "2680"}, {
"n": "王牌竞速", "v": "6463"
}, {"n": "重返帝国", "v": "6955"}, {"n": "吞噬星空:黎明", "v": "6651"}, {
"n": "口袋妖怪", "v": "2541"
}, {"n": "QQ炫舞手游", "v": "2991"}, {"n": "一拳超人:最强之男", "v": "4629"}, {
"n": "荣耀新三国", "v": "6943"
}, {"n": "少年三国志2", "v": "6125"}, {"n": "我的起源", "v": "5365"}, {
"n": "决战平安京", "v": "3064"
}, {"n": "剑灵2", "v": "7223"}, {"n": "开心消消乐", "v": "1712"}, {
"n": "小小蚁国", "v": "7803"
}, {"n": "最强NBA", "v": "2988"}, {"n": "剑侠情缘手游", "v": "2621"}, {
"n": "长安幻想", "v": "6727"
}, {"n": "我叫MT4", "v": "4087"}, {"n": "全明星街球派对", "v": "8401"}, {
"n": "大话西游手游", "v": "2626"
}, {"n": "荣耀大天使", "v": "6477"}, {"n": "镇魂街:天生为王", "v": "6557"}, {
"n": "摩尔庄园", "v": "5981"
}, {"n": "游戏王:决斗链接", "v": "4451"}, {"n": "剑侠世界2手游", "v": "3150"}, {
"n": "青云诀2", "v": "6009"
}, {"n": "战地无疆", "v": "7909"}, {"n": "一念逍遥", "v": "6419"}, {
"n": "永劫无间手游", "v": "7579"
}, {"n": "尘白禁区", "v": "7297"}, {"n": "元梦之星", "v": "9521"}, {
"n": "不良人3", "v": "5891"
}, {"n": "剑灵:革命", "v": "4545"}, {"n": "魔力宝贝:旅人", "v": "7573"}, {
"n": "米加小镇", "v": "7269"
}, {"n": "龙武手游", "v": "5219"}, {"n": "斗罗大陆2绝世唐门", "v": "6581"}, {
"n": "西行纪燃魂", "v": "8303"
}, {"n": "坦克世界闪击战", "v": "4977"}, {"n": "军棋", "v": "2561"}, {
"n": "饥荒:新家", "v": "6491"
}, {"n": "拳皇命运", "v": "3379"}, {"n": "实况足球", "v": "3741"}, {
"n": "战舰世界闪击战", "v": "4101"
}, {"n": "时空召唤", "v": "2551"}, {"n": "王牌战争:文明重启", "v": "5479"}, {
"n": "雀魂麻将", "v": "7107"
}, {"n": "欢乐升级", "v": "3925"}, {"n": "绿色征途", "v": "4227"}, {
"n": "弹弹堂手游", "v": "2857"
}, {"n": "太极熊猫3猎龙", "v": "2778"}, {"n": "哈利波特:魔法觉醒", "v": "5835"}, {
"n": "天地劫:幽城再临", "v": "5987"
}, {"n": "热血街篮", "v": "5859"}, {"n": "神雕侠侣手游", "v": "1781"}, {
"n": "山海镜花", "v": "5089"
}, {"n": "三国志战棋版", "v": "7937"}, {"n": "神雕侠侣2", "v": "4209"}, {
"n": "仙魔决", "v": "1674"
}, {"n": "王者荣耀星之破晓", "v": "7927"}, {"n": "我在江湖之神魔道", "v": "7699"}, {
"n": "梦幻模拟战", "v": "3481"
}, {"n": "单机手游", "v": "2777"}, {"n": "斗罗大陆-斗神再临", "v": "6631"}, {
"n": "未来之役", "v": "6831"
}, {"n": "风云岛行动", "v": "4695"}, {"n": "新游推荐", "v": "3160"}, {
"n": "火影忍者OL", "v": "3901"
}, {"n": "九灵神域", "v": "7719"}, {"n": "武动乾坤", "v": "3829"}, {
"n": "秦时明月2", "v": "1784"
}, {"n": "文明与征服", "v": "7071"}, {"n": "战双:帕弥什", "v": "4133"}, {
"n": "大航海时代:海上霸主", "v": "6929"
}, {"n": "剑网1归来", "v": "7361"}, {"n": "绝区零", "v": "7711"}, {
"n": "黑色沙漠手游", "v": "7287"
}, {"n": "虎牙吃鸡", "v": "7465"}, {"n": "一剑斩仙", "v": "6843"}, {
"n": "传奇天下", "v": "6927"
}, {"n": "斗斗堂", "v": "7133"}, {"n": "斗罗大陆", "v": "6119"}, {
"n": "天谕手游", "v": "5925"
}, {"n": "坎公骑冠剑", "v": "6641"}, {"n": "最终幻想觉醒", "v": "2721"}, {
"n": "神将三国", "v": "6621"
}, {"n": "灌篮高手正版授权手游", "v": "5399"}, {"n": "剑与家园", "v": "2838"}, {
"n": "极无双2", "v": "7825"
}, {"n": "光明大陆", "v": "2832"}, {"n": "荒野行动", "v": "3084"}, {
"n": "战斗法则", "v": "9513"
}, {"n": "疯狂原始人", "v": "4619"}, {"n": "逆战手游", "v": "7575"}, {
"n": "石器时代:觉醒", "v": "9159"
}]
}], "8": [{
"key": "cateId",
"name": "分类",
"init": "1663",
"value": [{"n": "星秀", "v": "1663"}, {"n": "户外", "v": "2165"}, {
"n": "一起看", "v": "2135"
}, {"n": "二次元", "v": "2633"}, {"n": "虚拟偶像", "v": "6055"}, {"n": "旅游", "v": "6791"}, {
"n": "放映厅", "v": "6245"
}, {"n": "娱乐天地", "v": "100022"}, {"n": "交友", "v": "4079"}, {
"n": "组队", "v": "5367"
}, {"n": "吃喝玩乐", "v": "100044"}, {"n": "原创", "v": "6861"}, {
"n": "虎牙文化", "v": "4089"
}, {"n": "体育", "v": "2356"}, {"n": "虎牙地方", "v": "5123"}, {"n": "颜值", "v": "2168"}, {
"n": "科技", "v": "2408"
}, {"n": "音乐", "v": "3793"}, {"n": "趣分享", "v": "5883"}, {"n": "一起买", "v": "7759"}, {
"n": "派对", "v": "7785"
}]
}],
};
if (this.customArea.length > 0) {
const filterCfg = this.customArea.split('#');
this.classes.unshift({"type_id": "custom", "type_name": "自选"});
const filterList = _.map(filterCfg, (it) => {
const filterKv = it.split(',');
return {
n: filterKv[1], v: filterKv[0],
};
});
const defKey = filterList[0];
this.filterObj["custom"] = [{"key": "cateId", "name": "分类", "init": defKey.v, "value": filterList}];
}
if (this.isJustLive) {
// key-value映射修改
const filterKeys = Object.keys(this.filterObj);
for (const filterKey of filterKeys) {
const filterItem = this.filterObj[filterKey];
for (const typeItem of filterItem) {
typeItem.value = _.map(typeItem.value, (it) => {
// 修改默认值
if (it.v === typeItem.init) {
typeItem.init = it.n;
}
return {
n: it.n, v: it.n,
};
});
}
}
}
this.classes.unshift({"type_id": "home", "type_name": "首页"});
}
async setHome(filter) {
await this.setClasses()
await this.setFilterObj()
}
async parseVodShortListFromJson(obj) {
let vod_list = []
if (this.isJustLive) {
for (const it of obj["data"]) {
let vodShort = new VodShort()
vodShort.vod_id = it["roomId"]
vodShort.vod_name = it["ownerName"] + it["roomName"]
vodShort.vod_pic = it["roomPic"]
vodShort.vod_remarks = it["categoryName"]
vod_list.push(vodShort)
}
} else {
for (const it of obj.data.datas) {
let vodShort = new VodShort()
vodShort.vod_id = it["profileRoom"]
vodShort.vod_name = it["nick"] + it["introduction"]
vodShort.vod_pic = it["screenshot"]
vodShort.vod_remarks = it["gameFullName"]
vod_list.push(vodShort)
}
}
return vod_list
}
getPlayUrlData(streamInfo, ratio) {
const hlsUrl = streamInfo["sHlsUrl"] + '/' + streamInfo["sStreamName"] + '.' + streamInfo["sHlsUrlSuffix"];
const srcAntiCode = unescape(streamInfo["sHlsAntiCode"]);
let codeList = srcAntiCode.split('&');
codeList = codeList.filter(code => code !== '');
let cryptoInfo = {};
for (const code of codeList) {
const [k, v] = code.split('=');
cryptoInfo[k] = v;
}
const fm = Utils.unquote(cryptoInfo["fm"]);
const fmDecoded = Utils.base64Decode(fm);
const hashPrefix = fmDecoded.split('_')[0];
const ctype = cryptoInfo["ctype"] || '';
const txyp = cryptoInfo["txyp"] || '';
const fs = cryptoInfo.fs || '';
const t = cryptoInfo.t || '';
const u = 1463993859134;
const curTime = Date.now();
const seqid = Math.floor(curTime + u);
const wsTime = (Math.floor(curTime / 1e3) + 3600).toString(16);
const v0 = seqid + '|' + ctype + '|' + t;
const v1 = Utils.md5Encode(v0);
const v2 = hashPrefix + '_' + u + '_' + streamInfo["sStreamName"] + '_' + v1 + '_' + wsTime;
const hash = Utils.md5Encode(v2);
// ratio = ""
const purl = `${hlsUrl}?wsSecret=${hash}&wsTime=${wsTime}&seqid=${seqid}&ctype=${ctype}&ver=1&txyp=${txyp}&fs=${fs}&ratio=${ratio}&u=${u}&t=${t}&sv=2107230339`;
return {
cdnType: streamInfo["sCdnType"], playUrl: purl,
};
}
async parseVodDetailfromJson(liveInfo, streamInfoList, bitInfoList) {
let vodDetail = new VodDetail()
vodDetail.vod_name = liveInfo["introduction"] ?? liveInfo["sIntroduction"]
vodDetail.vod_pic = liveInfo["screenshot"] ?? liveInfo["sScreenshot"]
vodDetail.vod_remarks = liveInfo["gameFullName"] ?? liveInfo["sGameFullName"]
vodDetail.type_name = liveInfo["gameFullName"] ?? liveInfo["sGameFullName"]
vodDetail.vod_director = liveInfo["nick"] ?? liveInfo["sNick"]
vodDetail.vod_content = liveInfo["activityCount"] ?? liveInfo["lActivityCount"]
vodDetail.vod_content = vodDetail.vod_content + '人在线'
let vod_play_from_list = []
let vod_play_list = []
for (const streamInfo of streamInfoList) {
let vodItems = []
for (const bitinfo of bitInfoList) {
let format_name = this.huYaPlayForamtObj[streamInfo["sCdnType"]]
if (format_name === bitinfo["sDisplayName"]) {
const urlData = this.getPlayUrlData(streamInfo, bitinfo["iBitRate"]);
vod_play_from_list.push(format_name)
vodItems.push("虎牙直播" + '$' + urlData["playUrl"])
vod_play_list.push(vodItems.join("#"))
break
}
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodDetailFromDoc(vodData, playData) {
let vodDetail = new VodDetail()
vodDetail.vod_name = vodData["data"]["roomName"]
vodDetail.vod_director = vodData["data"]["ownerName"]
vodDetail.vod_pic = vodData["data"]["roomPic"]
vodDetail.vod_remarks = vodData["data"]["categoryName"]
vodDetail.vod_content = vodData["data"]["online"] + "人在线"
let vod_play_from_list = []
let vod_play_list = []
for (const key of Object.keys(this.livePlayForamtObj)) {
let vodItems = []
if (playData.data.hasOwnProperty(key)) {
vod_play_from_list.push(this.livePlayForamtObj[key])
vodItems.push("JustLive" + '$' + playData["data"][key])
vod_play_list.push(vodItems.join("#"))
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodShortListFromDocBySearch(data) {
let vod_list = [];
for (const vod of data.response['3']["docs"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod["room_id"]
vodShort.vod_name = vod["game_nick"] + vod["game_introduction"]
vodShort.vod_pic = vod["game_screenshot"]
vodShort.vod_remarks = vod["game_name"]
vod_list.push(vodShort)
}
return vod_list
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0 || typeof pg == 'undefined') pg = 1;
let url = '';
let data = {}
if (this.isJustLive) {
if (tid === 'home') {
url = this.siteUrl + '/api/live/getRecommendByPlatform?platform=huya&size=20&page=' + pg;
} else {
url = this.siteUrl + '/api/live/getRecommendByPlatformArea?platform=huya&size=20&area=' + extend.cateId + '&page=' + pg;
}
data = JSON.parse(await this.fetch(url, null, this.getHeader()));
} else {
if (tid === 'home') {
url = this.siteUrl + '/cache.php?m=LiveList&do=getLiveListByPage&tagAll=1&page=' + pg;
} else {
url = this.siteUrl + '/cache.php?m=LiveList&do=getLiveListByPage&gameId=' + extend["cateId"] + '&tagAll=0&page=' + pg;
}
data = JSON.parse(await this.fetch(url, null, this.getHeader()));
}
this.vodList = await this.parseVodShortListFromJson(data)
}
async setDetail(id) {
let liveInfo = null;
let streamInfoList = null;
if (this.isJustLive) {
await this.jadeLog.debug("JustLive", true)
const vodInfo = await this.fetch(this.siteUrl + `/api/live/getRoomInfo?platform=huya&roomId=${id}`, null, this.getHeader())
const playInfo = await this.fetch(this.siteUrl + `/api/live/getRealUrl?platform=huya&roomId=${id}`, null, this.getHeader())
const vodData = JSON.parse(vodInfo);
const playData = JSON.parse(playInfo)
this.vodDetail = await this.parseVodDetailFromDoc(vodData, playData)
} else {
await this.jadeLog.debug("虎牙直播", true)
const resp = await this.fetch('https://mp.huya.com/cache.php?m=Live&do=profileRoom&roomid=' + id, null, this.getHeader());
const data = JSON.parse(resp);
liveInfo = data.data["liveData"];
let bitInfo = JSON.parse(liveInfo["bitRateInfo"])
streamInfoList = data.data.stream["baseSteamInfoList"];
this.vodDetail = await this.parseVodDetailfromJson(liveInfo, streamInfoList, bitInfo)
}
/**
*
* await this.jadeLog.debug("虎牙直播",true)
* const headers = {
* 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': Utils.MOBILEUA,
* };
* let content = await this.fetch('https://m.huya.com/' + id, null, headers);
* let liveData = JSON.parse(Utils.getStrByRegex(/<script> window.HNF_GLOBAL_INIT = (.*?)<\/script>/, content))
* const vodData = liveData["roomInfo"];
* liveInfo = vodData["tLiveInfo"];
* streamInfoList = vodData["tLiveInfo"]["tLiveStreamInfo"]["vStreamInfo"]["value"]
* let bitInfoList = vodData["tLiveInfo"]["tLiveStreamInfo"]["vBitRateInfo"]["value"]
* this.vodDetail = await this.parseVodDetailfromJson(liveInfo, streamInfoList, bitInfoList)
* */
}
async setSearch(wd, quick) {
const resp = await this.fetch('https://search.cdn.huya.com/?m=Search&do=getSearchContent&q=' + wd + '&uid=0&v=4&typ=-5&livestate=0&rows=40&start=0', null, this.getHeader());
const data = JSON.parse(resp);
this.vodList = await this.parseVodShortListFromDocBySearch(data)
}
}
let spider = new HuyaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

319
JN/CATJS/js/ikanbot.js Normal file
View File

@ -0,0 +1,319 @@
/*
* @File : ikanbot.js
* @Author : jade
* @Date : 2024/1/15 10:32
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {load, _} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
function _0xf746(_0xbb40c4, _0x1cb776) {
const _0x45e084 = _0x45e0();
return _0xf746 = function (_0xf74696, _0x4d32af) {
_0xf74696 = _0xf74696 - 0x1a8;
let _0xcbfa28 = _0x45e084[_0xf74696];
return _0xcbfa28;
}, _0xf746(_0xbb40c4, _0x1cb776);
}
function _0x45e0() {
const _0x58b10c = ['1580630GngmmA', '117uvwflw', 'join', 'current_id', '565448Apkhig', '23092JwmytW', '707152yowhOv', 'getElementById', '855936CGaczt', 'length', '2966831GCGpvn', '611266nfcTEf', 'value', 'substring'];
_0x45e0 = function () {
return _0x58b10c;
};
return _0x45e0();
}
(function (_0x27923d, _0x43d7fc) {
const _0x439396 = _0xf746, _0x30f164 = _0x27923d();
while (!![]) {
try {
const _0xa560eb = -parseInt(_0x439396(0x1b4)) / 0x1 + parseInt(_0x439396(0x1ad)) / 0x2 + -parseInt(_0x439396(0x1b1)) / 0x3 * (-parseInt(_0x439396(0x1b5)) / 0x4) + -parseInt(_0x439396(0x1b0)) / 0x5 + parseInt(_0x439396(0x1aa)) / 0x6 + parseInt(_0x439396(0x1ac)) / 0x7 + parseInt(_0x439396(0x1a8)) / 0x8;
if (_0xa560eb === _0x43d7fc) break; else _0x30f164['push'](_0x30f164['shift']());
} catch (_0x3ae316) {
_0x30f164['push'](_0x30f164['shift']());
}
}
}(_0x45e0, 0x4a3d9));
function get_tks(play_id, e_token) {
const _0xf07220 = _0xf746;
let _0x35162d = play_id, _0xf25678 = e_token;
if (!_0x35162d || !_0xf25678) return;
let _0x3882a3 = _0x35162d['length'], _0x52a097 = _0x35162d[_0xf07220(0x1af)](_0x3882a3 - 0x4, _0x3882a3),
_0x2d9d1b = [];
for (let _0x570711 = 0x0; _0x570711 < _0x52a097[_0xf07220(0x1ab)]; _0x570711++) {
let _0x23e537 = parseInt(_0x52a097[_0x570711]), _0x48b93d = _0x23e537 % 0x3 + 0x1;
_0x2d9d1b[_0x570711] = _0xf25678[_0xf07220(0x1af)](_0x48b93d, _0x48b93d + 0x8), _0xf25678 = _0xf25678[_0xf07220(0x1af)](_0x48b93d + 0x8, _0xf25678[_0xf07220(0x1ab)]);
}
return _0x2d9d1b[_0xf07220(0x1b2)]('');
}
class IKanBotSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://v.ikanbot.com"
}
getName() {
return "🤖┃爱看机器人┃🤖"
}
getAppName() {
return "爱看机器人"
}
getJSName() {
return "ikanbot"
}
getType() {
return 3
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromDoc($) {
let vod_list = [];
let VodShortElements = $($("[class=\"row list-wp\"]")).find("a")
for (const vodShortElement of VodShortElements) {
let vodShort = new VodShort()
let reElement = $(vodShortElement).find("img")[0]
vodShort.vod_id = vodShortElement.attribs["href"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(reElement.attribs["data-src"])
vodShort.vod_name = reElement.attribs["alt"]
vod_list.push(vodShort)
}
return vod_list
}
getChildren(detail, index) {
try {
return detail[index].children[0].data;
} catch (e) {
return ""
}
}
async parseVodDetailFromDoc($) {
const detail = $('div.detail > .meta');
let vodDetail = new VodDetail();
vodDetail.vod_pic = this.jsBase + Utils.base64Encode($('div.item-root > img')[0].attribs['data-src'])
vodDetail.vod_name = this.getChildren(detail, 0)
vodDetail.vod_year = this.getChildren(detail, 1)
vodDetail.vod_area = this.getChildren(detail, 3);
vodDetail.vod_actor = this.getChildren(detail, 4);
let id = Utils.getStrByRegex(/<input type="hidden" id="current_id" value="(.*?)"/, $.html())
let token = Utils.getStrByRegex(/<input type="hidden" id="e_token" value="(.*?)"/, $.html())
let mtype = Utils.getStrByRegex(/<input type="hidden" id="mtype" value="(.*?)"/, $.html())
let params = {
"videoId": id, "mtype": mtype, "token": get_tks(id, token),
}
let content = await this.fetch(this.siteUrl + '/api/getResN', params, this.getHeader())
const list = JSON.parse(content)["data"]["list"];
let playlist = {};
let index = 0
let form_list = []
for (const l of list) {
const flagData = JSON.parse(l["resData"]);
for (const f of flagData) {
index = index + 1
const from = f.flag;
const urls = f.url;
if (!from || !urls) continue;
if (playlist[from]) continue;
form_list.push(`线路${index}`)
playlist[from] = urls;
}
}
vodDetail.vod_play_from = form_list.join('$$$');
vodDetail.vod_play_url = _.values(playlist).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
const items = $('div.media > div.media-left > a');
for (const item of items) {
let vodShort = new VodShort();
const img = $(item).find('img:first')[0];
vodShort.vod_id = item.attribs.href
vodShort.vod_name = img.attribs.alt
vodShort.vod_pic = this.jsBase + Utils.base64Encode(img.attribs['data-src'])
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let html = await this.fetch(this.siteUrl + "/category", null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let classElements = $($($("[class=\"row visible-xs-block visible-sm-block\"]")).find("li")).find("a")
for (const classElement of classElements) {
this.classes.push({"type_name": $(classElement).text(), "type_id": classElement.attribs["href"]})
}
}
}
async setFilterObj() {
for (const class_dic of this.classes.slice(1, 9)) {
let type_id = class_dic["type_id"]
if (type_id.indexOf("category") === -1 || type_id.indexOf(",") > -1) {
let type_url = type_id.split(",").slice(-1)[0]
let html = await this.fetch(this.siteUrl + type_url, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let containerElement = $("[class=\"row visible-xs-block visible-sm-block\"]")
let filterElements = containerElement.find("[class=\"nav nav-pills\"]").find("a")
let value_list = []
if (type_id.indexOf(",") > -1) {
value_list.push({"n": "全部", "v": type_id.split(",")[0]})
}
let extend_dic = {
"key": type_id, "name": $(containerElement.find("h5")).text(), "value": value_list
}
for (const filterElement of filterElements) {
value_list.push({"n": $(filterElement).text(), "v": filterElement.attribs["href"]})
}
if (value_list.length > 0) {
this.filterObj[type_id] = [extend_dic]
}
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let categoryUrl = (this.siteUrl + (extend[tid] || tid.split(",")[0]))
let update_page = false
if (categoryUrl.indexOf("html") > -1) {
categoryUrl = categoryUrl.replace('.html', pg > 1 ? `-p-${pg}.html` : '.html');
} else {
categoryUrl = categoryUrl + `?p=${pg}`
update_page = true
}
await this.jadeLog.debug(`分类URL:${categoryUrl}`)
let html = await this.fetch(categoryUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let pageDoc = $('div.page-more > a:contains(下一页)')
if (update_page) {
this.page = parseInt(pageDoc[0].attribs["href"].split("p=")[1])
}
const hasMore = pageDoc.length > 0;
this.limit = 24
this.count = hasMore ? parseInt(pg) + 1 : parseInt(pg);
this.total = this.limit * this.count
}
}
async setDetail(id) {
let html = await this.fetch(this.siteUrl + id, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setSearch(wd, quick) {
const html = await this.fetch(this.siteUrl + '/search?q=' + wd, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
}
}
let spider = new IKanBotSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

317
JN/CATJS/js/jable.js Normal file
View File

@ -0,0 +1,317 @@
/*
* @File : jable.js
* @Author : jade
* @Date : 2024/3/4 9:44
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class JableTVSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://jable.tv"
this.cookie = ""
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getImgHeaders());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getImgHeaders());
}
}
getImgHeaders(){
return {
"User-Agent": "PostmanRuntime/7.37.3",
"Postman-Token": "c2602692-1a05-4bb0-93cd-270afad97e87",
"Host": "assets-cdn.jable.tv",
"Proxy": true
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getAppName() {
return "Jable"
}
getName() {
return "🔞┃Jable┃🔞"
}
getJSName() {
return "jable"
}
getType() {
return 3
}
getHeader() {
// let header = super.getHeader()
let header = {}
header["User-Agent"] = "PostmanRuntime/7.36.3"
header["Host"] = "jable.tv"
header["Postman-Token"] = "33290483-3c8d-413f-a160-0d3aea9e6f95"
return header
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
return super.getHtml(url, true, headers);
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"title-box\"]")
let defaultTypeIdElements = $("div.row")
for (const navElement of $(defaultTypeIdElements[0]).find("a")) {
let type_name = $(navElement).text()
let type_id = navElement.attribs.href
if (type_id.indexOf(this.siteUrl) > -1) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
navElements = navElements.slice(1, 9)
defaultTypeIdElements = defaultTypeIdElements.slice(1, 9)
for (let i = 0; i < navElements.length; i++) {
let typeId = $(defaultTypeIdElements[i]).find("a")[0].attribs["href"]
this.classes.push(this.getTypeDic("标签", typeId));
break
}
}
async getSortFilter($) {
let sortElements = $("[class=\"sorting-nav\"]").find("a")
let extend_dic = {"name": "排序", "key": "sort", "value": []}
for (const sortElement of sortElements) {
let typeId = sortElement.attribs["data-parameters"].split("sort_by:")[1]
let typeName = $(sortElement).text()
extend_dic["value"].push({"n": typeName, "v": typeId})
}
return extend_dic
}
async getFilter($, index, type_id, type_name) {
let extend_list = []
if (index < 4) {
let extend_dic = {"name": type_name, "key": "type", "value": []}
let type_seletc_list = ["div.img-box > a", "[class=\"horizontal-img-box ml-3 mb-3\"] > a", "", "sort"]
let type_id_select_list = ["div.absolute-center > h4", "div.detail"]
let default$ = await this.getHtml(type_id)
for (const element of default$(type_seletc_list[index])) {
let typeId = element.attribs["href"]
let typeName = $($(element).find(type_id_select_list[index])).text().replaceAll("\t", "").replaceAll("\n", '').replaceAll(" ", "");
extend_dic["value"].push({"n": typeName, "v": typeId})
}
if (extend_dic.value.length > 0) {
extend_list.push(extend_dic)
//排序
let sortDetail$ = await this.getHtml(extend_dic["value"][0]["v"])
let sort_extend_dic = await this.getSortFilter(sortDetail$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
} else {
//排序
let sort_extend_dic = await this.getSortFilter(default$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
}
} else {
let defaultTypeIdElements = $("div.row").slice(1, 9)
let navElements = $("[class=\"title-box\"]").slice(1, 9)
for (let i = 0; i < navElements.length; i++) {
let extend_dic = {"name": $($(navElements[i]).find("h2")).text(), "key": "type", "value": []}
for (const filterElement of $(defaultTypeIdElements[i]).find("a")) {
let filter_type_id = filterElement.attribs.href
if (filter_type_id.indexOf(this.siteUrl) > -1) {
extend_dic["value"].push({"n": $(filterElement).text(), "v": filter_type_id})
}
}
extend_list.push(extend_dic)
}
let sortDetail$ = await this.getHtml(type_id)
let sort_extend_dic = await this.getSortFilter(sortDetail$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
}
return extend_list
}
async setFilterObj() {
let $ = await this.getHtml(this.siteUrl)
let classes = this.classes.slice(1)
for (let i = 0; i < classes.length; i++) {
let type_name = classes[i].type_name
let type_id = classes[i].type_id
// if (type_id.indexOf("models") > 1) {
// type_id = `https://jable.tv/models/?mode=async&function=get_block&block_id=list_models_models_list&sort_by=total_videos&_=${new Date().getTime()}`
// }
let extend_list = await this.getFilter($, i, type_id, type_name)
if (extend_list.length > 1 && i < 4) {
type_id = extend_list[0]["value"][0]["v"]
this.classes[i + 1] = this.getTypeDic(type_name, type_id)
}
this.filterObj[type_id] = extend_list
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("div.video-img-box")
for (const element of vodElements) {
let vodShort = new VodShort()
let vod_pic = $(element).find("img").attr("data-src")
if (vod_pic !== undefined) {
vodShort.vod_pic = vod_pic
// if (this.catOpenStatus) {
// vodShort.vod_pic = this.jsBase + Utils.base64Encode(vod_pic)
// } else {
// vodShort.vod_pic = vod_pic
// }
let url = $(element).find("a").attr("href");
vodShort.vod_id = url.split("/")[4];
vodShort.vod_name = url.split("/")[4];
let remarks_list = $($(element).find("[class=\"sub-title\"]")).text().split("\n")
if (remarks_list.length > 1) {
vodShort.vod_remarks = remarks_list[1].replaceAll(" ", "").replaceAll("\t", "")
} else {
vodShort.vod_remarks = "精选"
}
if (!_.isEmpty(vodShort.vod_pic) && vodShort.vod_remarks !== "[限時優惠]只需1元即可無限下載") {
vod_list.push(vodShort);
}
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let leftElement = $("[class=\"header-left\"]")
vodDetail.vod_name = $($(leftElement).find("h4")).text();
let vod_pic = Utils.getStrByRegex(/<video poster="(.*?)" id=/, $.html())
vodDetail.vod_pic = vod_pic
// if (this.catOpenStatus) {
// vodDetail.vod_pic = this.jsBase + Utils.base64Encode(vod_pic)
// } else {
// vodDetail.vod_pic = vod_pic
// }
vodDetail.vod_year = $($("[class=\"inactive-color\"]")).text()
let episodeName = $($("[class=\"header-right d-none d-md-block\"] > h6")).text().replaceAll("\n", "").replaceAll("●", "")
let vodItems = []
let episodeUrl = Utils.getStrByRegex(/var hlsUrl = '(.*?)';/, $.html())
vodItems.push(episodeName + "$" + episodeUrl)
let vod_play_list = []
vod_play_list.push(vodItems.join("#"))
let vod_play_from_list = ["Jable"]
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + "/videos/" + id + "/")
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let extend_type = extend["type"] ?? tid
let sort_by = extend["sort"] ?? "video_viewed"
this.limit = 24
let cateUrl;
this.total = 0
this.count = 0
if (tid.indexOf("latest-updates") > 1) {
cateUrl = `https://jable.tv/latest-updates/?mode=async&function=get_block&block_id=list_videos_latest_videos_list&sort_by=post_date&from=${pg}&_=1709730132217`
} else {
cateUrl = extend_type + `/${pg}/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=${sort_by}&_=${new Date().getTime()}`
}
let $ = await this.getHtml(cateUrl);
this.vodList = await this.parseVodShortListFromDoc($)
let page = $($("[class=\"page-item\"]").slice(-1)[0]).text()
if (page.indexOf("最後") > -1) {
} else {
if (parseInt(page) === this.page || _.isEmpty(page)) {
await this.jadeLog.debug("分类页面到底了")
this.total = this.page
this.count = this.page
}
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/search/${wd}/`
let $ = await this.getHtml(searchUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new JableTVSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

295
JN/CATJS/js/jiafeimao.js Normal file
View File

@ -0,0 +1,295 @@
/*
* @File : jiafeimao.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 加菲猫 (已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class JiaFeiMaoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://jfmys.app"
}
getAppName() {
return "加菲猫"
}
getName() {
return `🐈┃加菲猫┃🐈`
}
getJSName() {
return "jiafeimao"
}
getType() {
return 3
}
getPic(url){
if (url.indexOf("http:") > -1 || url.indexOf("https:") > -1){
return url
}else{
return this.siteUrl + url
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/id\/(.*?)\//,$(element).find("a")[0].attribs.href)
vodShort.vod_name = $(element).find("a")[0].attribs.title
vodShort.vod_pic = this.getPic($(element).find("img")[0].attribs["data-src"])
vodShort.vod_remarks = $($(element).find("[class=\"v-tips\"]")).html()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $(".icon > .container").find("[class=\"imain clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"tv-list clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $($("[class=\"iptit\"]").find("h3")).html().split(" ")[0]
vodDetail.vod_content = $($("[class=\"idetail container\"]").find("[class=\"infor_intro\"]")).text()
let vodPlayElements = $("[class=\"fjcon\"]")
let vod_play_from_list = []
let vod_play_list = []
let playFormatElemets = $($(vodPlayElements).find("[class=\"fjtop clearfix\"]")).find("a")
let playUrlElements = $(vodPlayElements).find("[class=\"xjn_ul play-list\"]")
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push("线路" +( i+1).toString())
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
parseVodDetail(vod_data) {
let vodDetail = new VodDetail()
vodDetail.vod_name = vod_data["vod_name"]
vodDetail.vod_pic = this.getPic(vod_data["vod_pic"])
vodDetail.vod_remarks = vod_data["vod_remarks"]
vodDetail.vod_area = vod_data["vod_area"]
vodDetail.vod_year = vod_data["vod_year"]
vodDetail.vod_actor = vod_data["vod_actor"]
vodDetail.vod_director = vod_data["vod_director"]
vodDetail.vod_content = vod_data["vod_content"].replaceAll("<p>","").replaceAll("</p>","")
let vod_play_from = []
for (let i = 0; i < vod_data["vod_play_from"].split("$$$").length; i++) {
vod_play_from.push("线路"+(i+1).toString())
}
vodDetail.vod_play_from = vod_play_from.join("$$$")
vodDetail.vod_play_url = vod_data["vod_play_url"]
vodDetail.type_name = vod_data["type_name"]
return vodDetail
}
async parseVodDetailfromJson(obj) {
let vodDetail;
let vod_data_list = obj["list"]
if (vod_data_list.length > 0) {
let vod_data = vod_data_list[0]
vodDetail = this.parseVodDetail(vod_data)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"tv-bd search-list\"]").find("[class=\"item clearfix\"]")
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/id\/(.*?).html/, $($(vodElement).find("[class=\"s_tit\"]")).find("a")[0].attribs.href)
vodShort.vod_name = $($($(vodElement).find("[class=\"s_tit\"]")).find("a")).text()
vodShort.vod_pic = this.getPic($(vodElement).find("img")[0].attribs.src)
vodShort.vod_remarks = $($(vodElement).find("[class=\"s_score\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let $ = await this.getHtml()
let content = $($("[class=\"container\"]").find("script")).html()
let navContent = Utils.getStrByRegex(/document.write\('(.*?);/, content)
for (const navElement of $(navContent).find("a")) {
let type_id = navElement.attribs["href"]
let type_name = $(navElement).text()
if (type_id !== "/" && type_name !== "专题" && type_name !== "站长模板") {
this.classes.push(this.getTypeDic(type_name, Utils.getStrByRegex(/id\/(.*?).html/, type_id)))
}
}
}
async getFilter($) {
let elements = $($("[class=\"container\"]").find("[class=\"select_list clearfix\"]")).find("li")
let extend_list = []
let key_value_dic = {
"分类": /id\/(.*?).html/,
"地区": /area\/(.*?)\//,
"年份": /year\/(.*?).html/,
"字母": /letter\/(.*?).html/,
"排序": /by\/(.*?)\//,
}
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
let name = $($($(element).find("[class=\"v-tit\"]"))).text().replaceAll("", "")
if (name !== "频道") {
let extend_dic = {"key": (i + 1).toString(), "name": name, "value": []}
for (const ele of $(element).find("a")) {
let type_id = Utils.getStrByRegex(key_value_dic[name], ele.attribs.href)
if (_.isEmpty(type_id)) {
type_id = "/"
}
extend_dic["value"].push({"n": $(ele).text(), "v": decodeURIComponent(type_id)})
}
extend_list.push(extend_dic)
}
}
let sortElments = $("[class=\"v-hd clearfix\"]")
let extend_dic = {"key": (elements.length + 1).toString(), "name": "排序", "value": []}
extend_dic["value"].push({"n": "全部", "v": "/"})
for (const ele of $(sortElments).find("a")) {
let type_id = Utils.getStrByRegex(key_value_dic["排序"], ele.attribs.href)
if (_.isEmpty(type_id)) {
type_id = "/"
}
extend_dic["value"].push({"n": $(ele).text(), "v": type_id})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + `/index.php/vod/show/id/${type_id}.html`)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtend(extend, key, value) {
if (extend[key] !== undefined && extend[key] !== "/") {
return value + "/" + extend[key] + "/"
} else {
return ""
}
}
async setCategory(tid, pg, filter, extend) {
let area = this.getExtend(extend, "3", "area")
let sort = this.getExtend(extend, "6", "by")
let id = this.getExtend(extend, "2", "id")
let letter = this.getExtend(extend, "5", "letter")
let year = this.getExtend(extend, "4", "year")
if (_.isEmpty(id)) {
id = "id/" + tid + "/"
}
let url = this.siteUrl + `/index.php/vod/show/${area}${sort}${id}${letter}${year}page/${pg}.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": id
}, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(content))
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + "/index.php/vod/search.html?wd="+wd)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new JiaFeiMaoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

482
JN/CATJS/js/jianpian.js Normal file
View File

@ -0,0 +1,482 @@
/*
* @File : jianpian.js
* @Author : jade
* @Date : 2024/1/15 10:32
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 完成荐片所有功能添加弹幕
*/
import {Spider} from "./spider.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class JianPianSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://api2.rinhome.com"
// this.siteUrl = "https://ownjpykxttjzuhy.jiesiwa.com"
}
getName() {
return "🌼┃荐片┃🌼"
}
getAppName() {
return "荐片"
}
getJSName() {
return "jianpian"
}
getType() {
return 3
}
getHeader() {
return {
"User-Agent": "jianpian-android/360",
"JPAUTH": "y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv",
"Referer": "www.jianpianapp.com"
}
}
async spiderInit(inReq=null) {
if (inReq !== null){
this.jsBase = await js2Proxy(inReq,"img",this.getHeader());
}else{
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.spiderInit(null)
}
async parseVodShortListFromJson(data_list) {
let vod_list = [];
for (const data of data_list) {
let vodShort = new VodShort();
vodShort.vod_id = data["id"]
if (data["path"] !== undefined) {
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["path"])
} else {
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["thumbnail"])
}
vodShort.vod_name = data["title"]
if (data["mask"] !== undefined){
vodShort.vod_remarks = data["mask"]
}else{
vodShort.vod_remarks = data["playlist"]["title"]
}
vod_list.push(vodShort)
}
return vod_list
}
objToList(list, key, split_value = "*") {
let value_list = []
for (const dic of list) {
value_list.push(dic[key])
}
return value_list.join(split_value)
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail();
vodDetail.vod_id = obj["id"]
vodDetail.vod_year = obj["year"]["title"]
if (!this.catOpenStatus) {
vodDetail.vod_pic = obj["thumbnail"] + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version353@JPAUTH=y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv"
} else {
vodDetail.vod_pic = this.jsBase + Utils.base64Encode(obj["thumbnail"])
}
vodDetail.type_name = obj["category"][0]["title"]
vodDetail.vod_name = obj["title"]
vodDetail.vod_content = obj["description"]
vodDetail.vod_area = obj["area"]["title"]
vodDetail.vod_director = this.objToList(obj["directors"], "name")
vodDetail.vod_actor = this.objToList(obj["actors"], "name")
vodDetail.vod_remarks = "评分:" + obj["score"]
let playKeyList = [{"btbo_downlist": "btbo"}, {"xunlei_downlist": "迅雷"}, {"m3u8_downlist": "m3u8"}, {"new_ftp_list": "new_ftp"}, {"new_m3u8_list": "new_m3u8"}]
let playlist = {}
let urlList = []
for (const dic of playKeyList) {
let key = Object.keys(dic)[0]
let value = Object.values(dic)[0]
if (obj[key].length > 0) {
let url_str_list = []
for (const dic of obj[key]) {
url_str_list.push(dic["title"] + "$" + dic["url"])
}
if (urlList.indexOf(url_str_list.join("#")) === -1) {
urlList.push(url_str_list.join("#"))
playlist[value] = url_str_list.join("#")
} else {
await this.jadeLog.warning(`key为:${key},播放链接重复,无需保存`)
}
}
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setClasses() {
let type_name_list = ["全部", "电影", "电视剧", "动漫", "综艺"]
let type_id_list = ["0", "1", "2", "3", "4"]
for (let i = 0; i < type_name_list.length; i++) {
let type_name = type_name_list[i]
let type_id = type_id_list[i]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
}
async setFilterObj() {
this.filterObj = {
"0": [{
"key": "area", "name": "地區", "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": "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": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "1": [{
"key": "area", "name": "地區", "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": "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": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "2": [{
"key": "area", "name": "地區", "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": "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": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "3": [{
"key": "area", "name": "地區", "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": "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": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "4": [{
"key": "area", "name": "地區", "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": "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": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}]
}
}
async setHomeVod() {
let content = await this.fetch(this.siteUrl + "/api/tag/hand?code=unknown601193cf375db73d&channel=wandoujia", null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data_list = content_json["data"][0]["video"]
this.homeVodList = await this.parseVodShortListFromJson(data_list)
}
}
async setCategory(tid, pg, filter, extend) {
let cateId = extend["cateId"] ?? tid
let area = extend["area"] ?? "0";
let year = extend["year"] ?? "0";
let by = extend["by"] ?? "hot";
this.limit = 24
let categoryUrl = this.siteUrl + `/api/crumb/list?area=${area}&category_id=${cateId}&page=${pg}&type=0&limit=24&sort=${by}&year=${year}`
await this.jadeLog.debug(`分类URL:${categoryUrl}`)
let content = await this.fetch(categoryUrl, null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data = content_json["data"]
this.vodList = await this.parseVodShortListFromJson(data)
}
}
async setDetail(id) {
let url = this.siteUrl + "/api/node/detail?channel=wandoujia&token=&id=" + id;
let content = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content);
let data_list = content_json["data"]
this.vodDetail = await this.parseVodDetailfromJson(data_list)
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/api/video/search?page=1" + "&key=" + wd;
const content = await this.fetch(url, null, this.getHeader());
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data_list = content_json["data"]
this.vodList = await this.parseVodShortListFromJson(data_list)
}
}
async setPlay(flag, id, flags) {
await this.jadeLog.debug(`播放链接为:${id}`)
this.playUrl = id
}
}
let spider = new JianPianSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

282
JN/CATJS/js/jiujiuliu.js Normal file
View File

@ -0,0 +1,282 @@
/*
* @File : jiujiuliu.js
* @Author : jade
* @Date : 2024/1/4 14:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 996影视
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class JiuJiuLiuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.ojig519d8se.icu"
}
getName() {
return "🔞┃九九六影视┃🔞"
}
getAppName() {
return "九九六影视"
}
getJSName() {
return "jiujiuliu"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"stui-vodlist clearfix\"]").find("li")
for (const vodElement of vodElements) {
let resource = $(vodElement).find("[class=\"stui-vodlist__thumb lazyload\"]")[0]
let vodShort = new VodShort()
vodShort.vod_id = resource.attribs["href"]
vodShort.vod_name = resource.attribs["title"]
vodShort.vod_pic = resource.attribs["data-original"]
vodShort.vod_remarks = $($(resource).find("[class=\"pic-text text-right\"]")[0]).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"stui-pannel_bd\"]").find("li")
for (const vodElement of vodElements) {
let resource = $($(vodElement).find("[class=\"thumb\"]")[0]).find("a")[0]
let vodShort = new VodShort()
vodShort.vod_id = resource.attribs["href"]
vodShort.vod_name = resource.attribs["title"]
vodShort.vod_pic = resource.attribs["data-original"]
vodShort.vod_remarks = Utils.getStrByRegex(/类型:(.*?)地区/, $($(vodElement).find("[class=\"hidden-mi\"]")[0]).text())
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"col-pd clearfix\"]")[1]
let vodShortElement = $(vodElement).find("[class=\"stui-content__thumb\"]")[0]
let vodItems = []
for (const playElement of $("[class=\"stui-content__playlist clearfix\"]").find("a")) {
let episodeUrl = this.siteUrl + playElement.attribs["href"];
let episodeName = $(playElement).text();
vodItems.push(episodeName + "$" + episodeUrl);
}
vodDetail.vod_name = $(vodShortElement).find("[class=\"stui-vodlist__thumb picture v-thumb\"]")[0].attribs["title"]
vodDetail.vod_pic = $(vodShortElement).find("img")[0].attribs["data-original"]
vodDetail.vod_remarks = $($(vodShortElement).find("[class=\"pic-text text-right\"]")[0]).text()
let data_str = $($(vodElement).find("[class=\"data\"]")).text().replaceAll(" ", " ")
vodDetail.type_name = Utils.getStrByRegex(/类型:(.*?) /, data_str)
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?) /, data_str)
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?) /, data_str)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?) /, data_str)
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?) /, data_str)
vodDetail.vod_content = $($("[class=\"stui-pannel_bd\"]").find("[class=\"col-pd\"]")).text()
vodDetail.vod_play_from = ["996"].join("$$$")
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader(),false,false,0,true)
if (html !== null) {
let $ = load(html)
let menuElements = $("[class=\"stui-header__menu type-slide\"]").find("a")
for (const menuElement of menuElements) {
let type_dic = {
"type_name": $(menuElement).text(),
"type_id": "/show/id/" + menuElement.attribs["href"].split("/").slice(-1)[0].split(".")[0]
}
if ($(menuElement).text() !== "首页") {
this.classes.push(type_dic)
}
}
}
let x = 0
}
async getFilter($) {
let hdElements = $("[class=\"stui-pannel_hd\"]")
let extend_list = []
let index = 0
for (let i = 0; i < 2; i++) {
let cateElemet = hdElements[i]
let typeElements = $(cateElemet).find("ul")
if (i === 0) {
for (const typeElement of typeElements) {
let extend_dic = {
"key": (index + 1).toString(), "name": $($(typeElement).find("li")[0]).text(), "value": []
}
for (const ele of $(typeElement).find("li").slice(1)) {
if (!_.isEmpty($(ele).text())) {
if (index === 0) {
extend_dic["value"].push({
"n": $(ele).text(),
"v": $(ele).find("a")[0].attribs["href"].split("/").slice(-1)[0].split(".")[0]
})
} else {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
}
}
extend_list.push(extend_dic)
index = index + 1
}
} else {
let extend_dic = {
"key": (index + 1).toString(), "name": $($(cateElemet).find("li")[0]).text(), "value": []
}
extend_dic["value"].push({"n": "全部", "v": "time"})
for (const ele of $(cateElemet).find("li").slice(1)) {
if (!_.isEmpty($(ele).text())) {
extend_dic["value"].push({
"n": $(ele).text(), "v": $(ele).find("a")[0].attribs["href"].split("/")[3]
})
}
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + type_id + ".html"
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
getParams(params, value) {
let x = value ?? "全部"
if (x === "全部" || x === undefined) {
return ""
} else {
return params + value
}
}
async setCategory(tid, pg, filter, extend) {
let typeName = this.getParams("/id/", extend["1"])
if (_.isEmpty(typeName)) {
typeName = "/id/" + tid.split("/").slice(-1)[0]
}
let plot = this.getParams("/class/", extend["2"])
let area = this.getParams("/area/", extend["3"])
let year = this.getParams("/year/", extend["4"])
let language = this.getParams("/lang/ ", extend["5"])
let letter = this.getParams("/letter/ ", extend["6"])
let time = this.getParams("/by/", extend["7"])
let cateUrl = this.siteUrl + `/show${area}${time}${plot}${typeName}${language}${letter}${year}/page/${pg.toString()}.html`
await this.jadeLog.info(`类别URL为:${cateUrl}`)
this.limit = 36
let html = await this.fetch(cateUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id
let html = await this.fetch(detailUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/search.html?wd=${wd}`
let html = await this.fetch(searchUrl, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
let x = 0
}
async setPlay(flag, id, flags) {
let html = await this.fetch(id, null, this.getHeader())
if (html !== null) {
let matcher = Utils.getStrByRegex(/player_aaaa=(.*?)<\/script>/, html)
let player = JSON.parse(matcher);
try {
this.playUrl = decodeURIComponent(Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(player["url"])))
this.header = this.getHeader()
} catch (e) {
this.playUrl = player["url"]
}
}
}
}
let spider = new JiuJiuLiuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

308
JN/CATJS/js/kankan70.js Normal file
View File

@ -0,0 +1,308 @@
/*
* @File : kankan70.js
* @Author : jade
* @Date : 2023/12/29 15:33
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
function get_qp_name44(qp_type) {
if (qp_type === 'zd') return '最大';
if (qp_type === 'yj') return '永久';
if (qp_type === 'hn') return '牛牛';
if (qp_type === 'gs') return '光波';
if (qp_type === 'sn') return '新朗';
if (qp_type === 'wl') return '涡轮';
if (qp_type === 'lz') return '良子';
if (qp_type === 'fs') return 'F速';
if (qp_type === 'ff') return '飞飞';
if (qp_type === 'bd') return '百度';
if (qp_type === 'uk') return '酷U';
if (qp_type === 'wj') return '无天';
if (qp_type === 'bj') return '八戒';
if (qp_type === 'tk') return '天空';
if (qp_type === 'ss') return '速速';
if (qp_type === 'kb') return '酷播';
if (qp_type === 'sd') return '闪电';
if (qp_type === 'xk') return '看看';
if (qp_type === 'tp') return '淘淘';
if (qp_type === 'jy') return '精英';
return qp_type;
}
class Kankan70Spider extends Spider {
constructor() {
super();
this.siteUrl = "http://cqdb6.com";
}
getName() {
return "📺┃70看看┃📺"
}
getAppName() {
return "70看看"
}
getJSName() {
return "kankan70"
}
getType() {
return 3
}
paraseUrlObject(js_str) {
let content_list = js_str.split(";")
let urlObject = {}
let js_name = ""
let play_id = 0
let pldy_id = 0
let js_key = ""
for (let i = 0; i < content_list.length; i++) {
let content = content_list[i]
if (content.indexOf("var lianzaijs") > -1) {
js_name = content.split("=")[0].split(" ")[1]
js_key = js_name.split("_")[1]
} else if (content.indexOf("pl_id=") > -1) {
play_id = content.split("=")[1]
urlObject[js_name] = {"play_id": play_id, "list": [], "pl_dy": pldy_id}
} else if (content.indexOf("var pl_dy") > -1) {
pldy_id = content.split("=")[1]
}
if (content.indexOf(`playarr_${js_key}[`) > -1) {
let play_url = content.split("=\"")[1].split(",")[0]
urlObject[js_name]["list"].push(play_url)
}
}
let play_url_list = [], play_format_list = [];
for (const key of Object.keys(urlObject)) {
if (key.indexOf("_") > -1) {
let play_format_name = get_qp_name44(key.split("_")[1])
play_format_list.push(play_format_name)
let vodItems = []
let index = 0
for (const play_url of urlObject[key]["list"]) {
index = index + 1
vodItems.push("第" + index.toString() + "集" + "$" + play_url)
}
play_url_list.push(vodItems.join("#"))
}
}
return {"play_format": play_format_list.join("$$$"), "play_url": play_url_list.join("$$$")}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vod_elements = $("a.li-hv")
for (const vod_element of vod_elements) {
let vodShort = new VodShort()
vodShort.vod_id = "/" + vod_element.attribs["href"]
vodShort.vod_name = vod_element.attribs["title"]
vodShort.vod_pic = $(vod_element).find("img")[0].attribs["data-original"]
let remarkEle = $(vod_element).find("p.bz")[0]
if (remarkEle.length > 0) {
vodShort.vod_remarks = remarkEle.children[0].data
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let infoElement = $("[class=info]")
let dtElement = $(infoElement).find("dt.name")[0]
vodDetail.vod_name = dtElement.children[0].data
vodDetail.vod_remarks = dtElement.children[1].children[0].data
let ddString = $(infoElement).find("dd").text()
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?) /, ddString)
vodDetail.vod_year = Utils.getStrByRegex(/年代:(.*?)\n/, ddString)
vodDetail.type_name = Utils.getStrByRegex(/类型:(.*?)\n/, ddString)
vodDetail.vod_content = $(infoElement).find("[class=des2]").text().replaceAll("\n", "").replaceAll("剧情:", "")
vodDetail.vod_pic = $("img.lazy")[0].attribs["data-original"]
return vodDetail
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const vod_object of obj) {
let vodShort = new VodShort()
vodShort.vod_id = vod_object["url"]
vodShort.vod_pic = vod_object["thumb"]
vodShort.vod_remarks = vod_object["time"]
vodShort.vod_name = vod_object["title"]
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let elements = $("[class=index-list-l]")
for (const element of elements) {
let typeElement = $($(element).find("[class=\"h1 clearfix\"]")[0]).find("a")
let type_id = typeElement[0].attribs["href"]
let type_name = $(typeElement[1]).text()
if (!_.isEmpty(type_name)) {
this.classes.push({"type_id": type_id, "type_name": type_name})
}
}
}
}
async getFilter(type_id) {
let url = this.siteUrl + type_id
let html = await this.fetch(url, null, this.getHeader())
let extend_list = []
if (!_.isEmpty(html)) {
let $ = load(html)
let elements = $("[class=\"sy scon clearfix\"]").find("dl")
let i = 0
for (const element of elements) {
let type_name = $($(element).find("dt")).text().replace("按", "").replace("", "")
let extend_dic = {
"key": (i + 1).toString(), "name": type_name, "value": []
}
let type_elements = $(element).find("a")
let index = 0
if (type_name === "剧情") {
index = 3
} else if (type_name === "年代") {
index = 2
} else if (type_name === "地区") {
index = 4
}
for (const type_element of type_elements) {
let type_id_list = type_element.attribs["href"].split("/")
extend_dic["value"].push({"n": $(type_element).text(), "v": type_id_list[index]})
}
extend_list.push(extend_dic)
i = i + 1
}
}
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (type_id !== "最近更新") {
this.filterObj[type_id] = await this.getFilter(type_id)
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let class_name = tid.split("/")[1]
let id = tid.split("/")[2]
let api_str = Utils.getStrByRegex(/var _yu_gda_s="(.*?)";/, html)
let params = {
"action": class_name,
"page": parseInt(pg),
"year": extend["2"] ?? "0",
"area": extend["3"] ?? "all",
"class": extend["1"] ?? "0",
"dect": "",
"id": id
}
let cate_html = await this.fetch(api_str, params, this.getHeader())
if (cate_html !== null) {
let $ = load(cate_html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id
let html = await this.fetch(detailUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
let mather = /<script type="text\/javascript" src="http:\/\/test.gqyy8.com:8077\/ne2(.*?)"><\/script>/g.exec(html)
let js_url = "http://test.gqyy8.com:8077/ne2" + mather[1]
let js_str = await this.fetch(js_url, null, this.getHeader())
if (!_.isEmpty(js_str)) {
let playObject = this.paraseUrlObject(js_str)
this.vodDetail.vod_play_url = playObject["play_url"]
this.vodDetail.vod_play_from = playObject["play_format"]
}
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search.php"
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let params = {
"top": 10, "q": wd,
}
let api_url = Utils.getStrByRegex(/var my_search='(.*?)';/, html)
let content = await this.fetch(api_url, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content.replaceAll("",""))
this.vodList = await this.parseVodShortListFromJson(content_json)
}
}
}
}
let spider = new Kankan70Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

444
JN/CATJS/js/kuaikan.js Normal file
View File

@ -0,0 +1,444 @@
/*
* @File : kuaikan.js
* @Author : jade
* @Date : 2024/3/19 11:12
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {jinja2, _, dayjs, Crypto} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
const charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
function randStr(len, withNum) {
let _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (let i = 0; i < len; i++) {
let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11);
_str += charStr[idx];
}
return _str;
}
function randDevice() {
return {
brand: 'Huawei',
model: 'HUAWEI Mate 20',
release: '10',
buildId: randStr(3, false).toUpperCase() + _.random(11, 99) + randStr(1, false).toUpperCase(),
};
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
function jsonParse(input, json) {
try {
let url = json.url ?? '';
if (url.startsWith('//')) {
url = 'https:' + url;
}
if (!url.startsWith('http')) {
return {};
}
let headers = json['headers'] || {};
let ua = (json['user-agent'] || '').trim();
if (ua.length > 0) {
headers['User-Agent'] = ua;
}
let referer = (json['referer'] || '').trim();
if (referer.length > 0) {
headers['Referer'] = referer;
}
_.keys(headers).forEach((hk) => {
if (!headers[hk]) delete headers[hk];
});
return {
header: headers, url: url,
};
} catch (error) {
}
return {};
}
class KuaiKanSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://api1.baibaipei.com:8899';
this.device = {}
this.parse = []
}
getName() {
return "🛥︎┃快看视频┃🛥︎"
}
getAppName() {
return "快看视频"
}
getJSName() {
return "kuaikan"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.setDevice();
}
async request(reqUrl, postData, agentSp, get) {
let ts = dayjs().valueOf().toString();
let rand = randStr(32);
let sign = Crypto.enc.Hex.stringify(Crypto.MD5('H58d2%gLbeingX*%D4Y8!C!!@G_' + ts + '_' + rand))
.toString()
.toLowerCase();
let headers = {
'user-agent': agentSp || this.device.ua,
};
if (reqUrl.includes('baibaipei')) {
headers['device-id'] = this.device.id;
headers['sign'] = sign;
headers['time'] = ts;
headers['md5'] = rand;
headers['version'] = '2.1.5';
headers['system-model'] = this.device.model;
headers['system-brand'] = this.device.brand;
headers['system-version'] = this.device.release;
headers["host"] = "api1.baibaipei.com:8899"
}
if (!get) {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
let res = await req(reqUrl, {
method: get ? 'get' : 'post', headers: headers, data: postData || {}, postType: 'form'
});
await this.jadeLog.debug(`URL:${reqUrl},headers:${JSON.stringify(headers)},data:${[JSON.stringify(postData)]}`)
let content = res.content;
try {
let key = Crypto.enc.Utf8.parse('IjhHsCB2B5^#%0Ag');
let iv = Crypto.enc.Utf8.parse('y8_m.3rauW/>j,}.');
let src = Crypto.enc.Base64.parse(content);
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
await this.jadeLog.debug(`response:${dst}`)
return JSON.parse(dst);
} catch (e) {
return JSON.parse(content)
}
}
async setDevice() {
let deviceKey = 'device';
let deviceInfo = await local.get(this.siteKey, deviceKey);
if (deviceInfo.length > 0) {
try {
this.device = JSON.parse(deviceInfo);
} catch (error) {
}
}
if (_.isEmpty(this.device)) {
this.device = randDevice();
this.device.id = randStr(13).toLowerCase();
this.device.ua = 'okhttp/3.14.9';
await local.set(this.siteKey, deviceKey, JSON.stringify(this.device));
}
}
async setClasses() {
await this.setDevice()
let response = await this.request(this.siteUrl + '/api.php/Index/getTopVideoCategory');
for (const type of response.data) {
let typeName = type["nav_name"];
if (typeName === '推荐') continue;
let typeId = type["nav_type_id"].toString();
this.classes.push({
type_id: typeId, type_name: typeName,
});
}
}
async getFilter(filterData) {
await this.jadeLog.debug(JSON.stringify(filterData))
let filterAll = []
for (let key of Object.keys(filterData)) {
let itemValues = filterData[key];
if (key === 'plot') key = 'class';
let typeExtendName = '';
switch (key) {
case 'class':
typeExtendName = '类型';
break;
case 'area':
typeExtendName = '地区';
break;
case 'lang':
typeExtendName = '语言';
break;
case 'year':
typeExtendName = '年代';
break;
case 'sort':
typeExtendName = '排序';
break;
}
if (typeExtendName.length === 0) continue;
let newTypeExtend = {
key: key, name: typeExtendName,
};
let newTypeExtendKV = [];
for (let j = 0; j < itemValues.length; j++) {
const name = itemValues[j];
let value = key === 'sort' ? j + '' : name === '全部' ? '0' : name;
newTypeExtendKV.push({n: name, v: value});
}
newTypeExtend['init'] = key === 'sort' ? '1' : newTypeExtendKV[0]['v'];
newTypeExtend.value = newTypeExtendKV;
filterAll.push(newTypeExtend);
}
return filterAll
}
async setFilterObj() {
for (const typeDic of this.classes) {
let typeId = typeDic["type_id"]
if (typeId !== "最近更新") {
let filterData = await this.request(this.siteUrl + '/api.php/Video/getFilterType', {type: typeId})
this.filterObj[typeId] = await this.getFilter(filterData["data"])
}
}
}
async parseVodShortListFromJSONByHome(obj) {
let vod_list = []
for (const data of obj["video"]) {
let video_vod_list = await this.parseVodShortListFromJson(data["list"])
vod_list.push(...video_vod_list)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["vod_id"]
vodShort.vod_name = data["vod_name"]
vodShort.vod_pic = data["vod_pic"]
vodShort.vod_remarks = data["vod_remarks"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.load_dic(JSON.stringify(obj))
vodDetail.vod_content = obj["vod_content"].trim()
vodDetail.type_name = obj["vod_class"]
let playlist = {};
for (const item of obj["vod_play"]) {
let from = item["playerForm"];
if (from === 'jp' && this.catOpenStatus) continue;
if (from === 'xg' && this.catOpenStatus) continue;
let urls = [];
for (const u of item.url) {
urls.push(formatPlayUrl(vodDetail.vod_name, u.title) + '$' + u.play_url);
}
if (!playlist.hasOwnProperty(from) && urls.length > 0) {
playlist[from] = urls;
}
}
this.parse = obj.parse || [];
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
let urls = _.values(playlist);
let vod_play_url = [];
for (const urlist of urls) {
vod_play_url.push(urlist.join('#'));
}
vodDetail.vod_play_url = vod_play_url.join('$$$');
return vodDetail
}
async setHomeVod() {
let data = await this.request(this.siteUrl + "/api.php/Index/getHomePage", {"p": "1", "type": "1"})
this.homeVodList = await this.parseVodShortListFromJSONByHome(data.data)
}
async setCategory(tid, pg, filter, extend) {
if (pg === 0) pg = 1;
let reqUrl = this.siteUrl + '/api.php/Video/getFilterVideoList';
let formData = JSON.parse(jinja2(`{
"type": "{{tid}}",
"p": "{{pg}}",
"area": "{{ext.area|default(0)}}",
"year": "{{ext.year|default(0)}}",
"sort": "{{ext.sort|default(0)}}",
"class": "{{ext.class|default(0)}}"}`, {ext: extend, tid: tid, pg: pg}));
console.log(formData);
let data = await this.request(reqUrl, formData);
this.vodList = await this.parseVodShortListFromJson(data["data"]["data"])
}
async setDetail(id) {
let data = await this.request(this.siteUrl + '/api.php/Video/getVideoInfo', {video_id: id})
this.vodDetail = await this.parseVodDetailfromJson(data["data"]["video"])
}
async setPlay(flag, id, flags) {
this.result.jx = 0
try {
if (id.indexOf('youku') >= 0 || id.indexOf('iqiyi') >= 0 || id.indexOf('v.qq.com') >= 0 || id.indexOf('pptv') >= 0 || id.indexOf('le.com') >= 0 || id.indexOf('1905.com') >= 0 || id.indexOf('mgtv') >= 0)
{
if (this.parse.length > 0) {
for (let index = 0; index < this.parse.length; index++) {
try {
const p = this.parse[index];
let res = await req(p + id, {
headers: {'user-agent': 'okhttp/4.1.0'},
});
await this.jadeLog.debug(`解析连接结果为:${JSON.stringify(res)}`)
let result = jsonParse(id, JSON.parse(res.content)["data"]);
if (result.url){
this.playUrl = result.url // 这里可以直接返回弹幕,无法进行快进操作
this.danmuUrl = await this.danmuSpider.getVideoUrl(id,0)
this.result.jx = 1
}
} catch (error) {
}
}
}
} else if (id.indexOf('jqq-') >= 0) {
let jqqHeaders = await this.request(this.siteUrl + '/jqqheader.json', null, null, true);
let ids = id.split('-');
let jxJqq = await req('https://api.juquanquanapp.com/app/drama/detail?dramaId=' + ids[1] + '&episodeSid=' + ids[2] + '&quality=LD', {headers: jqqHeaders});
let jqqInfo = JSON.parse(jxJqq.content);
if (jqqInfo.data["playInfo"]["url"]) {
this.playUrl = jqqInfo.data["playInfo"]["url"]
}
} else if (id.startsWith("ftp")) {
this.playUrl = id
} else {
let res = await this.request(this.siteUrl + '/video.php', {url: id});
let result = jsonParse(id, res.data);
if (result.url) {
if (result.url.indexOf("filename=1.mp4") > -1) {
this.playUrl = result.url
} else {
this.playUrl = await js2Proxy(true, this.siteType, this.siteKey, 'lzm3u8/' + Utils.base64Encode(result.url), {});
}
}
}
} catch (e) {
await this.jadeLog.error(e)
}
}
async setSearch(wd, quick) {
let data = await this.request(this.siteUrl + '/api.php/Search/getSearch', {key: wd, type_id: 0, p: 1})
this.vodList = await this.parseVodShortListFromJson(data["data"]["data"])
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'lzm3u8') {
await this.jadeLog.debug(`使用代理播放,播放连接为:${url}`)
const resp = await req(url, {});
let hls = resp.content;
const jsBase = await js2Proxy(false, this.siteType, this.siteKey, 'lzm3u8/', {});
const baseUrl = url.substr(0, url.lastIndexOf('/') + 1);
await this.jadeLog.debug(hls.length)
hls = hls.replace(/#EXT-X-DISCONTINUITY\r*\n*#EXTINF:6.433333,[\s\S]*?#EXT-X-DISCONTINUITY/, '');
await this.jadeLog.debug(hls.length)
hls = hls.replace(/(#EXT-X-KEY\S+URI=")(\S+)("\S+)/g, function (match, p1, p2, p3) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + up + p3;
});
hls = hls.replace(/(#EXT-X-STREAM-INF:.*\n)(.*)/g, function (match, p1, p2) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + jsBase + Utils.base64Decode(up);
});
hls = hls.replace(/(#EXTINF:.*\n)(.*)/g, function (match, p1, p2) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + up;
});
return JSON.stringify({
code: resp.code, content: hls, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new KuaiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

93
JN/CATJS/js/liangzi.js Normal file
View File

@ -0,0 +1,93 @@
/*
* @File : liangzi.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 量子资源
*/
import {VodSpider} from "./vodSpider.js";
class LiangziSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://cj.lzcaiji.com"
this.remove18 = true
}
getAppName() {
return "量子资源"
}
getName() {
return "🐝┃量子资源┃🐝"
}
getJSName() {
return "liangzi"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new LiangziSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

93
JN/CATJS/js/liangzi18.js Normal file
View File

@ -0,0 +1,93 @@
/*
* @File : liangzi18.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 量子资源18
*/
import {VodSpider} from "./vodSpider.js";
class Liangzi18Spider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://cj.lzcaiji.com"
this.remove18 = false
}
getAppName() {
return "量子资源18+"
}
getName() {
return "🔞┃量子资源18+┃🔞"
}
getJSName() {
return "liangzi18"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new Liangzi18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

260
JN/CATJS/js/liujiushu.js Normal file
View File

@ -0,0 +1,260 @@
/*
* @File : liujiushu.js
* @Author : jade
* @Date : 2024/04/23 10:02
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
import {formatContent} from "../lib/utils.js";
class LiuJiuShuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.diyi69.com"
}
getAppName() {
return "六九书吧"
}
getJSName() {
return "liujiushu"
}
getType() {
return 10
}
getName() {
return "📚︎┃六九书吧┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
let bookShortElements = $(element).find("a")
bookShort.book_remarks = $(bookShortElements[2]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = bookShortElements[0].attribs.href
bookShort.book_pic = $(element).find("img")[0].attribs["src"]
return bookShort
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $($("[class=\"flex\"]")[0]).find("li")
for (const bookElement of bookElements) {
let bookShort = this.parseVodShortFromElement($, bookElement)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let bookElements = $("ul.flex > li")
let books = [];
for (const item of bookElements) {
let bookShort = new BookShort()
bookShort.book_id = $(item).find('a:first')[0].attribs.href;
const img = $(item).find('img:first')[0];
bookShort.book_name = img.attribs.title
bookShort.book_pic = img.attribs["data-original"]
bookShort.book_remarks = $($(item).find('em:first')).text();
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let books = []
let bookElements = $('li.searchresult')
for (const bookElement of bookElements) {
let bookShort = new BookShort()
let bookShortElements = $(bookElement).find("a")
bookShort.book_remarks = $(bookShortElements[2]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = bookShortElements[0].attribs.href
bookShort.book_pic = $(bookShortElements[0]).find("img")[0].attribs["data-original"]
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
bookDetail.book_name = $('[property$=title]')[0].attribs.content
bookDetail.book_year = $('[property$=update_time]')[0].attribs.content
bookDetail.book_director = $('[property$=author]')[0].attribs.content
bookDetail.book_content = $('[property$=description]')[0].attribs.content
bookDetail.book_remarks = $('[property$=category]')[0].attribs.content
bookDetail.book_pic = $('div.novel_info_main>img')[0].attribs.src
bookDetail.book_id = id
const playBook = {};
const sectionsElements = $("[class=\"flex ulcard\"]").find("li")
const urlElements = $("[class=\"section chapter_list\"]")
for (let i = 0; i < sectionsElements.length; i++) {
const sectionElement = sectionsElements[i]
const urlElemnet = urlElements[i]
let vodItems = []
for (const urlEle of $(urlElemnet).find("a")) {
const epName = $(urlEle).text();
const playUrl = epName + "-" + urlEle.attribs.href;
vodItems.push(epName + '$' + playUrl)
}
let name = $($(urlElemnet).find("[class=\"title jcc\"]")).text()
if (_.isEmpty(name)) {
let text = $(sectionElement).text().split("")[0]
playBook[text] = vodItems.join("#")
} else {
name = name.replaceAll("《","").replaceAll("》","").replaceAll(bookDetail.book_name,"")
playBook[name] = vodItems.reverse().join("#")
}
}
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
for (const a of $('div.navigation > nav > a[href!="/"]')) {
let type_id_list = a.attribs.href.split("/").slice(0, 3)
this.classes.push({
type_id: type_id_list.join("/"), type_name: a.children[0].data.trim(), tline: 2,
});
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + `${tid}/${pg}.html`);
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
let id_list = id.split("-")
id = id_list[1]
let content = id_list[0] + "\n\n"
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += Utils.formatContent($("[class=\"content\"]").html().trim().replaceAll("<p>", " ").replaceAll("</p>", "\n"));
id = $("[id=\"next_url\"]")[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content": content}
}
async setSearch(wd, quick) {
let params = {"searchkey": wd, "searchtype": "all", "Submit": ""}
let content = await this.fetch(this.siteUrl + "/search/", params, this.getHeader())
let $ = load(content)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'img') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + url)
let bookDetail = await this.parseVodDetailFromDoc($)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new LiuJiuShuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

328
JN/CATJS/js/lovemovie.js Normal file
View File

@ -0,0 +1,328 @@
/*
* @File : lovemovie.js
* @Author : jade
* @Date : 2024/4/29 09:36
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 爱情电影网
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import {gbk_us} from "../lib/gbk_us.js";
class LoveMovieSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://b.aqdyje.com"
this.removeKey = "骑兵营"
}
getName() {
return "💕┃爱情电影网┃💕"
}
getAppName() {
return "爱情电影网"
}
getJSName() {
return "lovemovie"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
let buffer = await this.fetch(url, null, headers, false, false, 1, proxy)
let html = Utils.decode(buffer, "gb2312")
await this.jadeLog.debug(`html content:${html}`)
if (!_.isEmpty(html)) {
return load(html)
} else {
return load(gbkDecode(buffer))
}
}
async getFilter($, navElements) {
let extend_list = []
let extend_dic = {"key": "class", "name": "类型", "value": [this.getFliterDic("全部", "全部")]}
for (const navElement of $(navElements).find("li")) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
extend_dic["value"].push(this.getFliterDic(type_name, type_id))
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav-item drop-down \"]")
for (const navElement of navElements) {
let elemenet = $(navElement).find("a")[0]
let type_name = $(elemenet).text()
let type_id = elemenet.attribs.href
if (type_name !== this.removeKey) {
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter($, navElement)
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"play-img\"]")
if (vodElements.length === 0) {
vodElements = $("[class=\"show-list list-mode fn-clear\"]").find("li")
}
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = vodElement.attribs.href
if (_.isEmpty(vodShort.vod_id)) {
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
}
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
for (const element of $(vodElement).find("label")) {
let text = $(element).text().trim()
if (!_.isEmpty(text)) {
vodShort.vod_remarks = text
break
}
}
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = $($(vodElement).find("p")[0]).text().replace("\n")
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $("[class=\"show-list\"]").find("li")
let vod_list = []
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_remarks = $($(vodElement).find("[class=\"type fn-left\"]")).text().replace("类型:", "")
if (vodShort.vod_remarks !== "社处片" && vodShort.vod_remarks !== "社保片" && vodShort.vod_remarks !== "撸丝片" && vodShort.vod_remarks !== "撸丝动漫") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let imgElement = $("[class=\"detail-pic fn-left\"]").find("img")[0]
vodDetail.vod_pic = imgElement.attribs.src
vodDetail.vod_name = imgElement.attribs.alt
let vodInfoElement = $("[class=\"info fn-clear\"]")
for (const vodDlElement of $(vodInfoElement).find("dl")) {
let text = $(vodDlElement).text()
if (text.indexOf("主演") > -1) {
vodDetail.vod_actor = text.replaceAll("主演:", "").replaceAll("\n", "")
}
if (text.indexOf("状态") > -1) {
vodDetail.vod_remarks = text.replaceAll("状态:", "").replaceAll("\n", "")
}
if (text.indexOf("类型") > -1) {
vodDetail.type_name = text.replaceAll("类型:", "").replaceAll("\n", "")
}
if (text.indexOf("地区") > -1) {
vodDetail.vod_area = text.replaceAll("地区:", "").replaceAll("\n", "")
}
if (text.indexOf("导演") > -1) {
vodDetail.vod_director = text.replaceAll("导演:", "").replaceAll("\n", "")
}
if (text.indexOf("年份") > -1) {
vodDetail.vod_year = text.replaceAll("年份:", "").replaceAll("\n", "")
}
if (text.indexOf("剧情") > -1) {
vodDetail.vod_content = text.replaceAll("剧情:", "").replaceAll("\n", "")
}
}
let playList = {}
let html = $.html()
let playListElements = $("[class=\"play-list\"]")
let index = 1
for (const playListElement of playListElements) {
let playName = `播放连接-${index}`
let vodItems = []
for (const playUrlElement of $(playListElement).find("a")) {
let playUrlName = playUrlElement.attribs.title
let playUrl = playUrlElement.attribs.href
vodItems.push(playUrlName + "$" + playUrl)
}
playList[playName] = vodItems.join("#")
index = index + 1
}
index = 1
let ciliListElements = $("[class=\"con4\"]")
for (const ciliListElement of ciliListElements) {
let playName = `磁力链接-${index}`
let vodItems = []
let playUrlName = playName
let playUrl = $($(ciliListElement).find("div")).find("a")[0].attribs.href
if (playUrl !== "javascript:void(0);") {
vodItems.push(playUrlName + "$" + playUrl)
playList[playName] = vodItems.join("#")
index = index + 1
}
}
vodDetail.vod_play_url = _.values(playList).join('$$$');
vodDetail.vod_play_from = _.keys(playList).join('$$$');
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
getExtend(extend) {
if (extend["class"] !== undefined) {
if (extend["class"] !== "全部") {
return extend["class"]
}
}
return undefined
}
async setCategory(tid, pg, filter, extend) {
let classes = this.getExtend(extend) ?? tid
let url
if (classes === tid) {
url = this.siteUrl + classes
} else {
if (parseInt(pg) === 1) {
url = this.siteUrl + classes
} else {
url = this.siteUrl + classes + `index${pg}.html`
}
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("磁力") > -1) {
this.playUrl = id
} else {
let idSplitList = id.split("-")
let flag_id = parseInt(idSplitList[1])
let episode = parseInt(idSplitList[2].split(".")[0])
let $ = await this.getHtml(this.siteUrl + id)
let playJsUrl = Utils.getStrByRegex(/<script type="text\/javascript" src="(.*?)">/, $.html())
let playJsContent = await this.fetch(this.siteUrl + playJsUrl, null, this.getHeader())
let playUrlListStr = Utils.getStrByRegex(/var VideoListJson=(.*?),urlinfo=/, playJsContent)
let playDic = eval(playUrlListStr)
this.playUrl = playDic[flag_id][1][episode].split("$")[1]
if (this.playUrl.indexOf("m3u8") === -1) {
let html = await this.fetch(this.playUrl, null, this.getHeader())
this.playUrl = Utils.getStrByRegex(/url: '(.*?)'/, html)
}
}
}
GBKEncode(str) {
var arr_index = 0x8140; //33088;
str += '';
var gbk = [];
var wh = '?'.charCodeAt(0); //gbk中没有的字符的替换符
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) gbk.push(charcode);
else {
var gcode = gbk_us.indexOf(charcode);
if (~gcode) {
gcode += arr_index;
gbk.push(0xFF & (gcode >> 8), 0xFF & gcode);
} else {
gbk.push(wh);
}
}
}
return gbk;
}
encode(str) {
let encodeStr = ""
for (const ch of str) {
let bitArr = this.GBKEncode(ch);
for (let i = 0; i < bitArr.length; i++) {
bitArr[i] = '%' + ('0' + bitArr[i].toString(16)).substr(-2).toUpperCase();
}
encodeStr = encodeStr + bitArr.join('');
}
return encodeStr
}
async setSearch(wd, quick) {
let params = {"searchword": this.encode(wd)}
let buffer = await this.post(this.siteUrl + "/search.asp", params, this.getHeader(), "form", 1)
let $ = load(Utils.decode(buffer, "gb2312"))
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new LoveMovieSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, LoveMovieSpider}

133
JN/CATJS/js/lovemovie18.js Normal file
View File

@ -0,0 +1,133 @@
/*
* @File : lovemovie18.js
* @Author : jade
* @Date : 2024/4/29 09:36
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 爱情电影网
*/
import {LoveMovieSpider} from "./lovemovie.js";
import {VodShort} from "../lib/vod.js";
class LoveMovie18Spider extends LoveMovieSpider {
constructor() {
super();
this.siteUrl = "https://b.aqdyje.com"
this.removeKey = "骑兵营"
}
getName() {
return "🔞┃爱情电影网18+┃🔞"
}
getAppName() {
return "爱情电影网18+"
}
getJSName() {
return "lovemovie18"
}
getType() {
return 3
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $("[class=\"show-list\"]").find("li")
let vod_list = []
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_remarks = $($(vodElement).find("[class=\"type fn-left\"]")).text().replace("类型:", "")
if (vodShort.vod_remarks === "社处片" || vodShort.vod_remarks === "社保片" || vodShort.vod_remarks === "撸丝片" || vodShort.vod_remarks === "撸丝动漫") {
vod_list.push(vodShort)
}
}
return vod_list
}
async getFilter(type_id) {
let $ = await this.getHtml(this.siteUrl + type_id)
let extend_list = []
let extend_dic = {"key": "class", "name": "类型", "value": []}
for (const navElement of $("[class=\"subnav-tv fn-left\"]").find("a")) {
let type_name = $(navElement).text()
let type_id = navElement.attribs.href
extend_dic["value"].push(this.getFliterDic(type_name, type_id))
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav-item drop-down \"]")
this.classes = []
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
if (type_name === this.removeKey) {
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter(type_id)
}
}
}
async setCategory(tid, pg, filter, extend) {
let classes = this.getExtend(extend) ?? tid
let url
if (parseInt(pg) === 1) {
url = this.siteUrl + classes
} else {
url = this.siteUrl + classes + `index${pg}.html`
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
let spider = new LoveMovie18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

181
JN/CATJS/js/mhdq.js Normal file
View File

@ -0,0 +1,181 @@
/*
* @File : mhdq.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 18+韩漫
*/
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class MHDQSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.18hanman.com';
}
getName() {
return "🔞|韩漫18|🔞"
}
getAppName() {
return "韩漫18"
}
getJSName() {
return "mhdq"
}
getType() {
return 20
}
async setClasses() {
this.classes = []
let $ = await this.getHtml(this.siteUrl + "/category/")
for (const a of $('div.classopen ul.duzhe a[href!="/"]')) {
this.classes.push({
type_id: a.attribs.href,
type_name: a.children[0].data.trim()
});
}
}
async parseVodShortListFromDocByCategory($) {
const list = eval($('div[class="row exemptComic-box"]')[0].attribs.list);
let books = [];
for (const book of list) {
let bookShort = this.parseVodShortFromJson(book)
books.push(bookShort)
}
return books
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
const a = $(element).find('a:first')[0];
const img = $(element).find('img:first-child')[0];
bookShort.book_id = a.attribs.href
bookShort.book_name = $($(element).find("a").slice(-1)[0]).html()
bookShort.book_pic = img.attribs.src
bookShort.book_remarks = $($(element).find("span")).text()
return bookShort
}
async parseVodShortListFromDoc($) {
let vodElements = $('ul.catagory-list li')
let books = []
for (const vodElement of vodElements) {
let bookShort = await this.parseVodShortFromElement($, vodElement)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $('ul.u_list')
let books = []
for (const vodElement of vodElements) {
let bookShort = await this.parseVodShortFromElement($, vodElement)
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
bookDetail.book_id = id
bookDetail.book_name = $('div.title:first').text().trim()
bookDetail.pic = $($('div.img:first-child')).find("img")[0].attribs.src
let contentElements = $('div.info ').find("p")
for (const contentElelent of contentElements) {
if ($(contentElelent).text().indexOf("更新至")) {
bookDetail.book_remarks = $(contentElelent).text().replaceAll("更新至:","")
}
if ($(contentElelent).text().indexOf("作者")) {
bookDetail.book_director = $(contentElelent).text().replaceAll("作者:","")
}
}
bookDetail.book_content = $("[class=\"text\"]").text()
let urls = [];
const links = $('ul.list a[href!="/"]');
for (const l of links) {
let name = l.children[0].data;
let link = l.attribs.href;
urls.push(name + '$' + link);
}
bookDetail.volumes = '全卷';
bookDetail.urls = urls.join('#');
return bookDetail
}
async setCategory(tid, pg, filter, extend) {
const $ = await this.getHtml(this.siteUrl + `${tid}/page/${pg}`)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `${id}`)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setPlay(flag, id, flags) {
const $ = await this.getHtml(this.siteUrl + id);
let content = [];
for (const l of $('div.chapterbox img')) {
const img = $(l).attr('src');
content.push(img);
}
this.playUrl = {
"content": content,
}
}
async setSearch(wd, quick) {
const $ = await this.getHtml(this.siteUrl + `/index.php/search?key=${wd}`);
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new MHDQSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

269
JN/CATJS/js/mp4movie.js Normal file
View File

@ -0,0 +1,269 @@
/*
* @File : mp4movie.js
* @Author : jade
* @Date : 2024/2/19 9:41
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class DyttSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.mp4us.com"
this.apiUrl = "https://m.mp4us.com"
this.dyttReconnectTimes = 0
}
getName() {
return "🍚┃Mp4电影┃🍚"
}
getAppName() {
return "Mp4电影"
}
getJSName() {
return "mp4movie"
}
getType() {
return 3
}
// getHeader() {
// return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/","Connection":"keep-alive"};
// }
async getFilter() {
let extend_list = []
let $ = await this.getHtml()
let suoyinElement = $("[class=\"nav navbar-nav\"]").find("li").slice(-1)[0]
let souyinUrl = $(suoyinElement).find("a")[0].attribs.href
let souyin$ = await this.getHtml(this.siteUrl + souyinUrl)
let sortElements = souyin$("[class=\"sort-box\"]").find("[class=\"sort-list\"]").slice(1,-1)
for (const sortElement of sortElements){
let name = $($(sortElement).find("h5")).text().replace("","")
let extend_dic = {"key": name, "name":name, "value": []}
for (const ele of $(sortElement).find("a")) {
extend_dic["value"].push({"n": $(ele).text(), "v": ele.attribs.data.split("-")[1]})
}
extend_list.push(extend_dic)
}
return extend_list
}
// async setFilterObj() {
// for (const type_dic of this.classes) {
// let type_id = type_dic["type_id"]
// if (type_id !== "最近更新") {
// this.filterObj[type_id] = await this.getFilter()
// }
// }
// }
async setClasses() {
let $ = await this.getHtml()
let suoyinElement = $("[class=\"nav navbar-nav\"]").find("li").slice(-1)[0]
let souyinUrl = $(suoyinElement).find("a")[0].attribs.href
let souyin$ = await this.getHtml(this.siteUrl + souyinUrl)
let sortElements = souyin$("[class=\"sort-box\"]").find("[class=\"sort-list\"]")
let classElements = $(sortElements[0]).find("li")
for (const classElement of classElements) {
let type_name = $($(classElement).find("a")).text()
let type_id = $(classElement).find("a")[0].attribs.data.replaceAll("id-", "")
if (type_name !== "全部") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"index_today cclear\"]").find("a")
for (const vodElement of vodElements){
let vodShort = new VodShort();
vodShort.vod_name = vodElement.attribs.title
vodShort.vod_id = vodElement.attribs.href
vodShort.vod_pic = this.detailProxy + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
return vod_list
}
getSearchHeader() {
let headers = this.getHeader()
headers["Cookie"] = "Hm_lvt_d8c8eecfb13fe991855f511a6e30c3d2=1708243467,1708325624,1708326536;Hm_lpvt_d8c8eecfb13fe991855f511a6e30c3d2;1708326536"
return headers
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let html = $.html()
let detailRootElement = $("[class=\"article-header\"]")
let detailElements = $(detailRootElement).find("p")
let content = ""
for (const detailElement of detailElements){
content = content + $(detailElement).text() + "\n"
}
vodDetail.type_name = $($($(detailRootElement).find("[class=\"post-meta\"]")).find("span")[0]).text()
vodDetail.vod_pic = $(detailRootElement).find("img")[0].attribs.src
vodDetail.vod_name = Utils.getStrByRegex(/名称:(.*?)\n/,content)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?)\n/,content)
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?)\n/,content)
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?)\n/,content)
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?)\n/,content)
vodDetail.vod_remarks = Utils.getStrByRegex(/更新:(.*?)\n/,content)
let contentElement = $("[class=\"article-related info\"]").find("p")
vodDetail.vod_content = $(contentElement).text()
let downloadElements = $("[class=\"article-related download_url\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < downloadElements.length; i++) {
let playFormatElement = downloadElements[i]
let format_name = $($(playFormatElement).find("h2")).text().replaceAll(vodDetail.vod_name,"")
vod_play_from_list.push(format_name.replaceAll("下载","播放"))
let vodItems = []
for (const playUrlElement of $(downloadElements[i]).find("a")) {
let episodeName = $(playUrlElement).text().replaceAll("磁力链下载","").replaceAll(".mp4","")
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodShortListFromJson(obj) {
let vod_list = []
let $ = load(obj["ajaxtxt"])
let vodElements = $($("ul")).find("li");
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["data-original"]
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/,$(vodElement).find("img")[0].attribs.alt)
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_remarks = "评分:"+ $($(vodElement).find("[class=\"rate badge\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $($("[id=\"list_all\"]").find("ul")).find("li")
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/,$($($(vodElement).find("[class=\"text_info\"]")).find("a")[0]).text())
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(vodElement).find("[class=\"update_time\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async setHomeVod() {
let $ = await this.getHtml();
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
return this.vodDetail
}
async setCategory(tid, pg, filter, extend) {
// let url = this.apiUrl + `/list-index-id-${tid}`
// let area = extend["地区"] ?? ""
// let year = extend["年代"] ?? ""
// let tag = extend["标签"] ?? ""
// if (parseInt(pg) > 1){
// url = url + `-p-${pg}`
// }
// if (!_.isEmpty(area) && area !== "0"){
// url = url + `-area-${area}`
// }
// if (!_.isEmpty(year) && year !== "0"){
// url = url + `-year-${year}`
// }
// if (!_.isEmpty(tag) && tag !== "0"){
// url = url + `-wd-${tag}`
// }
// let resp = await this.fetch(url + ".html",null,this.getHeader())
// this.vodList = await this.parseVodShortListFromJson(JSON.parse(resp))
let url = this.siteUrl + `/list/${tid}-${pg}.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search/"
let params = {"wd":wd,"p":"1","t":"j/tNgwBS2e8O4x9TuIkYuQ=="}
let html = await this.post(url,params,this.getSearchHeader())
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new DyttSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

429
JN/CATJS/js/mxanime.js Normal file
View File

@ -0,0 +1,429 @@
/*
* @File : mxanime.js
* @Author : jade
* @Date : 2024/3/30 14:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : MX动漫
*/
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_, load} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
class MxAnimeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.mxdm6.com/"
}
getName() {
return "🍒┃MX动漫┃🍒"
}
getAppName() {
return "MX动漫"
}
getJSName() {
return "mxanime"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav-menu-items\"]")[0]).find("[class=\"nav-menu-item \"]")
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = element.attribs.title
let type_id = element.attribs.href
if (type_name !== "萌图") {
this.classes.push(this.getTypeDic(type_name, Utils.getStrByRegex(/type\/(.*?).html/, type_id)))
}
}
}
async getFilter($) {
let elements = $("[class=\"library-box scroll-box\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + `/type/${type_id}.html`)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
parseVodShortFromElement($, vodElement) {
let vodShort = new VodShort()
let element = $($(vodElement).find("[class=\"module-item-titlebox\"]")).find("a")[0]
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $($(vodElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
vodShort.vod_remarks = $($(vodElement).find("[class=\"module-item-text\"]")).text()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"module-list module-lines-list mxone-box\"]").find("[class=\"module-item\"]")
for (const vodElement of vodElements) {
let vodShort = await this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"module-item\"]")
for (const vodElement of vodElements) {
let vodShort = await this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"module-search-item\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
let element = $(vodElement).find("[class=\"video-serial\"]")[0]
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $($(vodElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
let remarkElements = $($(vodElement).find("[class=\"video-info-item video-info-actor\"]").slice(-1)[0]).find("a")
let remark_list = []
for (const remarkElement of remarkElements){
let remark = remarkElement.children[0].data
remark_list.push(remark)
}
vodShort.vod_remarks = remark_list.join("*")
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"video-info\"]")
vodDetail.vod_pic = $("[class=\"module-item-pic\"]").find("img")[0].attribs["data-src"]
vodDetail.vod_name = $($(vodElement).find("[class=\"page-title\"]")).text()
let classElements = $(vodElement).find("[class=\"video-info-items\"]")
for (const classElement of classElements){
let text = $(classElement).text().replaceAll("\n","").replaceAll("\t","").replaceAll(" ","") + "end"
if (text.indexOf("年份") > -1){
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?)end/,text).replaceAll("/","")
}
if(text.indexOf("备注") > -1){
let x = Utils.getStrByRegex(/备注:(.*?)end/,text)
vodDetail.vod_remarks = Utils.getStrByRegex(/备注:\/(.*?)end/,text)
}
if (text.indexOf("标签") > -1){
vodDetail.type_name = Utils.getStrByRegex(/标签:(.*?)end/,text)
}
if (text.indexOf("剧情") > -1){
vodDetail.vod_content = Utils.getStrByRegex(/剧情:(.*?)end/,text)
}
}
let playFormatElemets = $("[class=\"module-tab-item tab-item\"]")
let playUrlElements = $("[class=\"scroll-content\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push(playFormatElement.attribs["data-dropdown-value"])
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtendValue(extent, key) {
if (extent[key] === undefined) {
return ""
} else {
if (extent[key] === "0") {
return ""
} else {
return extent[key]
}
}
}
async setCategory(tid, pg, filter, extend) {
await this.jadeLog.debug(`extend:${JSON.stringify(extend)}`)
let type = this.getExtendValue(extend, "1")
let time = this.getExtendValue(extend, "2")
let word = this.getExtendValue(extend, "3")
let sort = this.getExtendValue(extend, "4")
let urlParams = [tid.toString(), "", sort, type, "", word, "", "", pg.toString(), "", "", time]
let url = this.siteUrl + "/show/" + urlParams.join("-") + ".html"
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + `/search/${wd}-------------.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playerConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/,$.html()))
const m3mu8_url = "https://danmu.yhdmjx.com/m3u8.php?url=" + playerConfig["url"]
const m3u8_res = await (await this.fetch(m3mu8_url,null,this.getHeader()));
const m3u8_result = m3u8_res.match(/"url": getVideoInfo\("(.*?)"\),/)[1];
const bt_token = m3u8_res.match(/<script>var bt_token = "(.*?)"/)[1];
let m3u8_token_key = await (await this.fetch("https://danmu.yhdmjx.com/js/play.js",null,this.getHeader()));
m3u8_token_key = m3u8_token_key.match(/var _token_key=CryptoJS\['enc'\]\['Utf8'\]\[_0x17f1\('67','qETJ'\)\]\((.*?\))/)[1];
m3u8_token_key = this.decrypt_token_key(m3u8_token_key);
this.playUrl = await this.getVideoInfo(m3u8_result, m3u8_token_key, bt_token);
}
decrypt_token_key(toekn_key){
var _0xod4 = 'jsjiami.com.v6',
_0x175e = [_0xod4, 'JMOsw6omwoDCmw==', 'wp3DkSx5Eg==', 'HB7CscOJfS3DuUjDv2bDjsOmwr3Cm8KcwoI=', 'fR/Dqg==', 'ShRGTcKa', 'w5Y8VBs=', 'esKYKQ==', 'FgIdwrPDnMKOw7k=', 'HhXCmA==', 'woNrRsKSwpnDvcKfw4g=', 'ezBn', 'w43DkcK5w4MaJiE=', 'w44Ob8KjwrjCrMKtUA==', 'HwtswqI=', 'YsKnwrRawro=', 'Sm/CpQXCjz4RH8ORSXw=', 'IsO6w64=', 'T8OeAQ==', 'VcK4Hg==', 'csOmfBJ4', 'd8OAcA5L', 'Tn4RL2s=', 'w7goGizCmw==', 'w6XDlcOGwpoY', 'TsK7wpNPwrg=', 'w7J1CzLCnsO+HA==', 'w4XDkcK0w5YXPg==', 'S8KoCcKS', 'PcKWHcK/Eg==', 'Z2oMJ3rCiw==', 'YsKMG8KMwo0=', 'QsOecgRIwp4=', 'dFzDkUUxw48Qw7nCmX3CicODCMKnw74IOg==', 'acO2KU1B', 'wrAnw6DDrg==', 'w5MsScKwwoA=', 'wohZG8KhBg==', 'b8OieSpZ', 'w4ZmEsORw6I=', 'w7jDhxvCh8KY', 'w7wQa8KFwr0=', 'IMObw4E3wqU=', 'JsOjw5Erwrg=', 'w6MwcsKOwqU=', 'b8KIwqF0wrs=', 'XhXDvT52', 'wrDCmirChSE=', 'w5t1wpvDuwE=', 'XA7CtsKeEA==', 'wonCvVthw78=', 'U8KPP8KMwq4=', 'wp7DhCxjGTU=', 'woPDoBdiEQ==', 'HjzCrE/Dvg==', 'SsOQOWHCgg==', 'w6NdwoXCkMOx', 'w6shYWQ/', 'eE/Cgg==', 'XW/Csj7CmDoA', 'w680OynCgcK5BA8=', 'w4PDoMOTwrog', 'w5R7wqbCpMOPwrMxUcOiM8OuMVLCisKKFsOXAcOWY8O6w5hM', 'WwjDoht0', 'PzXCiHHDiA==', 'QMOFaMKcfQ==', 'bz9bVsK+', 'w7Npwp/DsB9ONw==', 'EcOPBQ3Cig==', 'woHDnzk=', 'DsKQLxtd', 'R8OCJmk=', 'wp55O8On', 'bkXCmhTCqg==', 'w7vDgx3Cg8KU', 'w6nDo8KdAn8=', 'O8KwP8KEDw==', 'wqzCtCHCtCg=', 'w5nDgmYhw5c=', 'wp0OZsK+w4A=', 'wrFxe8KFwp/DvcKew4EbN8K7BMORMx3DuxtOVELChsOEIQ==', 'BMKWRDc=', 'IS5dw6nDhQ==', 'w6geeG8t', 'SsK/wohywpc=', 'LBlnw7jDkA==', 'wodiLsOg', 'Ig5Ow7/Dlw==', 'TMOOewRZwoQ=', 'LjnClV7DvA==', 'woZsO8KcPQ==', 'eWvClMKeKQ==', 'wq1KWsKswr8=', 'w4p+AGFa', 'C8O7F8K2CQcKFxxgwo5sfh3DpAFV', 'w6XDqMKoCw==', 'w6Z8wqnCpMOe', 'w6x/CHRhXhV/w7I=', 'wrvClndGw5Y=', 'VsKcwo5RwoA=', 'ZcK2BMKmLQ==', 'BCcPwofDvQ==', 'eGEsF20=', 'eMOcUglq', 'w4U9XEAMw4/Dm3rCuzpxTg/DvyDDvMONH8OTwpTCtsKbw6k=', 'VwXDkTxG', 'CzHCrl3DkQ==', 'w7PDkVovw4o=', 'dsONYDdj', 'w79pwr3Duh4=', 'w55kwoLCpMOR', 'w6gbc8KGwpw=', 'bCnCtMKCCg==', 'Php5w64=', 'w7x8wpfDtiQ=', 'w4TDk2AB', 'w7lowoHDtgQ=', 'DB/CsnjDuQ==', 'woTDl8K3wp4S', 'wr0Ewq7Dq8Oh', 'GmHCpGxN', 'w5/Dm2XDpw==', 'w5bDpsOCwqoA', 'YMKowphwwqc=', 'ahFuVsK9', 'w57DtEsbw7k=', 'w6LDo8Kq', 'UsKzE8KO', 'w6xlBFl9', 'WMOgIXbCiw==', 'DBhjw5fDhQ==', 'w6pUwoHCnsOs', 'ZF7CtsKiHg==', 'wos4w7wCwr0c', 'JlXCjlpyw5pMw6s=', 'TcO1N8K4wqE=', 'SMOzTcKYRw==', 'w4HDosOzwrUc', 'wqxdwqE2wrY=', 'A8OPGQjChw==', 'wpkxasOxBQ==', 'wpIZSA==', 'VsOnEEvChg==', 'bMOSZy93', 'c8OwZsKnRQ==', 'SsK/wpBHwoQ=', 'ccOsHVFf', 'w6ZKYMO8w6rDr8OrCHxdwqtdwrDDksOMccKZwobDpQPDgsOrAMKXF8OMPcOySsKuL8KLwq8vwr/DkjbDqsOCbRrCkcOTTFfDlsKkw7PChCM1wqTDisKawpHDt8KCQRY3w6DDgMKVw6M=', 'w7hYwq3ClsOa', 'Fic5wqLDiw==', 'KcKqHCVV', 'wqvDucKSwrs/', 'YcOfQcKPSQ==', 'wpjClmNRw7U=', 'wpHClSnCizg=', 'w4PDh8Kw', 'JsOYGwnCpw==', 'w5vDksK8w6sl', 'U8ORCHt+Rw==', 'woVxO8OSJQ==', 'b37Chw/Clw==', 'w6ViBXZlQg==', 'UwPCucKQCgU=', 'UMOeZgs=', 'MTLCtW7Dq2o=', 'wqAQwr/DqcOi', 'DiLDtsOOZsKEbsOrGm03EcKEwr/CplQ=', 'dzPDnRhP', 'wplgT8KBwow=', 'XUzCg8KF', 'K8KTCcKrCQ==', 'w6ZKJMOw', 'LxTCmn/DsA==', 'wooObcKBw6g=', 'w5djwofDoTQ=', 'VMOHeAts', 'Kw96w7bDig==', 'wogpw6crwps=', 'PDzDn8OcWQ==', 'wrfCoWxfw4E=', 'wrrDv8KDwoI+', 'w7hnwrjCssOq', 'w4LDrMOwwpMp', 'S2vCvyjCjic=', 'w6DDoT7CtcKNwoo=', 'wp1Lw5zCpj4=', 'RsOEGcKVwps=', 'woxlwo0twoM=', 'MAZYw7TDmg==', 'w7ENEC7CgA==', 'wolVw4jCryEqVMOYdg==', 'wp45w6cCwqY=', 'w6UhVHs1', 'QBZFW8KH', 'Ozhvw7vDkQ==', 'E8O4DAXCnA==', 'AcOXR8OZ', 'w4NhwqbCk8O6', 'f8OyScKpRRJTBQd9w4t3PgzCtRMQwrjDrUZ9Z8Od', 'A8OHw7Inwoc=', 'wqlQE8KHDg==', 'wqYbZMOVMg==', 'w57DuVwAw60=', 'W8OyQMKtVAk=', 'w60PBwXCng==', 'w4h7w70gw55WbHfDuR0VQ8K+asOxwoJn', 'w5rDhMK2w5gX', 'N0HCklc=', 'w58TTsK4wrg=', 'w7dXNMOhw79pwqBMw70=', 'SsKQCcKf', 'KSXCumrDug==', 'woc1w7gUwrEEw7s=', 'wplowqIvwoFGMQ==', 'acO9DcK+', 'UMKBwpJNwp1ZfA==', 'wpV+NsKCLQ==', 'w5PDrMOrwo4iwrcU', 'XHjCoyPCkw==', 'w5kOUsKkwqXCqcKm', 'QMKRAcKDDMK+AA==', 'bMKoNcKgwrc=', 'w6k0HTPClw==', 'wpUYYcOcBA==', 'w6k6BjnCnMK9', 'w5HDnncPw60=', 'jEsjiamLiI.coRVzmBz.v6gWBKxrg=='];
(function (_0x2410c8, _0x4731c1, _0x21bfda) {
var _0x12d6b4 = function (_0x56792e, _0x26ff38, _0x14a967, _0x1f013c, _0x21c988) {
_0x26ff38 = _0x26ff38 >> 0x8,
_0x21c988 = 'po';
var _0x10be12 = 'shift',
_0x47704d = 'push';
if (_0x26ff38 < _0x56792e) {
while (--_0x56792e) {
_0x1f013c = _0x2410c8[_0x10be12]();
if (_0x26ff38 === _0x56792e) {
_0x26ff38 = _0x1f013c;
_0x14a967 = _0x2410c8[_0x21c988 + 'p']();
} else if (_0x26ff38 && _0x14a967['replace'](/[ELIRVzBzgWBKxrg=]/g, '') === _0x26ff38) {
_0x2410c8[_0x47704d](_0x1f013c);
}
}
_0x2410c8[_0x47704d](_0x2410c8[_0x10be12]());
}
return 0xa44cc;
};
return _0x12d6b4(++_0x4731c1, _0x21bfda) >> _0x4731c1 ^ _0x21bfda;
}(_0x175e, 0x15c, 0x15c00));
var _0x17f1 = function (_0x3abb24, _0x9f8a97) {
_0x3abb24 = ~~'0x' ['concat'](_0x3abb24);
var _0x411694 = _0x175e[_0x3abb24];
if (_0x17f1['nIHPps'] === undefined) {
(function () {
var _0x264909 = typeof window !== 'undefined' ? window : typeof process === 'object' && typeof require === 'function' && typeof global === 'object' ? global : this;
var _0x52b78f = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
// _0x264909['atob'] || (_0x264909['atob'] = function (_0x202c2d) {
// var _0x2e97e4 = String(_0x202c2d)['replace'](/=+$/, '');
// for (var _0x488147 = 0x0,
// _0x1702c1, _0x5d977a, _0x1a87f9 = 0x0,
// _0x2378be = ''; _0x5d977a = _0x2e97e4['charAt'](_0x1a87f9++); ~_0x5d977a && (_0x1702c1 = _0x488147 % 0x4 ? _0x1702c1 * 0x40 + _0x5d977a : _0x5d977a, _0x488147++ % 0x4) ? _0x2378be += String['fromCharCode'](0xff & _0x1702c1 >> (-0x2 * _0x488147 & 0x6)) : 0x0) {
// _0x5d977a = _0x52b78f['indexOf'](_0x5d977a);
// }
// return _0x2378be;
// });
}());
var _0x5cedb3 = function (_0x19b8a7, _0x9f8a97) {
var _0x2b0e6a = [],
_0x4f25fe = 0x0,
_0x29acd8,
_0x2643f2 = '',
_0x58e8bd = '';
_0x19b8a7 = atob(_0x19b8a7);
for (var _0x1ac59f = 0x0,
_0x3346bd = _0x19b8a7['length']; _0x1ac59f < _0x3346bd; _0x1ac59f++) {
_0x58e8bd += '%' + ('00' + _0x19b8a7['charCodeAt'](_0x1ac59f)['toString'](0x10))['slice'](-0x2);
}
_0x19b8a7 = decodeURIComponent(_0x58e8bd);
for (var _0xb0c930 = 0x0; _0xb0c930 < 0x100; _0xb0c930++) {
_0x2b0e6a[_0xb0c930] = _0xb0c930;
}
for (_0xb0c930 = 0x0; _0xb0c930 < 0x100; _0xb0c930++) {
_0x4f25fe = (_0x4f25fe + _0x2b0e6a[_0xb0c930] + _0x9f8a97['charCodeAt'](_0xb0c930 % _0x9f8a97['length'])) % 0x100;
_0x29acd8 = _0x2b0e6a[_0xb0c930];
_0x2b0e6a[_0xb0c930] = _0x2b0e6a[_0x4f25fe];
_0x2b0e6a[_0x4f25fe] = _0x29acd8;
}
_0xb0c930 = 0x0;
_0x4f25fe = 0x0;
for (var _0x4f50dd = 0x0; _0x4f50dd < _0x19b8a7['length']; _0x4f50dd++) {
_0xb0c930 = (_0xb0c930 + 0x1) % 0x100;
_0x4f25fe = (_0x4f25fe + _0x2b0e6a[_0xb0c930]) % 0x100;
_0x29acd8 = _0x2b0e6a[_0xb0c930];
_0x2b0e6a[_0xb0c930] = _0x2b0e6a[_0x4f25fe];
_0x2b0e6a[_0x4f25fe] = _0x29acd8;
_0x2643f2 += String['fromCharCode'](_0x19b8a7['charCodeAt'](_0x4f50dd) ^ _0x2b0e6a[(_0x2b0e6a[_0xb0c930] + _0x2b0e6a[_0x4f25fe]) % 0x100]);
}
return _0x2643f2;
};
_0x17f1['RtnfNa'] = _0x5cedb3;
_0x17f1['afYpDj'] = {};
_0x17f1['nIHPps'] = !![];
}
var _0x5dc739 = _0x17f1['afYpDj'][_0x3abb24];
if (_0x5dc739 === undefined) {
if (_0x17f1['OqAPEJ'] === undefined) {
_0x17f1['OqAPEJ'] = !![];
}
_0x411694 = _0x17f1['RtnfNa'](_0x411694, _0x9f8a97);
_0x17f1['afYpDj'][_0x3abb24] = _0x411694;
} else {
_0x411694 = _0x5dc739;
}
return _0x411694;
};
return eval(toekn_key)
}
async getVideoInfo(data,key,iv) {
/*
Crypto v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var Crypto=Crypto||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
(function(){var u=Crypto,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=Crypto,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
(function(){var u=Crypto,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
l)}})();
Crypto.lib.Cipher||function(u){var p=Crypto,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
(function(){for(var u=Crypto,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
iv = Crypto.enc.Utf8.parse(iv);
key = Crypto.enc.Utf8.parse(key);
let result = Crypto.AES.decrypt(data, key,
{
iv : iv,
mode : Crypto.mode.CBC,
})
return Crypto.enc.Utf8.stringify(result).toString();
}
}
let spider = new MxAnimeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

389
JN/CATJS/js/nangua.js Normal file
View File

@ -0,0 +1,389 @@
/*
* @File : nangua.js
* @Author : jade
* @Date : 2024/3/18 10:54
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 南瓜影视
*/
import {Crypto, jinja2, _} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
function stripHtmlTag(src) {
return src
.replace(/<\/?[^>]+(>|$)/g, '')
.replace(/&.{1,5};/g, '')
.replace(/\s{2,}/g, ' ');
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
class NanGuaSpider extends Spider {
constructor() {
super();
this.siteUrl = 'http://ys.changmengyun.com';
}
getName() {
return "🎃┃南瓜影视┃🎃"
}
getAppName() {
return "南瓜影视"
}
getJSName() {
return "nangua"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
getHeader() {
let t = new Date().getTime().toString();
return {
'version_name': '1.0.6',
'version_code': '6',
'package_name': 'com.app.nanguatv',
'sign': Crypto.MD5('c431ea542cee9679#uBFszdEM0oL0JRn@' + t).toString().toLowerCase(),
'imei': 'c431ea542cee9679',
'timeMillis': t,
'User-Agent': 'okhttp/4.6.0'
}
}
async setClasses() {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/home_nav', null, this.getHeader()));
for (const key in data) {
if (data[key].name !== '精选') this.classes.push({
type_id: data[key].id, type_name: data[key].name,
});
}
}
async setFilterObj() {
this.filterObj = {
"2": [{
"key": "class",
"name": "类型",
"value": [{"n": "全部", "v": "类型"}, {"n": "国产剧", "v": "国产剧"}, {"n": "港台剧", "v": "港台剧"}]
}, {
"key": "area", "name": "地区", "value": [{"n": "全部", "v": "地区"}, {"n": "内地", "v": "内地"}, {
"n": "香港地区", "v": "香港地区"
}, {"n": "台湾地区", "v": "台湾地区"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"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": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}], "1": [{
"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": "美国"}, {"n": "欧洲", "v": "欧洲"}, {"n": "韩国", "v": "韩国"}, {
"n": "日本", "v": "日本"
}, {"n": "台湾地区", "v": "台湾地区"}, {"n": "泰国", "v": "泰国"}, {
"n": "台湾地区", "v": "台湾地区"
}, {"n": "印度", "v": "印度"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"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": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}], "4": [{
"key": "class", "name": "类型", "value": [{"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": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"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": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "新上线", "v": "新上线"}]
}, {
"key": "total",
"name": "状态",
"value": [{"n": "全部", "v": "状态"}, {"n": "连载", "v": "连载"}, {"n": "完结", "v": "完结"}]
}], "3": [{
"key": "class",
"name": "类型",
"value": [{"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": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"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": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "新上线", "v": "新上线"}]
}], "46": [{
"key": "class", "name": "类型", "value": [{"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": "其他"
}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"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": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}]
};
}
async parseVodShortListFromJSONByHome(obj) {
let vod_list = []
for (const data of obj["video"]) {
let video_vod_list = await this.parseVodShortListFromJson(data["data"])
vod_list.push(...video_vod_list)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = data["img"]
vodShort.vod_remarks = data["remarks"]
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = data["msg"]
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJsonBySearch(obj) {
let videos = [];
for (const data of obj){
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["video_name"]
vodShort.vod_remarks = data["qingxidu"]
vodShort.vod_pic = Utils.formatUrl(data["img"])
videos.push(vodShort)
}
return videos
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_id = obj["id"]
vodDetail.vod_name = obj["name"]
vodDetail.vod_pic = obj["img"]
vodDetail.type_name = obj["type"]
vodDetail.vod_year = obj["year"]
vodDetail.vod_content = stripHtmlTag(obj["info"])
vodDetail.vod_remarks = '更新至: ' + obj["msg"] + ' / 评分: ' + obj["score"]
let episodes = obj["player_info"];
let playlist = {};
episodes.forEach(function (it) {
let playurls = it["video_info"];
playurls.forEach(function (playurl) {
let source = it.show;
let t = formatPlayUrl(vodDetail.vod_name, playurl.name);
if (t.length === 0) t = playurl.name.trim();
if (!playlist.hasOwnProperty(source)) {
playlist[source] = [];
}
playlist[source].push(t + '$' + playurl.url);
});
});
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
let urls = _.values(playlist);
let vod_play_url = [];
urls.forEach(function (it) {
vod_play_url.push(it.join('#'));
});
vodDetail.vod_play_url = vod_play_url.join('$$$');
return vodDetail
}
async setHomeVod() {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/home_data?app=ylys&devices=android&imei=c431ea542cee9679&deviceModel=Subsystem%20for%20Android(TM)&deviceVersion=33&appVersionName=1.0.9&deviceScreen=427*250&appVersionCode=9&deviceBrand=Windows', null, this.getHeader()));
this.homeVodList = await this.parseVodShortListFromJSONByHome(data)
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0 || typeof (pg) == 'undefined') pg = 1;
let reqUrl = this.siteUrl + '/api.php/provide/vod_list?app=ylys&id=' + tid + '&page=' + pg + '&imei=c431ea542cee9679&';
reqUrl += jinja2('area={{ext.area}}&year={{ext.year}}&type={{ext.class}}&total={{ext.total}}&order={{ext.by}}', {ext: extend});
let data = JSON.parse(await this.fetch(reqUrl, null, this.getHeader())).list;
this.vodList = await this.parseVodShortListFromJson(data)
let pgChk = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/vod_list?app=ylys&id=' + tid + '&page=' + (parseInt(pg) + 1) + '&imei=c431ea542cee9679&', null, this.getHeader())).msg;
this.count = (pgChk === 'ok') ? parseInt(pg) + 1 : parseInt(pg);
this.limit = 20
this.total = this.limit * this.count
}
async setDetail(id) {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/vod_detail?app=ylys&imei=c431ea542cee9679&id=' + id, null, this.getHeader())).data;
this.vodDetail = await this.parseVodDetailfromJson(data)
}
async setSearch(wd, quick, pg) {
let page = parseInt(pg)
const limit = 20
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/search_result_more?app=ylys&video_name=' + wd + `&pageSize=${limit}&tid=0&imei=c431ea542cee9679&page=${pg}`, null, this.getHeader())).data;
this.vodList = await this.parseVodShortListFromJsonBySearch(data)
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
async setPlay(flag, id, flags) {
try {
if (id.indexOf('m3u8') !== -1) {
this.playUrl = id.split('url=')[1]
} else if (id.indexOf(',') !== -1) {
let mjurl = id.split(',')[1]
let jData = JSON.parse(await this.fetch(mjurl, null, this.getHeader()));
this.playUrl = jData["data"]["url"]
} else {
let jData = JSON.parse(await this.fetch(id, null, this.getHeader()));
this.playUrl = jData["data"]["url"]
}
} catch (e) {
await this.jadeLog.error("播放失败")
}
}
}
let spider = new NanGuaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

261
JN/CATJS/js/newvision.js Normal file
View File

@ -0,0 +1,261 @@
/*
* @File : newvision.js
* @Author : jade
* @Date : 2024/2/20 14:14
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 新视觉影院
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {Crypto} from "../lib/cat.js";
class NewVisionSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.6080yy3.com"
}
getAppName() {
return "新视觉影院"
}
getName() {
return "🐼┃新视觉影院┃🐼"
}
getJSName() {
return "newvision"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav-menu-items\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = Utils.getStrByRegex(/\/vodtype\/(.*?).html/, navElement.attribs.href)
let type_name = navElement.attribs.title
if (Utils.isNumeric(type_id)) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
let type_key_list = [3, 1, 11, 2]
for (let i = 0; i < elements.length; i++) {
let name = $($(elements[i]).find("a")[0]).text()
let extend_dic = {"key": name, "name": name, "value": []}
extend_dic["name"] = name
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
let type_id_list = Utils.getStrByRegex(/\/vodshow\/(.*?).html/, ele.attribs.href).split("-")
extend_dic["value"].push({
"n": $(ele).text(), "v": decodeURIComponent(type_id_list[type_key_list[i]])
})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `/vodshow/${type_id}-----------.html`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const result of obj["Data"]["result"]){
let vodShort = new VodShort()
vodShort.vod_id = result["vod_url"].replaceAll(this.siteUrl,"")
vodShort.vod_pic = result["vod_pic"]
vodShort.vod_name = result["vod_name"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let html = $.html()
let vodDetail = new VodDetail()
let vodDetailElement = $("[class=\"box view-heading\"]")
vodDetail.vod_name = $($(vodDetailElement).find("[class=\"page-title\"]")).text()
let typeElements = $($(vodDetailElement).find("[class=\"tag-link\"]").find("a"))
vodDetail.vod_area = $($(vodDetailElement).find("[class=\"tag-link\"]").slice(-1)[0]).text()
let type_list = []
for (const typeElement of typeElements) {
type_list.push($(typeElement).text())
}
vodDetail.type_name = type_list.join("/")
let itemElements = $(vodDetailElement).find("[class=\"video-info-items\"]")
vodDetail.vod_director = $($(itemElements[0]).find("a")).text()
let actor_list = []
for (const actorElement of $(itemElements[1]).find("a")) {
actor_list.push($(actorElement).text())
}
vodDetail.vod_pic = $($(vodDetailElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
vodDetail.vod_actor = actor_list.join("/")
vodDetail.vod_year = $($(itemElements[2]).find("[class=\"video-info-item\"]")).text()
vodDetail.vod_remarks = $($(itemElements[3]).find("[class=\"video-info-item\"]")).text()
vodDetail.vod_content = $($(itemElements[5]).find("[class=\"video-info-item video-info-content vod_content\"]")).text().replaceAll("\n", "\t").replaceAll("\t收起", "")
let playerformatElements = $("[class=\"module-tab-item tab-item\"]")
let playUrlElements = $("[class=\"scroll-content\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playerformatElements.length; i++) {
let playFormatElement = playerformatElements[i]
let format_name = playFormatElement.attribs["data-dropdown-value"]
if (format_name.indexOf("夸克") === -1) {
vod_play_from_list.push(format_name)
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let type_key_list = [3, 11, 1, 2]
if (extend["全部剧情"] !== undefined && extend["全部剧情"] !== "0") {
urlParams[type_key_list[0]] = extend["全部剧情"]
}
if (extend["全部时间"] !== undefined && extend["全部时间"] !== "0") {
urlParams[type_key_list[1]] = extend["全部时间"]
}
if (extend["全部地区"] !== undefined && extend["全部地区"] !== "0") {
urlParams[type_key_list[2]] = extend["全部地区"]
}
if (extend["时间排序"] !== undefined && extend["时间排序"] !== "0") {
urlParams[type_key_list[3]] = extend["时间排序"]
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let $ = await this.getHtml(reqUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
uic(url,uid){
let ut = Crypto.enc.Utf8.parse('2890'+uid+'tB959C')
let mm = Crypto.enc.Utf8.parse("2F131BE91247866E")
let decrypted = Crypto.AES.decrypt(url, ut, {iv: mm, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7});
return Crypto.enc.Utf8.stringify(decrypted);
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playUrl = $("[id=\"bfurl\"]")[0].attribs.href
if (playUrl.indexOf("http") > -1){
this.playUrl = playUrl
}else{
//需要解析URL,支持弹幕
let newUrl = "https://jiexi.xn--1lq90i13mxk5bolhm8k.xn--fiqs8s/player/ec.php?code=ak&if=1&url=" + playUrl
let play$ = await this.getHtml(newUrl)
let playHtml = play$.html()
let playConfig = JSON.parse(Utils.getStrByRegex(/let ConFig = (.*?),box = /,playHtml))
this.playUrl = this.uic(playConfig["url"],playConfig["config"]["uid"])
}
}
async setSearch(wd, quick) {
let url = `http://123.207.150.253/zxapi/public/?service=App.F.Fetch&req_p=${wd}&type=6080`
let content = await this.fetch(url,null,this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
}
let spider = new NewVisionSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

243
JN/CATJS/js/nivod.js Normal file
View File

@ -0,0 +1,243 @@
/*
* @File : nivod.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {getHeader, createSign, desDecrypt, ChannelResponse, getVod} from "../lib/nivid_object.js"
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class NivodSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.nivodz.com"
}
getName() {
return "👑‍┃泥视频┃墙👑"
}
getAppName() {
return "泥视频"
}
getJSName() {
return "nivod"
}
getType() {
return 3
}
async setClasses() {
this.Remove18ChannelCode = parseInt(this.cfgObj["code"])
let url = this.siteUrl + "/show/channel/list/WEB/3.2" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let channelResponse = new ChannelResponse()
channelResponse.fromJsonString(content, this.Remove18ChannelCode)
let filterUrl = this.siteUrl + "/show/filter/condition/WEB/3.2" + await createSign()
let filterContent = desDecrypt(await this.post(filterUrl, null, getHeader()))
if (filterContent !== null) {
channelResponse.setChannelFilters(filterContent)
this.classes = channelResponse.getClassList()
this.filterObj = channelResponse.getFilters()
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const cate_dic of obj) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodDetailfromJson(vod_dic) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_dic["showIdCode"]
vodDetail.vod_name = vod_dic["showTitle"]
vodDetail.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
vodDetail.vod_pic = vod_dic["showImg"]
vodDetail.vod_director = vod_dic["director"]
vodDetail.vod_actor = vod_dic["actors"]
vodDetail.vod_year = vod_dic["postYear"]
vodDetail.vod_content = vod_dic["showDesc"]
vodDetail.type_name = vod_dic["showTypeName"]
vodDetail.vod_area = vod_dic["regionName"]
return vodDetail
}
getVodRemarks(hot, playResolutions) {
let vod_remarks
if (this.catOpenStatus) {
vod_remarks = `清晰度:${playResolutions[0]}`
} else {
vod_remarks = `清晰度:${playResolutions[0]},热度:${(Math.floor(parseInt(hot) / 1000)).toString()}k`
}
return vod_remarks
}
getExtendDic(extend, params) {
if (extend["5"] === undefined) {
delete params.year_range
} else {
if (extend["5"] === "0") {
delete params.year_range
} else {
params.year_range = extend["5"]
}
}
if (extend["1"] !== undefined) {
params.sort_by = extend["1"]
}
if (extend["2"] !== undefined) {
params.show_type_id = extend["2"]
}
if (extend["3"] !== undefined) {
params.region_id = extend["3"]
}
if (extend["4"] !== undefined) {
params.lang_id = extend["4"]
}
return params
}
async setHomeVod() {
let url = this.siteUrl + "/index/mobile/WAP/3.0" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let content_json = JSON.parse(content)
let cate_list = content_json.list
for (const cate_dic of cate_list) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
this.homeVodList.push(vodShort)
}
}
}
}
}
async setCategory(tid, pg, filter, extend) {
let params = {
"sort_by": "0",
"channel_id": tid.toString(),
"show_type_id": "0",
"region_id": "0",
"lang_id": "0",
"year_range": "2023",
"start": ((parseInt(pg) - 1) * 20).toString()
}
this.limit = 20;
params = this.getExtendDic(extend, params)
let url = this.siteUrl + "/show/filter/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod_dic["showIdCode"]
vodShort.vod_name = vod_dic["showTitle"]
vodShort.vod_pic = vod_dic["showImg"]
vodShort.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
this.vodList.push(vodShort)
}
}
}
async setDetail(id) {
let params = {
"show_id_code": id.toString()
}
let url = this.siteUrl + "/show/detail/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
let vod_dic = content_json["entity"]
this.vodDetail = await this.parseVodDetailfromJson(vod_dic)
let niBaVodDetail = getVod(vod_dic["plays"], ["原画"], id.toString())
this.vodDetail.vod_play_from = niBaVodDetail.vod_play_from
this.vodDetail.vod_play_url = niBaVodDetail.vod_play_url
}
}
async setSearch(wd, quick) {
let params = {"cat_id": "1", "keyword": wd, "keyword_type": "0", "start": "0"}
let url = this.siteUrl + "/show/search/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vod_detail = await this.parseVodDetailfromJson(vod_dic)
this.vodList.push(vod_detail)
}
}
}
async setPlay(flag, id, flags) {
let playId = id.split("@")[0]
let showId = id.split("@")[1]
let params = {
"show_id_code": showId,
"play_id_code": playId
}
let url = this.siteUrl + "/show/play/info/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params,getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
this.playUrl = content_json["entity"]["playUrl"]
}
}
}
let spider = new NivodSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

242
JN/CATJS/js/nivod_18.js Normal file
View File

@ -0,0 +1,242 @@
/*
* @File : nivod18.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {getHeader, createSign, desDecrypt, ChannelResponse, getVod} from "../lib/nivid_object.js"
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class Nivod18Spider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.nivodz.com"
}
getName() {
return "🔞┃泥视频18+┃🔞"
}
getAppName() {
return "泥视频18+"
}
getJSName() {
return "nivod_18"
}
getType() {
return 3
}
async setClasses() {
let url = this.siteUrl + "/show/channel/list/WEB/3.2" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let channelResponse = new ChannelResponse()
channelResponse.fromJsonString(content, 2)
let filterUrl = this.siteUrl + "/show/filter/condition/WEB/3.2" + await createSign()
let filterContent = desDecrypt(await this.post(filterUrl, null, getHeader()))
if (filterContent !== null) {
channelResponse.setChannelFilters(filterContent)
this.classes = channelResponse.getClassList()
this.filterObj = channelResponse.getFilters()
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const cate_dic of obj) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodDetailfromJson(vod_dic) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_dic["showIdCode"]
vodDetail.vod_name = vod_dic["showTitle"]
vodDetail.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
vodDetail.vod_pic = vod_dic["showImg"]
vodDetail.vod_director = vod_dic["director"]
vodDetail.vod_actor = vod_dic["actors"]
vodDetail.vod_year = vod_dic["postYear"]
vodDetail.vod_content = vod_dic["showDesc"]
vodDetail.type_name = vod_dic["showTypeName"]
vodDetail.vod_area = vod_dic["regionName"]
return vodDetail
}
getVodRemarks(hot, playResolutions) {
let vod_remarks
if (this.catOpenStatus) {
vod_remarks = `清晰度:${playResolutions[0]}`
} else {
vod_remarks = `清晰度:${playResolutions[0]},热度:${(Math.floor(parseInt(hot) / 1000)).toString()}k`
}
return vod_remarks
}
getExtendDic(extend, params) {
if (extend["5"] === undefined) {
delete params.year_range
} else {
if (extend["5"] === "0") {
delete params.year_range
} else {
params.year_range = extend["5"]
}
}
if (extend["1"] !== undefined) {
params.sort_by = extend["1"]
}
if (extend["2"] !== undefined) {
params.show_type_id = extend["2"]
}
if (extend["3"] !== undefined) {
params.region_id = extend["3"]
}
if (extend["4"] !== undefined) {
params.lang_id = extend["4"]
}
return params
}
async setHomeVod() {
let url = this.siteUrl + "/index/mobile/WAP/3.0" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let content_json = JSON.parse(content)
let cate_list = content_json.list
for (const cate_dic of cate_list) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
this.homeVodList.push(vodShort)
}
}
}
}
}
async setCategory(tid, pg, filter, extend) {
let params = {
"sort_by": "0",
"channel_id": tid.toString(),
"show_type_id": "0",
"region_id": "0",
"lang_id": "0",
"year_range": "2023",
"start": ((parseInt(pg) - 1) * 20).toString()
}
this.limit = 20;
params = this.getExtendDic(extend, params)
let url = this.siteUrl + "/show/filter/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod_dic["showIdCode"]
vodShort.vod_name = vod_dic["showTitle"]
vodShort.vod_pic = vod_dic["showImg"]
vodShort.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
this.vodList.push(vodShort)
}
}
}
async setDetail(id) {
let params = {
"show_id_code": id.toString()
}
let url = this.siteUrl + "/show/detail/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
let vod_dic = content_json["entity"]
this.vodDetail = await this.parseVodDetailfromJson(vod_dic)
let niBaVodDetail = getVod(vod_dic["plays"], ["原画"], id.toString())
this.vodDetail.vod_play_from = niBaVodDetail.vod_play_from
this.vodDetail.vod_play_url = niBaVodDetail.vod_play_url
}
}
async setSearch(wd, quick) {
let params = {"cat_id": "1", "keyword": wd, "keyword_type": "0", "start": "0"}
let url = this.siteUrl + "/show/search/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vod_detail = await this.parseVodDetailfromJson(vod_dic)
this.vodList.push(vod_detail)
}
}
}
async setPlay(flag, id, flags) {
let playId = id.split("@")[0]
let showId = id.split("@")[1]
let params = {
"show_id_code": showId,
"play_id_code": playId
}
let url = this.siteUrl + "/show/play/info/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params,getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
this.playUrl = content_json["entity"]["playUrl"]
}
}
}
let spider = new Nivod18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

149
JN/CATJS/js/pan_search.js Normal file
View File

@ -0,0 +1,149 @@
/*
* @File : pan_search.js
* @Author : jade
* @Date : 2023/12/25 17:18
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 阿里盘搜仅支持搜搜
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import { detailContent,initCloud,playContent,getHeaders } from "../lib/cloud.js";
class PanSearchSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.pansearch.me/"
}
getName() {
return "🗂️┃阿里盘搜┃🗂️"
}
getAppName() {
return "阿里盘搜"
}
getJSName() {
return "pan_search"
}
getType() {
return 3
}
getSearchHeader() {
let headers = this.getHeader();
headers["x-nextjs-data"] = "1";
return headers;
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj);
}
async parseVodDetailfromJson(obj) {
let item = JSON.parse(obj)
let vodDetail = new VodDetail();
let splitList = item["content"].split("\n");
vodDetail.vod_name = splitList[0].replaceAll(/<\\?[^>]+>/g, "").replace("名称:", "");
let date = new Date(item["time"])
vodDetail.vod_remarks = date.toLocaleDateString().replace(/\//g, "-") + " " + date.toTimeString().substr(0, 8)
vodDetail.vod_pic = item["image"]
let share_url = ""
for (const content of splitList) {
if (content.indexOf("描述") > -1) {
vodDetail.vod_content = content.replace("描述:", "").replaceAll(/<\\?[^>]+>/g, "")
}
if (content.indexOf("标签:") > -1) {
vodDetail.type_name = content.replace("🏷 标签:", "")
}
if (content.indexOf("链接:") > -1) {
share_url = content.replaceAll(/<\\?[^>]+>/g, "").replace("链接:", "");
}
}
let playVod = await detailContent([share_url])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($, wd) {
let vod_list = []
let buildId = JSON.parse($("script[id=__NEXT_DATA__]")[0].children[0].data)["buildId"]
let url = this.siteUrl + "_next/data/" + buildId + "/search.json?keyword=" + encodeURIComponent(wd) + "&pan=aliyundrive";
let aliContent = await this.fetch(url, null, this.getSearchHeader())
if (!_.isEmpty(aliContent)) {
let items = JSON.parse(aliContent)["pageProps"]["data"]["data"]
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = JSON.stringify(item)
let splitList = item["content"].split("\n");
vodShort.vod_name = splitList[0].replaceAll(/<\\?[^>]+>/g, "").replace("名称:", "");
let date = new Date(item["time"])
vodShort.vod_remarks = date.toLocaleDateString().replace(/\//g, "-") + " " + date.toTimeString().substr(0, 8)
vodShort.vod_pic = item["image"]
vod_list.push(vodShort)
}
return vod_list
} else {
await this.jadeLog.error("搜索页面解析失败", true)
}
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailfromJson(id)
}
async setSearch(wd, quick) {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($, wd)
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
let spider = new PanSearchSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

459
JN/CATJS/js/pipixia.js Normal file
View File

@ -0,0 +1,459 @@
/*
* @File : pipixia.js
* @Author : jade
* @Date : 2024/2/2 13:33
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 完成所有的功能开发(已失效)
*/
import {_, Crypto, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {pipixiaMd5} from "../lib/pipiXiaObject.js"
class PiPiXiaSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://aikun.tv/"
this.pipixiaReconnectTimes = 0
}
getHeader() {
let headers = super.getHeader();
headers["Connection"] = "keep-alive"
headers["Host"] = "pipixia.vip"
return headers
}
getName() {
return `🦐┃皮皮虾影视┃🦐`
}
getAppName() {
return `皮皮虾影视`
}
getJSName() {
return "pipixia"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"wow fadeInUp animated\"]")).find("[class=\"public-list-box public-pic-b\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/v\/(.*?).html/, $(vodElement).find("a")[0].attribs.href)
vodShort.vod_name = $(vodElement).find("a")[0].attribs.title
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + $(vodElement).find("[class=\"lazy gen-movie-img mask-1\"]")[0].attribs["data-original"])
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"row-right hide\"]").find("[class=\"search-box flex rel\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort();
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + Utils.getStrByRegex(/url\((.*?)\);/, $(vodElement).find("[class=\"cover\"]")[0].attribs.style))
vodShort.vod_remarks = $($(vodElement).find("[class=\"public-list-prb hide ft2\"]")).html()
vodShort.vod_name = $($(vodElement).find("[class=\"thumb-txt cor4 hide\"]")).html()
vodShort.vod_id = Utils.getStrByRegex(/v\/(.*?).html/, $(vodElement).find("[class=\"button\"]")[0].attribs.href)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const vod_json of obj["list"]) {
let vodShort = new VodShort();
vodShort.vod_name = vod_json["vod_name"]
vodShort.vod_id = vod_json["vod_id"]
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + vod_json["vod_pic"])
vodShort.vod_remarks = vod_json["vod_remarks"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let detailElement = $("[class=\"vod-detail style-detail rel box cor1\"]")
vodDetail.vod_name = $($(detailElement).find("[class=\"slide-info-title hide\"]")).text()
vodDetail.vod_pic = this.siteUrl + $(detailElement).find("[class=\"detail-pic lazy mask-1\"]")[0].attribs["data-original"]
vodDetail.vod_remarks = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[0]).text()
vodDetail.vod_year = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[1]).text()
vodDetail.vod_area = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[2]).text()
vodDetail.vod_director = $($($(detailElement).find("[class=\"slide-info hide\"]")[1]).find("a")).text()
vodDetail.vod_actor = $($($(detailElement).find("[class=\"slide-info hide\"]")[2]).find("a")).text()
let type_list = []
for (const typeEle of $($(detailElement).find("[class=\"slide-info hide\"]")[3]).find("a")) {
type_list.push($(typeEle).text())
}
vodDetail.type_name = type_list.join("/")
vodDetail.vod_content = $($("[class=\"check text selected cor3\"]")).text()
let playElemet = $("[class=\"anthology wow fadeInUp animated\"]")
let playFormatElemets = $(playElemet).find("[class=\"swiper-slide\"]")
let playUrlElements = $(playElemet).find("[class=\"anthology-list-play size\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push(playFormatElement.children[1].data)
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
try {
let html = await this.fetch(url, null, headers)
if (!_.isEmpty(html) && html.indexOf("江苏反诈公益宣传") === -1) {
return load(html)
} else {
if (this.pipixiaReconnectTimes < this.maxReconnectTimes) {
Utils.sleep(2)
this.pipixiaReconnectTimes = this.pipixiaReconnectTimes + 1
return await this.getHtml(url, headers)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
} catch (e) {
await this.jadeLog.error(`获取html出错,出错原因为${e}`)
}
}
async setClasses() {
let $ = await this.getHtml()
this.classes = [this.getTypeDic("首页", "最近更新")]
let $2 = await this.getHtml(this.siteUrl + "/s/1.html")
let classElemets = $2("[class=\"nav-swiper rel\"]")[0]
for (const classElement of $(classElemets).find("a")) {
let type_id = Utils.getStrByRegex(/\/s\/(.*?).html/, classElement.attribs.href)
let type_name = $(classElement).text()
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
async getFilter($) {
let elements = $("[class=\"nav-swiper rel\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
let name = $($($(element).find("[class=\"filter-text bj cor5\"]")).find("span")).html()
if (name !== "频道") {
let extend_dic = {"key": (i + 1).toString(), "name": name, "value": []}
for (const ele of $(element).find("a")) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (Utils.isNumeric(type_id)) {
let url = this.siteUrl + `/s/${type_id}.html`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl + "/map.html")
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtend(extend, key) {
if (extend[key] !== undefined && extend[key] !== "全部") {
return extend[key]
} else {
return null
}
}
getExtendDic(params, extend) {
let class_value = this.getExtend(extend, "2")
if (class_value !== null) {
params["class"] = class_value
}
let area_value = this.getExtend(extend, "3")
if (area_value !== null) {
params["area"] = area_value
}
let year_value = this.getExtend(extend, "4")
if (year_value !== null) {
params["year"] = year_value
}
let lang_value = this.getExtend(extend, "5")
if (lang_value !== null) {
params["lang"] = lang_value
}
let letter_value = this.getExtend(extend, "6")
if (letter_value !== null) {
params["letter"] = letter_value
}
return params
}
async setCategory(tid, pg, filter, extend) {
if (Utils.isNumeric(tid)) {
let url = this.siteUrl + "/index.php/api/vod"
let time_1 = Math.floor(new Date().getTime() / 1000)
let key_1 = pipixiaMd5(time_1)
let params = {
"type": tid, "page": pg, "time": time_1.toString(), "key": key_1
}
params = this.getExtendDic(params, extend)
let content = await this.post(url, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
if (content_json["code"] === 1) {
this.vodList = await this.parseVodShortListFromJson(content_json)
}
}
}
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `/v/${id}.html`)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async getPlayConfig(element) {
// let playJSUrl = this.siteUrl + element.attribs.src
// let jsContent = await this.fetch(playJSUrl,null,null)
// let playListConfig = JSON.parse(Utils.getStrByRegex(/MacPlayerConfig.player_list=(.*?),MacPlayerConfig/,jsContent))
//
let playListConfig = {
"qq": {
"show": "QQ虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "qiyi": {
"show": "QY虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qiyi&if=1&url="
}, "youku": {
"show": "YK虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=youku&if=1&url="
}, "mgtv": {
"show": "MG虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=mgtv&if=1&url="
}, "NBY": {
"show": "极速线路",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SLNB": {
"show": "三路极速",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "FYNB": {
"show": "APP专享线路",
"des": "",
"ps": "0",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SPA": {
"show": "极速A",
"des": "",
"ps": "0",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SPB": {
"show": "极速B",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "kyB": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "JMZN": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "ZNJSON": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "znkan": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "bilibili": {
"show": "BLBL虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "pptv": {
"show": "PP虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "letv": {
"show": "LE虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "sohu": {
"show": "SH虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "DJMP4": {
"show": "短剧专用",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "CLDJ": {
"show": "短剧①",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "ChenXi": {
"show": "短剧专用2",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "HT-": {
"show": "自营线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "htys": {
"show": "解说线路", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "sgdj": {
"show": "短剧③",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}
}
return playListConfig
}
uic(url, uid) {
let ut = Crypto.enc.Utf8.parse('2890' + uid + 'tB959C');
let mm = Crypto.enc.Utf8.parse("2F131BE91247866E");
let decrypted = Crypto.AES.decrypt(url, ut, {iv: mm, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7});
return Crypto.enc.Utf8.stringify(decrypted);
}
async setVideoProxy(playUrl){
let urls = []
urls.push('proxy');
urls.push(playUrl);
const pUrls = urls
for (let index = 1; index < pUrls.length; index += 2) {
pUrls[index] = js2Proxy(false, this.siteType, this.siteKey, 'hls/' + encodeURIComponent(pUrls[index]), {});
}
pUrls.push('original');
pUrls.push(playUrl);
return pUrls
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playElements = $("[class=\"player-left\"]")
let scriptElements = $(playElements).find("script")
await this.jadeLog.debug($(scriptElements[0]).html())
let playConfig = JSON.parse($(scriptElements[0]).html().replaceAll("var player_aaaa=", ""))
let playListConfig = await this.getPlayConfig(scriptElements[1])
let jiexiUrl = playListConfig[playConfig["from"]]["parse"] + playConfig["url"]
let jiexi$ = await this.getHtml(jiexiUrl, {"User-Agent": Utils.CHROME})
let ConFig = JSON.parse(Utils.getStrByRegex(/let ConFig = (.*?),box = /, jiexi$.html()))
let playUrl = this.uic(ConFig["url"], ConFig.config.uid)
await this.jadeLog.debug(`播放链接为:${playUrl}`)
if (flag.indexOf("极速") > -1) {
this.playUrl = playUrl
} else {
if (this.catOpenStatus) {
this.playUrl = await this.setVideoProxy(playUrl)
} else {
this.playUrl = playUrl
}
}
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + `/vodsearch.html?wd=${decodeURI(wd)}`)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new PiPiXiaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}

115
JN/CATJS/js/push_agent.js Normal file
View File

@ -0,0 +1,115 @@
/*
* @File : push_agent.js
* @Author : jade
* @Date : 2024/3/6 9:30
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import { detailContent,initCloud,playContent,getHeaders} from "../lib/cloud.js";
class PushSpider extends Spider {
constructor() {
super();
}
getName() {
return "┃推送┃"
}
getAppName() {
return "推送"
}
getJSName() {
return "push"
}
getType() {
return 4
}
async init(cfg) {
try {
this.cfgObj = await this.SpiderInit(cfg)
this.catOpenStatus = this.cfgObj.CatOpenStatus
await initCloud(this.cfgObj);
} catch (e) {
await this.jadeLog.error(`初始化失败,失败原因为:${e}`)
}
}
async check(args){
// CatVodOpen目前支持http链接和https链接
await spider.jadeLog.debug(`剪切板输入内容为:${args}`)
if (this.catOpenStatus){
return !!args.startsWith("http");
}else{
// TV目前支持http链接和https链接和Ftp和magnet等格式
return !!(args.startsWith("http") || args.startsWith("ftp") || args.startsWith("magnet"));
}
}
async parseVodDetailfromJson(id) {
let vodDetail = new VodDetail()
vodDetail.vod_pic = Utils.RESOURCEURL + "/resources/push.jpg"
let mather = Utils.patternAli.exec(id)
let quarkMatcher = Utils.patternQuark.exec(id)
if (mather !== null && mather.length > 0) {
let playVod = await detailContent([id])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
} else if (quarkMatcher !== null && quarkMatcher.length > 0){
let playVod = await detailContent([id])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
}else {
vodDetail.vod_play_from = '推送';
vodDetail.vod_play_url = '推送$' + id;
}
return vodDetail
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailfromJson(id)
}
async setPlay(flag, id, flags) {
if (flag === "推送"){
this.playUrl = id
}else{
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
}
let spider = new PushSpider()
async function check(args) {
return await spider.check(args)
}
async function init(cfg) {
await spider.init(cfg)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
export function __jsEvalReturn() {
return {
support: check, init: init, detail: detail, play: play,
};
}
export {spider}

251
JN/CATJS/js/sehuatang.js Normal file
View File

@ -0,0 +1,251 @@
/*
* @File : sehuatang
* @Author : jade
* @Date : 2024/1/24 16:47
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 色花堂BT
*/
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_} from "../lib/cat.js";
class SHTSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.sehuatang.net"
}
getAppName() {
return "色花堂BT"
}
getName() {
return "🔞┃色花堂BT┃🔞"
}
getJSName() {
return "sehuatang"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.jsBaseDetail = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', {});
}
getHeader() {
return {
"User-Agent": "PostmanRuntime/7.36.1",
"Host": "www.sehuatang.net",
"Cookie": "cPNj_2132_saltkey=Q4BKEOEC; cf_clearance=6Gz2tvOXPkkJP2UhLnSsN4s0RrnDUy0jBN0kUvC5FNQ-1706109144-1-AebvwBnAURwWWQhj0QRBrRPku2n8xI73PIeuZVj2ckqY9zjQ7zFzDviX7Gkex1P1bUw9SXHGEYnkBB9nmWe6Nhk=; _safe=vqd37pjm4p5uodq339yzk6b7jdt6oich",
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodShortElements = $("[id=\"portal_block_43_content\"]").find("li")
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
vodShort.vod_remarks = $($(vodShortElement).find("a")[1]).text()
vodShort.vod_id = $(vodShortElement).find("a")[2].attribs["href"]
vodShort.vod_name = $(vodShortElement).find("a")[2].attribs["title"]
vodShort.vod_pic = this.jsBaseDetail + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $($("[class=\"bm_c\"]")[0]).find("tbody")
for (const vodElement of vodElements) {
let user_name = $($($(vodElement).find("cite")).find("a")[0]).text()
if (user_name !== "admin" && user_name !== undefined && !_.isEmpty(user_name)) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
vodShort.vod_remarks = $($(vodElement).find("a")[2]).text()
vodShort.vod_name = $($(vodElement).find("a")[3]).text()
vodShort.vod_pic = this.jsBaseDetail + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodElement = $("[class=\"t_f\"]")[0]
let content = $(vodElement).text().replaceAll("", ":").replaceAll("【", "").replaceAll("】", "")
vodDetail.vod_pic = $(vodElement).find("img")[0].attribs["file"]
vodDetail.vod_name = Utils.getStrByRegex(/影片名称(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_actor = Utils.getStrByRegex(/出演女优(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_remarks = Utils.getStrByRegex(/是否有码(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_play_from = "BT"
vodDetail.vod_play_url = vodDetail.vod_name + "$" + Utils.getStrByRegex(/磁力链接: (.*)复制代码/, content)
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let tagElements = $("[id=\"category_1\"]").find("tr").slice(0, -1)
for (const tagElement of tagElements) {
let classElements = $($(tagElement).find("[class=\"fl_icn_g\"]")).find("a")
for (const classElement of classElements) {
let type_id = classElement.attribs["href"]
let type_name = $(classElement).find("img")[0].attribs["alt"]
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let extend_list = []
let extend_dic1 = {"key": 1, "name": "类型", "value": []}
let typeElements = $("[id=\"thread_types\"]").find("a")
for (const typeElement of typeElements){
let type_name = ""
if (typeElement.children.length > 1){
type_name = typeElement.children[0].data + ":" + $(typeElement.children[1]).text()
}else{
type_name = typeElement.children[0].data
}
extend_dic1["value"].push({"n":type_name,"v":typeElement.attribs["href"]})
}
extend_list.push(extend_dic1)
let extend_dic2 = {"key": 1, "name": "主题", "value": []}
let themeElements = $("[class=\"tf\"]").find("a")
for (const themeElement of themeElements){
let type_name = $(themeElement).text()
if (type_name !== "更多" && type_name !== "显示置顶"){
extend_dic2["value"].push({"n":$(themeElement).text(),"v":themeElement.attribs["href"]})
}
}
extend_list.push(extend_dic2)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes){
let type_name = class_dic["type_name"]
let type_id = class_dic["type_id"]
if (type_name !== "最近更新"){
let $ = await this.getHtml(this.siteUrl + '/' + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (extend["1"]!==undefined && extend[1] ==="javascript:;"){
}else{
tid = extend["1"] ?? tid
}
let cateUrl
let tid_list = tid.split(".")[0].split("-")
if (tid_list.length > 2){
tid_list[2] = pg
cateUrl = this.siteUrl + "/" + tid_list.join("-") + ".html"
}else{
cateUrl = this.siteUrl + "/" + tid + "&page=" + pg
}
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + "/" + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'detail') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + "/" + url)
let vodDetail = await this.parseVodDetailFromDoc($)
await this.jadeLog.debug(`图片地址为:${vodDetail.vod_pic}`)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(vodDetail.vod_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(vodDetail.vod_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new SHTSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

672
JN/CATJS/js/sp360.js Normal file
View File

@ -0,0 +1,672 @@
/*
* @File : sp360.js
* @Author : jade
* @Date : 2024/3/21 11:18
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : SP360(需要用到解析)
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class Sp360Spider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.web.360kan.com"
}
getName() {
return "🥎┃360影视┃🥎"
}
getAppName() {
return "360"
}
getJSName() {
return "sp360"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
async setClasses() {
this.classes = [this.getTypeDic("最近更新", "最近更新"), this.getTypeDic("电影", "1"), this.getTypeDic("剧集", "2"), this.getTypeDic("综艺", "3"), this.getTypeDic("动漫", "4")]
}
async setFilterObj() {
this.filterObj = {
"1": [{
"key": "cat", "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": "其他"
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "更早", "v": "lt_year"
}]
}, {
"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": "其他"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}, {
"n": "最受好评", "v": "rankpoint"
}]
}], "2": [{
"key": "cat", "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": ""
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "更早", "v": "lt_year"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "内地"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "美国", "v": "美国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "新加坡", "v": "新加坡"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}, {
"n": "最受好评", "v": "rankpoint"
}]
}], "3": [{
"key": "cat", "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": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "日本", "v": "日本"
}, {
"n": "欧美", "v": "欧美"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}]
}], "4": [{
"key": "cat", "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": "OVA版", "v": "OVA版"
}, {
"n": "TV版", "v": "TV版"
}, {
"n": "新番动画", "v": "新番动画"
}, {
"n": "完结动画", "v": "完结动画"
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2011", "v": "2011"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "2006", "v": "2006"
}, {
"n": "2005", "v": "2005"
}, {
"n": "2004", "v": "2004"
}, {
"n": "更早", "v": "更早"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "日本", "v": "日本"
}, {
"n": "美国", "v": "美国"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}]
}]
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj["data"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["ent_id"] + "+" + data["cat"]
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["title"]
vodShort.vod_remarks = data["upinfo"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJsonByCategory(obj, tid) {
let vod_list = []
for (const data of obj["data"]["movies"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["id"] + "+" + tid
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["title"]
vodShort.vod_remarks = data["tag"]
if (!_.isEmpty(data["doubanscore"])) {
vodShort.vod_remarks = "豆瓣评分:" + data["doubanscore"]
} else {
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = data["pubdate"]
}
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
let data = obj["data"]
vodDetail.vod_name = data["title"]
vodDetail.vod_pic = data["cdncover"]
vodDetail.vod_remarks = data["pubdate"]
vodDetail.vod_actor = data["actor"].join("*")
vodDetail.vod_director = data["director"].join("*")
vodDetail.type_name = data["moviecategory"].join("*")
vodDetail.vod_year = data["pubdate"]
vodDetail.vod_area = data["area"].join("*")
vodDetail.vod_content = data["description"]
let playlist = {}
for (const playFormat of data["playlink_sites"]) {
let vodItems = []
if (!_.isEmpty(data["allepidetail"])) {
if (data["allepidetail"][playFormat] !== undefined) {
for (const items of data["allepidetail"][playFormat]) {
let episodeUrl = items["url"]
let episodeName = items["playlink_num"]
vodItems.push(episodeName + "$" + episodeUrl);
}
}
} else {
let items = data["playlinksdetail"][playFormat]
let episodeUrl = items["default_url"]
let episodeName = items["quality"]
vodItems.push(episodeName + "$" + episodeUrl);
}
if (vodItems.length > 0){
playlist[playFormat] = vodItems.join("#")
}
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async parseVodShortListFromJsonBySearch(obj) {
let vod_list = []
for (const data of obj["data"]["longData"]["rows"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["en_id"] + "+" + data["cat_id"]
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["titleTxt"]
vodShort.vod_remarks = data["coverInfo"]["txt"]
vod_list.push(vodShort)
}
return vod_list
}
async setHomeVod() {
let response = await this.fetch(this.siteUrl + "/v1/rank?cat=1", null, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(response))
}
async setCategory(tid, pg, filter, extend) {
let rank = extend["by"] ?? "rankhot"
let year = extend["year"] ?? ""
let cat = extend["cat"] ?? ""
let area = extend["area"] ?? ""
let url = this.siteUrl + `/v1/filter/list?catid=${tid}&rank=${rank}&cat=${cat}&year=${year}&area=${area}&act=&size=35&pageno=${pg}&callback=`
let response = await this.fetch(url, null, this.getHeader())
this.vodList = await this.parseVodShortListFromJsonByCategory(JSON.parse(response), tid)
}
async setDetail(id) {
let tid_list = id.split("+")
let url = this.siteUrl + `/v1/detail?cat=${tid_list[1]}&id=${tid_list[0]}`
let response = await this.fetch(url, null, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(response))
}
async setSearch(wd, quick) {
let url = `https://api.so.360kan.com/index?force_v=1&kw=${wd}&from=&pageno=1&v_ap=1&tab=all`
let response = await this.fetch(url, null, this.getHeader())
this.vodList = await this.parseVodShortListFromJsonBySearch(JSON.parse(response))
}
async setPlay(flag, id, flags) {
if (this.danmuStaus && ! this.catOpenStatus) {
this.danmuUrl = await this.danmuSpider.getVideoUrl(id, 0)
}
this.result.parse = 1 //启用自动解析
this.result.jx = 1
this.playUrl = id
}
}
let spider = new Sp360Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

901
JN/CATJS/js/spider.js Normal file
View File

@ -0,0 +1,901 @@
/*
* @File : spider.js
* @Author : jade
* @Date : 2023/12/25 17:19
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {JadeLogging} from "../lib/log.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_, load, Uri} from "../lib/cat.js";
import * as HLS from "../lib/hls.js";
import {hlsCache, tsCache} from "../lib/ffm3u8_open.js";
import {DanmuSpider} from "../lib/danmuSpider.js";
import { initCloud } from "../lib/cloud.js";
class Result {
constructor() {
this.class = []
this.list = []
this.filters = []
this.header = {"User-Agent": Utils.CHROME};
this.format = "";
this.danmaku = "";
this.url = "";
this.subs = [];
this.parse = 0
this.jx = 0;
this.page = 0
this.pagecount = 0
this.limit = 0;
this.total = 0;
this.extra = {}
}
get() {
return new Result()
}
home(classes, list, filters) {
return JSON.stringify({
"class": classes, "list": list, "filters": filters
})
}
homeVod(vod_list) {
return JSON.stringify({"page": this.page, "list": vod_list, "pagecount": this.page, "total": this.page})
}
category(vod_list, page, count, limit, total) {
return JSON.stringify({
page: parseInt(page), pagecount: count, limit: limit, total: total, list: vod_list,
});
}
search(vod_list) {
return JSON.stringify({"list": vod_list,"page":this.page,"pagecount":this.pagecount,"total":this.total})
}
detail(vod_detail) {
return JSON.stringify({"list": [vod_detail]})
}
play(url) {
if (!_.isEmpty(this.danmaku)) {
return JSON.stringify({
"url": url,
"parse": this.parse,
"header": this.header,
"format": this.format,
"subs": this.subs,
"danmaku": this.danmaku,
"extra": this.extra,
"jx": this.jx
})
} else {
return JSON.stringify({
"url": url,
"parse": this.parse,
"header": this.header,
"format": this.format,
"subs": this.subs,
"extra": this.extra,
"jx": this.jx
})
}
}
playTxt(url) {
return url
}
errorCategory(error_message) {
let vodShort = new VodShort()
vodShort.vod_name = "错误:打开无效"
vodShort.vod_id = "error"
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/error.png"
vodShort.vod_remarks = error_message
return JSON.stringify({
page: parseInt(0), pagecount: 0, limit: 0, total: 0, list: [vodShort],
})
}
setClass(classes) {
this.class = classes;
return this;
}
setVod(list) {
if (typeof list === "object" && Array.isArray(list)) {
this.list = list;
} else if (list !== undefined) {
this.list = [list]
}
return this;
}
setFilters(filters) {
this.filters = filters;
return this;
}
setHeader(header) {
this.header = header;
return this;
}
setParse(parse) {
this.parse = parse;
return this;
}
setJx() {
this.jx = 1;
return this;
}
setUrl(url) {
this.url = url;
return this;
}
danmu(danmaku) {
this.danmaku = danmaku;
return this;
}
setFormat(format) {
this.format = format;
return this;
}
setSubs(subs) {
this.subs = subs;
return this;
}
dash() {
this.format = "application/dash+xml";
return this;
}
m3u8() {
this.format = "application/x-mpegURL";
return this;
}
rtsp() {
this.format = "application/x-rtsp";
return this;
}
octet() {
this.format = "application/octet-stream";
return this;
}
setPage(page, count, limit, total) {
this.page = page
this.limit = limit
this.total = total
this.pagecount = count
return this;
}
toString() {
return JSON.stringify(this);
}
}
class Spider {
constructor() {
this.siteKey = ""
this.siteType = 0
this.jadeLog = new JadeLogging(this.getAppName(), "DEBUG")
this.classes = []
this.filterObj = {}
this.result = new Result()
this.catOpenStatus = true
this.danmuStaus = false
this.reconnectTimes = 0
this.maxReconnectTimes = 5
this.siteUrl = ""
this.vodList = []
this.homeVodList = []
this.count = 0
this.limit = 0
this.total = 0
this.page = 0
this.vodDetail = new VodDetail()
this.playUrl = ""
this.header = {}
this.remove18 = false
this.type_id_18 = 0
this.type_name_18 = "伦理片"
this.episodeObj = {}
this.danmuUrl = ""
this.cfgObj = {}
}
async reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer) {
await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
Utils.sleep(2)
if (this.reconnectTimes < this.maxReconnectTimes) {
this.reconnectTimes = this.reconnectTimes + 1
return await this.fetch(reqUrl, params, headers, redirect_url, return_cookie, buffer)
} else {
await this.jadeLog.error("请求失败,重连失败")
return null
}
}
getClassIdList() {
let class_id_list = []
for (const class_dic of this.classes) {
class_id_list.push(class_dic["type_id"])
}
return class_id_list
}
getTypeDic(type_name, type_id) {
return {"type_name": type_name, "type_id": type_id}
}
getFliterDic(type_name, type_id) {
return {"n": type_name, "v": type_id}
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
let html = await this.fetch(url, null, headers, false, false, 0, proxy)
if (!_.isEmpty(html)) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
getClassNameList() {
let class_name_list = []
for (const class_dic of this.classes) {
class_name_list.push(class_dic["type_name"])
}
return class_name_list
}
async postReconnect(reqUrl, params, headers,postType,buffer) {
await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
Utils.sleep(2)
if (this.reconnectTimes < this.maxReconnectTimes) {
this.reconnectTimes = this.reconnectTimes + 1
return await this.post(reqUrl, params, headers,postType,buffer)
} else {
await this.jadeLog.error("请求失败,重连失败")
return null
}
}
getHeader() {
return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/"};
}
async getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response,proxy) {
{
if (response.headers["location"] !== undefined) {
if (redirect_url) {
await this.jadeLog.debug(`返回重定向连接:${response.headers["location"]}`)
return response.headers["location"]
} else {
return this.fetch(response.headers["location"], params, headers, redirect_url, return_cookie, buffer,proxy)
}
} else if (response.content.length > 0) {
this.reconnectTimes = 0
if (return_cookie) {
return {"cookie": response.headers["set-cookie"], "content": response.content}
} else {
return response.content
}
} else if (buffer === 1) {
this.reconnectTimes = 0
return response.content
} else {
await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer,proxy)
}
}
}
async fetch(reqUrl, params, headers, redirect_url = false, return_cookie = false, buffer = 0, proxy = false) {
let data = Utils.objectToStr(params)
let url = reqUrl
if (!_.isEmpty(data)) {
url = reqUrl + "?" + data
}
let uri = new Uri(url);
let response;
if (redirect_url) {
response = await req(uri.toString(), {
method: "get", headers: headers, buffer: buffer, data: null, redirect: 2, proxy: proxy
})
} else {
response = await req(uri.toString(), {method: "get", headers: headers, buffer: buffer, data: null,proxy:proxy,timeout:10000});
}
if (response.code === 200 || response.code === 302 || response.code === 301 || return_cookie) {
return await this.getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response,proxy)
} else {
await this.jadeLog.error(`请求失败,失败原因为:状态码出错,请求url为:${uri},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
}
}
async redirect(response) {
}
async post(reqUrl, params, headers, postType = "form",buffer = 0) {
let uri = new Uri(reqUrl);
let response = await req(uri.toString(), {
method: "post", headers: headers, data: params, postType: postType,buffer: buffer
});
if (response.code === 200 || response.code === undefined || response.code === 302) {
// 重定向
if (response.headers["location"] !== undefined) {
return await this.redirect(response)
} else if (!_.isEmpty(response.content)) {
this.reconnectTimes = 0
return response.content
} else {
return await this.postReconnect(reqUrl, params, headers,postType,buffer)
}
} else {
await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为${JSON.stringify(response)}`)
return await this.postReconnect(reqUrl, params, headers,postType,buffer)
}
}
getName() {
return `🍥┃基础┃🍥`
}
getAppName() {
return `基础`
}
getJSName() {
return "base"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
}
async parseVodShortListFromJson(obj) {
}
parseVodShortFromElement($, element) {
}
async parseVodShortListFromDocByCategory($) {
}
async getFilter($) {
}
async setClasses() {
}
async setFilterObj() {
}
async parseVodShortListFromDocBySearch($) {
return []
}
async parseVodDetailFromDoc($) {
}
async parseVodDetailfromJson(obj) {
}
async parseVodPlayFromUrl(flag, play_url) {
}
async parseVodPlayFromDoc(flag, $) {
}
async SpiderInit(cfg) {
try {
this.siteKey = cfg["skey"]
this.siteType = parseInt(cfg["stype"].toString())
let extObj = null;
if (typeof cfg.ext === "string") {
await this.jadeLog.info(`读取配置文件,ext为:${cfg.ext}`)
extObj = JSON.parse(cfg.ext)
} else if (typeof cfg.ext === "object") {
await this.jadeLog.info(`读取配置文件,所有参数为:${JSON.stringify(cfg)}`)
await this.jadeLog.info(`读取配置文件,ext为:${JSON.stringify(cfg.ext)}`)
extObj = cfg.ext
} else {
await this.jadeLog.error(`不支持的数据类型,数据类型为${typeof cfg.ext}`)
}
let boxType = extObj["box"]
extObj["CatOpenStatus"] = boxType === "CatOpen";
return extObj
} catch (e) {
await this.jadeLog.error("初始化失败,失败原因为:" + e.message)
return {"token": null, "CatOpenStatus": false, "code": 0}
}
}
async initCloud(token) {
await initCloud(token)
}
async spiderInit() {
}
async init(cfg) {
this.danmuSpider = new DanmuSpider()
this.cfgObj = await this.SpiderInit(cfg)
await this.jadeLog.debug(`初始化参数为:${JSON.stringify(cfg)}`)
this.catOpenStatus = this.cfgObj.CatOpenStatus
this.danmuStaus = this.cfgObj["danmu"] ?? this.danmuStaus
try {
if (await this.loadFilterAndClasses()) {
await this.jadeLog.debug(`读取缓存列表和二级菜单成功`)
} else {
await this.jadeLog.warning(`读取缓存列表和二级菜单失败`)
await this.writeFilterAndClasses()
}
} catch (e) {
await local.set(this.siteKey, "classes", JSON.stringify([]));
await local.set(this.siteKey, "filterObj", JSON.stringify({}));
await this.jadeLog.error("读取缓存失败,失败原因为:" + e)
}
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', {});
this.douBanjsBase = await js2Proxy(true, this.siteType, this.siteKey, 'douban/', {});
this.baseProxy = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
this.videoProxy = await js2Proxy(true, this.siteType, this.siteKey, 'm3u8/', {});
this.detailProxy = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', this.getHeader());
}
async loadFilterAndClasses() {
// 强制清空
// await local.set(this.siteKey, "classes", JSON.stringify([]));
// await local.set(this.siteKey, "filterObj", JSON.stringify({}));
this.classes = await this.getClassesCache()
this.filterObj = await this.getFiletObjCache()
if (this.classes.length > 0) {
return true
} else {
await local.set(this.siteKey, "classes", JSON.stringify([]));
await local.set(this.siteKey, "filterObj", JSON.stringify({}));
return false
}
}
async writeFilterAndClasses() {
if (this.catOpenStatus) {
this.classes.push({"type_name": "最近更新", "type_id": "最近更新"})
}
await this.setClasses()
await this.setFilterObj()
await local.set(this.siteKey, "classes", JSON.stringify(this.classes));
await local.set(this.siteKey, "filterObj", JSON.stringify(this.filterObj));
}
async getClassesCache() {
let cacheClasses = await local.get(this.siteKey, "classes")
if (!_.isEmpty(cacheClasses)) {
return JSON.parse(cacheClasses)
} else {
return this.classes
}
}
async getFiletObjCache() {
let cacheFilterObj = await local.get(this.siteKey, "filterObj")
if (!_.isEmpty(cacheFilterObj)) {
return JSON.parse(cacheFilterObj)
} else {
return this.filterObj
}
}
async setHome(filter) {
}
async home(filter) {
this.vodList = []
await this.jadeLog.info("正在解析首页类别", true)
await this.setHome(filter)
await this.jadeLog.debug(`首页类别内容为:${this.result.home(this.classes, [], this.filterObj)}`)
await this.jadeLog.info("首页类别解析完成", true)
return this.result.home(this.classes, [], this.filterObj)
}
async setHomeVod() {
}
async homeVod() {
await this.jadeLog.info("正在解析首页内容", true)
await this.setHomeVod()
await this.jadeLog.debug(`首页内容为:${this.result.homeVod(this.homeVodList)}`)
await this.jadeLog.info("首页内容解析完成", true)
return this.result.homeVod(this.homeVodList)
}
async setCategory(tid, pg, filter, extend) {
}
async category(tid, pg, filter, extend) {
this.page = parseInt(pg)
await this.jadeLog.info(`正在解析分类页面,tid = ${tid},pg = ${pg},filter = ${filter},extend = ${JSON.stringify(extend)}`)
if (tid === "最近更新") {
this.page = 0
return await this.homeVod()
} else {
try {
this.vodList = []
await this.setCategory(tid, pg, filter, extend)
await this.jadeLog.debug(`分类页面内容为:${this.result.category(this.vodList, this.page, this.count, this.limit, this.total)}`)
await this.jadeLog.info("分类页面解析完成", true)
return this.result.category(this.vodList, this.page, this.count, this.limit, this.total)
} catch (e) {
await this.jadeLog.error(`分类页解析失败,失败原因为:${e}`)
}
}
}
async setDetail(id) {
}
setEpisodeCache() {
// 记录每个播放链接的集数
let episodeObj = {
"vodDetail": this.vodDetail.to_dict(),
}
let vod_url_channels_list = this.vodDetail.vod_play_url.split("$$$")
for (const vodItemsStr of vod_url_channels_list) {
let vodItems = vodItemsStr.split("#")
for (const vodItem of vodItems) {
let episodeName = vodItem.split("$")[0].split(" ")[0]
let episodeUrl = vodItem.split("$")[1]
let matchers = episodeName.match(/\d+/g)
if (matchers !== null && matchers.length > 0) {
episodeName = matchers[0]
}
episodeObj[episodeUrl] = {"episodeName": episodeName, "episodeId": episodeName}
}
}
return episodeObj
}
async detail(id) {
this.vodDetail = new VodDetail();
await this.jadeLog.info(`正在获取详情页面,id为:${id}`)
try {
await this.setDetail(id)
await this.jadeLog.debug(`详情页面内容为:${this.result.detail(this.vodDetail)}`)
await this.jadeLog.info("详情页面解析完成", true)
this.vodDetail.vod_id = id
if (this.siteType === 3) {
this.episodeObj = this.setEpisodeCache()
}
return this.result.detail(this.vodDetail)
} catch (e) {
await this.jadeLog.error("详情界面获取失败,失败原因为:" + e)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
}
async setDanmu(id) {
await this.jadeLog.debug(`${JSON.stringify(this.episodeObj)}`)
let episodeId = this.episodeObj[id]
let vodDetail = JSON.parse(this.episodeObj["vodDetail"])
delete vodDetail.vod_content;
delete vodDetail.vod_play_from;
delete vodDetail.vod_play_url;
delete vodDetail.vod_pic;
await this.jadeLog.debug(`正在加载弹幕,视频详情为:${JSON.stringify(vodDetail)},集数:${JSON.stringify(this.episodeObj[id])}`)
//区分电影还是电视剧
return await this.danmuSpider.getDammu(vodDetail, episodeId)
}
async play(flag, id, flags) {
await this.jadeLog.info(`正在解析播放页面,flag:${flag},id:${id},flags:${flags}`, true)
try {
let return_result;
await this.setPlay(flag, id, flags)
if (this.playUrl["content"] !== undefined) {
return_result = this.result.playTxt(this.playUrl)
} else {
if (this.danmuStaus && !this.catOpenStatus) {
if (!_.isEmpty(this.danmuUrl)) {
await this.jadeLog.debug("播放详情页面有弹幕,所以不需要再查找弹幕")
return_result = this.result.danmu(this.danmuUrl).play(this.playUrl)
} else {
let danmuUrl;
try {
danmuUrl = await this.setDanmu(id)
} catch (e) {
await this.jadeLog.error(`弹幕加载失败,失败原因为:${e}`)
}
return_result = this.result.danmu(danmuUrl).play(this.playUrl)
}
} else {
await this.jadeLog.debug("不需要加载弹幕", true)
return_result = this.result.play(this.playUrl)
}
}
await this.jadeLog.info("播放页面解析完成", true)
await this.jadeLog.debug(`播放页面内容为:${return_result}`)
return return_result;
} catch (e) {
await this.jadeLog.error("解析播放页面出错,失败原因为:" + e)
}
}
async setSearch(wd, quick) {
}
async search(wd, quick) {
this.vodList = []
await this.jadeLog.info(`正在解析搜索页面,关键词为 = ${wd},quick = ${quick}`)
await this.setSearch(wd, quick,1)
if (this.vodList.length === 0) {
if (wd.indexOf(" ") > -1) {
await this.jadeLog.debug(`搜索关键词为:${wd},其中有空格,去除空格在搜索一次`)
await this.search(wd.replaceAll(" ", "").replaceAll("", ""), quick)
}
}
await this.jadeLog.debug(`搜索页面内容为:${this.result.search(this.vodList)}`)
await this.jadeLog.info("搜索页面解析完成", true)
return this.result.search(this.vodList)
}
async getImg(url, headers) {
let resp;
let vpn_proxy = headers["Proxy"] // 使用代理不需要加headers
if (_.isEmpty(headers)) {
headers = {Referer: url, 'User-Agent': Utils.CHROME}
}
resp = await req(url, {buffer: 2, headers: headers,proxy:vpn_proxy});
try {
//二进制文件是不能使用Base64编码格式的
Utils.base64Decode(resp.content)
if (vpn_proxy){
await this.jadeLog.error(`使用VPN代理,图片地址为:${url},headers:${JSON.stringify(headers)},代理失败,准备重连,输出内容为:${JSON.stringify(resp)}`)
}else {
await this.jadeLog.error(`使用普通代理,图片地址为:${url},headers:${JSON.stringify(headers)},代理失败,准备重连,输出内容为:${JSON.stringify(resp)}`)
}
if (this.reconnectTimes < this.maxReconnectTimes){
this.reconnectTimes = this.reconnectTimes + 1
return await this.getImg(url,headers)
}else{
return {"code": 500, "headers": headers, "content": "加载失败"}
}
} catch (e) {
await this.jadeLog.debug("图片代理成功", true)
this.reconnectTimes = 0
return resp
}
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
await this.jadeLog.debug(`反向代理参数为:${url}`)
if (what === 'img') {
await this.jadeLog.debug("通过代理获取图片", true)
let resp = await this.getImg(url, headers)
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
} else if (what === "douban") {
let vod_list = await this.doubanSearch(url)
if (vod_list !== null) {
let vod_pic = vod_list[0].vod_pic
let resp;
if (!_.isEmpty(headers)) {
resp = await req(vod_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(vod_pic, {
buffer: 2, headers: {
Referer: vod_pic, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
} else if (what === "m3u8") {
let content;
if (!_.isEmpty(headers)) {
content = await this.fetch(url, null, headers, false, false, 2)
} else {
content = await this.fetch(url, null, {"Referer": url, 'User-Agent': Utils.CHROME}, false, false, 2)
}
await this.jadeLog.debug(`m3u8返回内容为:${Utils.base64Decode(content)}`)
if (!_.isEmpty(content)) {
return JSON.stringify({
code: 200, buffer: 2, content: content, headers: {},
});
} else {
return JSON.stringify({
code: 500, buffer: 2, content: content, headers: {},
})
}
} else if (what === 'hls') {
function hlsHeader(data, hls) {
let hlsHeaders = {};
if (data.headers['content-length']) {
Object.assign(hlsHeaders, data.headers, {'content-length': hls.length.toString()});
} else {
Object.assign(hlsHeaders, data.headers);
}
delete hlsHeaders['transfer-encoding'];
if (hlsHeaders['content-encoding'] == 'gzip') {
delete hlsHeaders['content-encoding'];
}
return hlsHeaders;
}
const hlsData = await hlsCache(url, headers);
if (hlsData.variants) {
// variants -> variants -> .... ignore
const hls = HLS.stringify(hlsData.plist);
return {
code: hlsData.code, content: hls, headers: hlsHeader(hlsData, hls),
};
} else {
const hls = HLS.stringify(hlsData.plist, (segment) => {
return js2Proxy(false, this.siteType, this.siteKey, 'ts/' + encodeURIComponent(hlsData.key + '/' + segment.mediaSequenceNumber.toString()), headers);
});
return {
code: hlsData.code, content: hls, headers: hlsHeader(hlsData, hls),
};
}
} else if (what === 'ts') {
const info = url.split('/');
const hlsKey = info[0];
const segIdx = parseInt(info[1]);
return await tsCache(hlsKey, segIdx, headers);
} else if (what === "detail") {
let $ = await this.getHtml(this.siteUrl + url)
let vodDetail = await this.parseVodDetailFromDoc($)
let resp = await this.getImg(vodDetail.vod_pic, headers)
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
} else {
return JSON.stringify({
code: 500, content: '',
});
}
}
getSearchHeader() {
const UserAgents = ["api-client/1 com.douban.frodo/7.22.0.beta9(231) Android/23 product/Mate 40 vendor/HUAWEI model/Mate 40 brand/HUAWEI rom/android network/wifi platform/AndroidPad", "api-client/1 com.douban.frodo/7.18.0(230) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.1.0(205) Android/29 product/perseus vendor/Xiaomi model/Mi MIX 3 rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
let randomNumber = Math.floor(Math.random() * UserAgents.length); // 生成一个介于0到9之间的随机整数
return {
'User-Agent': UserAgents[randomNumber]
}
}
async parseDoubanVodShortListFromJson(obj) {
let vod_list = []
for (const item of obj) {
let vod_short = new VodShort()
vod_short.vod_id = "msearch:" + item["id"]
if (item["title"] === undefined) {
vod_short.vod_name = item["target"]["title"]
} else {
vod_short.vod_name = item["title"]
}
if (item["pic"] === undefined) {
vod_short.vod_pic = item["target"]["cover_url"]
} else {
vod_short.vod_pic = item["pic"]["normal"]
}
if (item["rating"] === undefined) {
vod_short.vod_remarks = "评分:" + item["target"]["rating"]["value"].toString()
} else {
vod_short.vod_remarks = "评分:" + item["rating"]["value"].toString()
}
vod_list.push(vod_short);
}
return vod_list
}
sign(url, ts, method = 'GET') {
let _api_secret_key = "bf7dddc7c9cfe6f7"
let url_path = "%2F" + url.split("/").slice(3).join("%2F")
let raw_sign = [method.toLocaleUpperCase(), url_path, ts.toString()].join("&")
return CryptoJS.HmacSHA1(raw_sign, _api_secret_key).toString(CryptoJS.enc.Base64)
}
async doubanSearch(wd) {
try {
let _api_url = "https://frodo.douban.com/api/v2"
let _api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
let url = _api_url + "/search/movie"
let date = new Date()
let ts = date.getFullYear().toString() + (date.getMonth() + 1).toString() + date.getDate().toString()
let params = {
'_sig': this.sign(url, ts),
'_ts': ts,
'apiKey': _api_key,
'count': 20,
'os_rom': 'android',
'q': encodeURIComponent(wd),
'start': 0
}
let content = await this.fetch(url, params, this.getSearchHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
await this.jadeLog.debug(`豆瓣搜索结果:${content}`)
return await this.parseDoubanVodShortListFromJson(content_json["items"])
}
return null
} catch (e) {
await this.jadeLog.error("反向代理出错,失败原因为:" + e)
}
}
}
export {Spider, Result}

290
JN/CATJS/js/star.js Normal file
View File

@ -0,0 +1,290 @@
/*
* @File : star.js
* @Author : jade
* @Date : 2024/2/21 10:36
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 星视界 需要翻墙
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
class StarSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.histar.tv"
this.apiUrl = "https://aws.ulivetv.net"
}
getAppName() {
return "星视界"
}
getName() {
return "☄️┃星视界┃墙☄️"
}
getJSName() {
return "star"
}
getType() {
return 3
}
getApiHeader() {
return {'User-Agent': Utils.MOBILEUA, "Content-Type": 'application/json'}
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav_nav__zgz60\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = navElement.attribs.href
let type_name = $(navElement).text()
if (type_id !== "/" && type_name !== "电视直播") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
convertTypeData(typeData, key, name) {
if (!typeData || !typeData[key] || typeData[key].length <= 2) {
return null;
}
let valueList = typeData[key];
if (key === 'time') {
valueList = valueList.sort((a, b) => {
return b - a;
});
valueList.pop();
}
const values = _.map(valueList, (item) => {
let name;
let value;
if (item instanceof Array) {
name = item[0];
value = item[0];
} else {
name = item.toString();
value = item.toString();
}
return {
n: name, v: value,
};
});
values.unshift({
n: '全部', v: '',
});
return {
key: key, name: name, init: '', value: values,
};
}
async getFilter($) {
const json = $('#__NEXT_DATA__')[0].children[0].data;
const obj = JSON.parse(json).props["pageProps"]["filterCondition"];
const label = this.convertTypeData(obj, 'label', '类型');
const country = this.convertTypeData(obj, 'country', '地区');
const time = this.convertTypeData(obj, 'time', '年份');
return [label, country, time];
}
async setFilterObj() {
for (const type_dic of this.classes.slice(0, 4)) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `${type_id}/all/all/all`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
parseVodShortFromtJson(obj) {
let vodShort = new VodShort()
vodShort.vod_id = obj["id"]
vodShort.vod_name = obj["name"]
vodShort.vod_pic = obj["img"]
if (_.isEmpty(vodShort.vod_pic)) {
vodShort.vod_pic = obj["picurl"] ?? ""
}
vodShort.vod_remarks = obj["countStr"]
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = obj["time"]
}
return vodShort
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const results of obj) {
let name = results["name"]
if (name !== "电视直播") {
let cards = results["cards"]
for (const result of cards) {
let vodShort = this.parseVodShortFromtJson(result)
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodShortListFromJsonByCategory(obj) {
let vod_list = []
for (const result of obj.list) {
let vodShort = this.parseVodShortFromtJson(result)
vod_list.push(vodShort)
}
return vod_list
}
getObjectValues(objList,key){
let value_list = []
for (const result of objList){
value_list.push(result[key])
}
return value_list
}
async parseVodDetailfromJson(obj) {
const vObj = obj["collectionInfo"];
let vodDetail = new VodDetail();
vodDetail.vod_name = vObj["name"]
vodDetail.type_name = vObj["chname"]
vodDetail.vod_pic = vObj["picurl"]
vodDetail.vod_area = vObj["country"]
vodDetail.vod_remarks = vObj["countStr"]
vodDetail.vod_actor = this.getObjectValues(vObj["actor"],"name").join("/")
vodDetail.vod_director = this.getObjectValues(vObj["director"],"name").join("/")
vodDetail.vod_content = vObj["desc"]
const playInfo = vObj["videosGroup"];
const playVod = {};
_.each(playInfo, (info) => {
const sourceName = info.name;
let playList = '';
const videoInfo = info["videos"];
const vodItems = _.map(videoInfo, (epObj) => {
const epName = "第" + epObj["eporder"] + "集";
const playUrl = epObj["purl"]
return epName + '$' + playUrl;
});
if (_.isEmpty(vodItems)) return;
playList = vodItems.join('#');
playVod[sourceName] = playList;
});
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setHomeVod() {
let json = await this.fetch(this.apiUrl + "/v3/web/api/home?chName=首页", null, this.getApiHeader())
const obj = JSON.parse(json)["data"]["cardsGroup"];
this.homeVodList = await this.parseVodShortListFromJson(obj)
}
getClassChName(tid) {
for (const class_dic of this.classes) {
if (tid === class_dic["type_id"]) {
return class_dic["type_name"]
}
}
}
async setCategory(tid, pg, filter, extend) {
this.limit = 16;
const param = {
chName: this.getClassChName(tid), page: parseInt(pg), pageSize: this.limit
};
if (extend["label"] !== undefined) {
param["label"] = extend["label"]
}
if (extend["country"] !== undefined) {
param["country"] = extend["country"]
}
if (extend["time"] !== undefined) {
const year = parseInt(extend["time"]);
param["startTime"] = year;
param["endTime"] = year;
}
const json = await this.post(this.apiUrl + '/v3/web/api/filter', JSON.stringify(param), {
'User-Agent': Utils.MOBILEUA, "Content-Type": 'application/json'
}, "")
const data = JSON.parse(json).data;
this.vodList = await this.parseVodShortListFromJsonByCategory(data)
this.count = Math.floor(data["total"] / this.limit);
this.total = data.total
}
async setDetail(id) {
const $ = await this.getHtml(this.siteUrl + '/vod/detail/' + id);
const json = $('#__NEXT_DATA__')[0].children[0].data;
const obj = JSON.parse(json).props["pageProps"];
this.vodDetail = await this.parseVodDetailfromJson(obj)
}
async setSearch(wd, quick) {
const limit = 20;
const param = {
word: wd, page: 1, pageSize: limit,
};
const json = await this.post(this.apiUrl + '/v3/web/api/search', JSON.stringify(param), this.getApiHeader(), "");
const data = JSON.parse(json).data;
this.vodList = await this.parseVodShortListFromJsonByCategory(data)
}
}
let spider = new StarSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

127
JN/CATJS/js/testSpider.js Normal file
View File

@ -0,0 +1,127 @@
import {__jsEvalReturn} from './alipansou.js';
import * as Utils from "../lib/utils.js";
let spider = __jsEvalReturn();
async function testPlay(vodDetail) {
if (vodDetail.list && vodDetail.list.length > 0) {
const pFlag = vodDetail.list[0].vod_play_from.split('$$$');
const pUrls = vodDetail.list[0].vod_play_url.split('$$$');
if (pFlag.length > 0 && pUrls.length > 0) {
for (const i in pFlag) {
// console.debug(i)
let flag = pFlag[i];
let urls = pUrls[i].split('#');
// console.debug(flag, urls)
for (const j in urls) {
var name = urls[j].split('$')[0];
var url = urls[j].split('$')[1];
console.debug(flag + " | " + name + " | " + url);
var playUrl = await spider.play(flag, url, []);
console.debug('playURL: ' + playUrl);
}
}
}
}
}
async function testMusicPlay(vodDetail) {
if (vodDetail.list && vodDetail.list.length > 0) {
const pFlag = vodDetail.list[0].volumes.split('$$$');
const pUrls = vodDetail.list[0].urls.split('$$$');
if (pFlag.length > 0 && pUrls.length > 0) {
for (const i in pFlag) {
// console.debug(i)
let flag = pFlag[i];
let urls = pUrls[i].split('#');
// console.debug(flag, urls)
for (const j in urls) {
var name = urls[j].split('$')[0];
var url = urls[j].split('$')[1];
console.debug(flag + " | " + name + " | " + url);
var playUrl = await spider.play(flag, url, []);
console.debug('playURL: ' + playUrl);
}
break
}
}
}
}
async function test() {
let siteKey = 'alipansou';
let siteType = 3;
await spider.init({
skey: siteKey, stype: siteType, ext: {
"aliToken": "51427b95ab9d47a6921a27951ebd3f1e",
"box": "TV",
"code": "1",
"from": "star",
"danmu": true,
"cookie": "buvid3=02675249-8ED3-C418-87F5-59E18316459714816infoc; b_nut=1704421014; _uuid=5D435F74-F574-D9AB-62C1-B9294DE465D913102infoc; buvid_fp=e8c5650c749398e9b5cad3f3ddb5081e; buvid4=007E85D1-52C1-7E6E-07CF-837FFBC9349516677-024010502-J5vTDSZDCw4fNnXRejbSVg%3D%3D; rpdid=|()kYJmulRu0J'u~|RRJl)JR; PVID=1; SESSDATA=3be091d3%2C1720332009%2C699ed%2A11CjAcCdwXG5kY1umhCOpQHOn_WP7L9xFBfWO7KKd4BPweodpR6VyIfeNyPiRmkr5jCqsSVjg0R0dZOVVHRUo3RnhPRTZFc3JPbGdiUjFCdHpiRDhiTkticmdKTjVyS1VhbDdvNjFMSDJlbUJydUlRdjFUNGFBNkJlV2ZTa0N1Q1BEVi1QYTQzTUh3IIEC; bili_jct=b0ee7b5d3f27df893545d811d95506d4; DedeUserID=78014638; DedeUserID__ckMd5=4c8c5d65065e468a; enable_web_push=DISABLE; header_theme_version=CLOSE; home_feed_column=5; CURRENT_BLACKGAP=0; CURRENT_FNVAL=4048; b_lsid=75E916AA_18EA1A8D995; bsource=search_baidu; FEED_LIVE_VERSION=V_HEADER_LIVE_NO_POP; browser_resolution=1507-691; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTIzNjk5MTMsImlhdCI6MTcxMjExMDY1MywicGx0IjotMX0.8zQW_fNTCSBlK_JkHnzu3gDw62wuTK1qgKcbGec3swM; bili_ticket_expires=171236985",
"quarkCookie":"_UP_A4A_11_=wb965111521e45ffa80410c24a071a54; _UP_D_=pc; tfstk=fXFith4nnRk114LAjWc1TT-OQUXL5hGjqodxDjnVLDoBBchYujR4Drht3GaYxmqYlcPtWc34mknIMcFTB-Y_tuAv6G6_uIcxggIRw_U15jGV2EjCXmnslyoqlSMN9PGjgMEW0dR85uVOAjYmgwcEoqOqgIrqLyoIlq-ZuC738DgqgCJZgH8EuqxZNmAqqSPQTaC3h7bb2rFnSvW87D8jTW0iX0zasIR2zVDi4Poh2svabvzjnSTXixaaFogzbhS-Cry3xVcc9dlz--roR55Jj2wT8znUrEdYrfV3t-kh71znscDo-vYWpf24fSD_IE_78frQF0MNdMg367HmVvxFbyUnbY20XMOqX84UxYFpvQhbA-rqok-G4A9eUc4wG27YtK9jQ2gnVNJioG_mbu_h-wv5CAuIWgQh-K9jQ2gn2wbHFhMZRVIR.; __pus=c81f57897dafcb65d4ecb501bc299199AARcqF72zsatdbsCbiT3qVqsk36caaycoPQW7hz8rbEf+UY7f5aGgH1e90lsONAUwCAW8y27u5A/KXyYqkHCWgjS; __kp=99fa2760-1669-11ef-90cf-8f7a59c3b86e; __kps=AATSt4xuf6r6bqes3LdJvxvy; __ktd=c2e+aLICIvFoeklXXz36VA==; __uid=AATSt4xuf6r6bqes3LdJvxvy; Video-Auth=smob3MOUslklDq2MutANJYZCVo50sLv0GFelx3+cu1nK2fkdL2kvkdpT5yNOhNz0NLTyi5ThWRL47+ztJA4kXQ==; __puus=72f667c533c9a22496f88d2f1bb7ae71AAQ7mrvFw7s9AUPUXvnuGPkcDU3RRTVPdYaYQfsM9Cje2doYXgRZXbImg02EaUaEG+G9ikpo3xubGGdElArOuYvUtJzIXb6yHDnSZbtEUxkwvjfQRNEnDnVwLQ6LL2ORjRaxa9OUfwk/WppWvy6OcDqQtHYkaqB+Poxn5kFs7ZVdAtX7ZQks1czD+g9gAZjsbeBHxHQ1AP5MGc1s3M4RhwZQ"
}
});
let classes = JSON.parse(await spider.home(true));
console.debug(JSON.stringify(classes))
//测试首页列表
let homeVod = JSON.parse(await spider.homeVod())
console.debug(JSON.stringify(homeVod));
// 测试详情
let detail1 = JSON.parse(await spider.detail("/search?k=%e5%ba%86%e4%bd%99%e5%b9%b4%e7%ac%ac%e4%ba%8c%e5%ad%a3"))
await testPlay(detail1)
// 测试搜索
let search_page = JSON.parse(await spider.search("庆余年", false, 1))
console.debug(JSON.stringify(search_page))
// 测试分类
let catePage = JSON.parse(await spider.category("2", "1", undefined, {}));
console.debug(JSON.stringify(catePage))
// 测试详情
if (search_page.list && search_page.list.length > 0) {
for (const k in search_page.list) {
// console.debug(k)
if (k >= 1) break;
let obj = search_page.list[k]
let spVid = search_page.list[k].vod_id
console.debug("===", spVid)
var detail = JSON.parse(await spider.detail(spVid || search_page.list[k].vod_id));
await testPlay(detail);
}
}
}
export {test};

286
JN/CATJS/js/tiantian.js Normal file
View File

@ -0,0 +1,286 @@
/*
* @File : tiantian.js
* @Author : jade
* @Date : 2024/04/15 10:48
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 天天影视
*/
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class TianTianSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://op.ysdqjs.cn"
this.cookie = ""
this.extendObj = {"extend": "类型", "area": "地区", "year": "年代"}
this.parseMap = {};
}
async request(reqUrl, method, data) {
const headers = {
'User-Agent': Utils.CHROME,
};
if (!_.isEmpty(this.cookie)) {
headers['Cookie'] = this.cookie;
}
const postType = method === 'post' ? 'form-data' : '';
let res = await req(reqUrl, {
method: method || 'get', headers: headers, data: data, postType: postType,
});
if (res.code === 403) {
const path = res.data.match(/window\.location\.href ="(.*?)"/)[1];
this.cookie = _.isArray(res.headers['set-cookie']) ? res.headers['set-cookie'].join(';') : res.headers['set-cookie'];
headers['Cookie'] = this.cookie;
res = await req(this.siteUrl + path, {
method: method || 'get', headers: headers, data: data, postType: postType,
});
}
return res.content;
}
async postData(url, data) {
const timestamp = Math.floor(new Date().getTime() / 1000);
const key = 'kj5649ertj84ks89r4jh8s45hf84hjfds04k';
const sign = md5X(key + timestamp).toString();
let defaultData = {
sign: sign, timestamp: timestamp,
};
const reqData = data ? _.merge(defaultData, data) : defaultData;
return await this.request(url, 'post', reqData);
}
getName() {
return "⛄┃天天影视┃⛄"
}
getAppName() {
return "天天影视"
}
getJSName() {
return "tiantian"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
generateParam(tid, pg, extend, limit) {
const param = {
type_id: tid, page: pg, limit: limit,
};
if (extend["extend"] !== undefined && extend["extend"] !== "全部") {
param.class = extend["extend"];
}
if (extend["area"] !== undefined && extend["area"] !== "全部") {
param.area = extend.area;
}
if (extend["lang"] !== undefined && extend["lang"] !== "全部") {
param.lang = extend.lang;
}
if (extend["year"] !== undefined && extend["year"] !== "全部") {
param.year = extend.year;
}
return param;
}
async getFilter(data) {
let extend_list = []
Object.keys(data).forEach(key => {
if (Array.isArray(data[key])) {
if (!_.isEmpty(this.extendObj[key])) {
let extend_dic = {"key": key, "name": this.extendObj[key], "value": []}
let add_year_status = false
for (const extend_data of data[key]) {
if (key === "year") {
if (!data[key].includes("2024") && extend_data !== "全部" && !add_year_status) {
extend_dic["value"].push({"n": "2024", "v": "2024"})
add_year_status = true
}
}
if (!_.isEmpty(extend_data)) {
extend_dic["value"].push({"n": extend_data, "v": extend_data})
}
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
}
}
})
return extend_list
}
async setClasses() {
let resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/type/top_type'))
for (const data of resJson["data"]["list"]) {
let type_name = data["type_name"]
let type_id = data["type_id"].toString()
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter(data)
}
}
async parseVodShortListFromJson(vodList) {
let vod_list = []
for (const vodData of vodList) {
let vodShort = new VodShort()
vodShort.load_data(vodData)
if (_.isEmpty(vodShort.vod_pic) && vodData["vod_pic_thumb"] !== undefined) {
vodShort.vod_pic = vodData["vod_pic_thumb"]
}
if (vodShort.vod_name !== "首页轮播") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailfromJson(detailObj) {
let vodDetail = new VodDetail()
vodDetail.load_data(detailObj)
vodDetail.vod_content = Utils.formatContent(vodDetail.vod_content)
const playInfo = detailObj["vod_play_list"];
const playVod = {};
_.each(playInfo, (obj) => {
const sourceName = obj.name;
let playList = '';
const videoInfo = obj.urls;
const parse = obj["parse_urls"];
if (!_.isEmpty(parse)) this.parseMap[sourceName] = parse;
const vodItems = _.map(videoInfo, (epObj) => {
const epName = epObj.name;
const playUrl = epObj.url;
return epName + '$' + playUrl;
});
if (_.isEmpty(vodItems)) return;
playList = vodItems.join('#');
playVod[sourceName] = playList;
});
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setHomeVod() {
let resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/type/tj_vod'))
let vod_list = []
for (const data of resJson["data"]["type_vod"]) {
if (data["type_name"] !== "广告") {
vod_list = await this.parseVodShortListFromJson(data["vod"])
this.homeVodList = [...this.homeVodList, ...vod_list]
}
}
vod_list = await this.parseVodShortListFromJson(resJson["data"]["loop"])
this.homeVodList = [...this.homeVodList, ...vod_list]
vod_list = await this.parseVodShortListFromJson(resJson["data"]["cai"])
this.homeVodList = [...this.homeVodList, ...vod_list]
}
async setCategory(tid, pg, filter, extend) {
const limit = 12;
const param = this.generateParam(tid, pg, extend, limit);
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/type_search', param));
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
}
async setDetail(id) {
const param = {
vod_id: id,
}
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/vod_details', param));
this.vodDetail = await this.parseVodDetailfromJson(resJson["data"])
}
async setPlay(flag, id, flags) {
const parsers = this.parseMap[flag];
if (flag.indexOf("芒果") > -1 || flag.indexOf("腾讯") > -1 || flag.indexOf("爱奇艺") > -1) {
if (!this.catOpenStatus) {
this.danmuUrl = await this.danmuSpider.downloadDanmu("https://dmku.thefilehosting.com/?ac=dm&url=" + id)
}
}
if (!_.isEmpty(parsers)) {
for (const parser of parsers) {
if (_.isEmpty(parser)) continue;
try {
const resp = await this.request(parser + id);
const json = JSON.parse(resp);
if (!_.isEmpty(json.url)) {
this.playUrl = json.url;
break;
}
} catch (e) {
}
}
}
}
async setSearch(wd, quick, pg) {
const limit = 12;
const param = {
keyword: wd, page: pg, limit: limit,
};
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/search', param));
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
const page = parseInt(pg);
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
}
let spider = new TianTianSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, TianTianSpider}

343
JN/CATJS/js/ttkan.js Normal file
View File

@ -0,0 +1,343 @@
/*
* @File : ttkan.js
* @Author : jade
* @Date : 2024/5/10 9:59
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class TTKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://cn.ttkan.co"
this.apiUrl = "https://cn.ttkan.co/api"
}
getAppName() {
return "天天看小说"
}
getJSName() {
return "ttkan"
}
getType() {
return 10
}
getName() {
return "📚︎┃天天看小说┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
let bookShortElements = $(element).find("a")
bookShort.book_name = bookShortElements[0].attribs["aria-label"]
bookShort.book_id = bookShortElements[0].attribs.href
if ($(element).find("amp-img").length > 0) {
bookShort.book_pic = $(element).find("amp-img")[0].attribs["src"].split("?")[0]
}
bookShort.book_remarks = $($(element).find("p")[0]).text()
return bookShort
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $("[class=\"frame_body\"]").find("[class=\"pure-g\"]").slice(-1)[0]
for (const bookElement of bookElements.children) {
let bookShort = this.parseVodShortFromElement($, $(bookElement).find("li")[0])
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let bookImgElements = $("[class=\"pure-u-xl-1-5 pure-u-lg-1-4 pure-u-md-1-3 pure-u-sm-1-3 pure-u-13-24\"]")
let bookMsgElements = $("[class=\"pure-u-xl-4-5 pure-u-lg-3-4 pure-u-md-2-3 pure-u-sm-2-3 pure-u-11-24\"]")
let books = [];
for (let i = 0; i < bookImgElements.length; i++) {
let bookShort = new BookShort()
let imgElement = bookImgElements[i]
let msgElement = bookMsgElements[i]
let element = $(imgElement).find('a')[0]
bookShort.book_id = element.attribs.href;
const img = $(imgElement).find('amp-img')[0];
bookShort.book_name = $(element).text()
bookShort.book_pic = img.attribs["src"].split("?")[0]
bookShort.book_name = img.attribs["alt"]
bookShort.book_remarks = $($(msgElement).find('li').slice(-1)).text().replaceAll("状态:","");
books.push(bookShort)
}
return books
}
async parseVodShortListFromJson(obj) {
let books = [];
for (const data of obj) {
let bookShort = new BookShort()
bookShort.book_id = "/novel/chapters/" + data["novel_id"]
bookShort.book_name = data["name"]
bookShort.book_remarks = "作者:" + data.author
bookShort.book_pic = "https://static.ttkan.co/cover/" + data["topic_img"]
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let books = []
let bookElements = $("[class=\"frame_body\"]").find("[class=\"pure-g\"]").slice(-1)[0]
for (const bookElement of bookElements.children) {
let bookShort = new BookShort()
bookShort.book_id = $(bookElement).find("a")[0].attribs.href
bookShort.book_name = $($(bookElement).find("li")[0]).text()
bookShort.book_remarks = $($(bookElement).find("li")[1]).text()
bookShort.book_pic = $(bookElement).find("amp-img")[0].attribs.src.split("?")[0]
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
let infoElement = $("[class=\"pure-g novel_info\"]")
bookDetail.book_pic = $(infoElement).find("amp-img")[0].attribs.src.split("?")[0]
let elements = $(infoElement).find("[class=\"pure-u-xl-5-6 pure-u-lg-5-6 pure-u-md-2-3 pure-u-1-2\"]").find("li")
bookDetail.book_name = $(elements[0]).text()
bookDetail.book_director = $(elements[1]).text().replaceAll("作者:","")
bookDetail.book_remarks = $(elements[3]).text().replaceAll("状态:","")
bookDetail.book_year= $("[class=\"near_chapter\"]").find("time")[0].attribs.datetime.replaceAll("T"," ").split(".")[0]
bookDetail.book_content = $($('[class="description"]')).text().trim()
bookDetail.book_id = id
const playBook = {};
const nearElement = $('[class="near_chapter"]').find("a")[0]
let nearVodItems = []
const epName = $(nearElement).text();
const page = nearElement.attribs.href.split("&page=").slice(-1)[0]
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${page}.html` ;
nearVodItems.push(epName + '$' + playUrl)
const lastestElements = $('[class="chapters_frame"]').find("a")
for (const lastestElement of lastestElements){
const epName = $(lastestElement).text();
const page = lastestElement.attribs.href.split("&page=").slice(-1)[0]
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${page}.html` ;
nearVodItems.push(epName + '$' + playUrl)
}
playBook["最近章节"] = nearVodItems.reverse().join("#")
let params = {"language":"cn","novel_id":id.replaceAll("/novel/chapters/",""),"__amp_source_origin":encodeURIComponent(this.siteUrl)}
let resJSon = JSON.parse(await this.fetch(this.apiUrl + "/nq/amp_novel_chapters" ,params,this.getHeader()))
let allVodItems = []
for (const data of resJSon["items"]){
const epName = data.chapter_name;
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${data.chapter_id}.html` ;
allVodItems.push(epName + '$' + playUrl)
}
playBook["目录"] = allVodItems.join("#")
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $('div.novel_class_nav > a')
for (const element of navElements) {
let type_id = element.attribs.href
let type_name = $(element).text()
this.classes.push(this.getTypeDic(type_name, type_id));
}
}
async getFilter($) {
let extend_list = []
let extend_dic = {"name": "排序", "key": "sort", "value": []}
let elements = $('div.rank_nav > a')
let sortList = []
let isNewSort = false
if (elements.length === 0) {
elements = $('div.nav_filter_inner > a')
isNewSort = true
}
for (const element of elements) {
let type_name = $(element).text()
let type_id = element.attribs.href
sortList.push(this.getFliterDic(type_name, type_id))
}
if (isNewSort) {
const lastItem = sortList.splice(-1, 1);
sortList = lastItem.concat(sortList);
}
extend_dic["value"] = sortList
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
getExtend(extend) {
if (extend["sort"] === undefined) {
return "*"
}
if (extend["sort"] === "全部") {
return "*"
} else {
let value = extend["sort"].replaceAll("/novel/", "").replaceAll("class/", "")
if (value.indexOf("_") > -1){
return value.split("_").slice(-1)[0]
}else{
return value
}
}
}
async setCategory(tid, pg, filter, extend) {
if (tid === "/novel/rank") {
tid = extend["sort"] ?? tid
let $ = await this.getHtml(this.siteUrl + tid)
this.vodList = await this.parseVodShortListFromDocByCategory($)
let x = 0
} else {
let extendFilter = this.getExtend(extend)
let limit = 18
let params = {
"language": "cn",
"limit": limit,
"type": tid.replaceAll("/novel/", "").replaceAll("class/", ""),
"filter": extendFilter,
"page": parseInt(pg),
"__amp_source_origin": encodeURIComponent(this.siteUrl)
}
let resJson = JSON.parse(await this.fetch(this.apiUrl + "/nq/amp_novel_list", params, this.getHeader()))
this.vodList = await this.parseVodShortListFromJson(resJson["items"])
}
}
async setPlay(flag, id, flags) {
let id_list = id.split("-")
id = id_list[1]
let content = id_list[0] + "\n\n"
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += Utils.formatContent($("[class=\"content\"]").html().trim().replaceAll("<p>", " ").replaceAll("</p>", "\n"));
id = $("[id=\"next_url\"]")[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content": content}
}
async setSearch(wd, quick) {
let params = {"q":encodeURIComponent(wd)}
let content = await this.fetch(this.siteUrl + "/novel/search", params, this.getHeader())
let $ = load(content)
this.vodList = await this.parseVodShortListFromDocBySearch($)
let x = 0
}
async setPlay(flag, id, flags) {
let id_list = id.split("+")
id = id_list[1]
let content = id_list[0] + "\n\n"
let $ = await this.getHtml(this.siteUrl + "/novel/pagea/" + id)
let bookContentList = $('[class="content"]').text().trim().replaceAll("章节报错 分享给朋友:","").replaceAll(" ","").split("\n")
let newBookContentList = []
for (const bookContent of bookContentList){
if (!_.isEmpty(bookContent.replaceAll(" ",""))){
newBookContentList.push(bookContent.replaceAll(" "," "))
}
}
content = content + " " + newBookContentList.join("\n\n")
this.playUrl = {"content": content}
}
}
let spider = new TTKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

192
JN/CATJS/js/vodSpider.js Normal file
View File

@ -0,0 +1,192 @@
/*
* @File : vodSpider.js
* @Author : jade
* @Date : 2024/2/6 16:53
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class VodSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = false
this.type_id_18 = 34
}
async spiderInit(inReq) {
if (inReq !== null) {
this.detailProxy = await js2Proxy(inReq, "detail", this.getHeader());
} else {
this.detailProxy = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromJson(obj, isSearch = false) {
let vod_list = []
let vodShort;
for (const vod_data of obj["list"]) {
if (!isSearch) {
vodShort = this.parseVodDetail(vod_data)
} else {
vodShort = new VodShort();
vodShort.vod_pic = this.detailProxy + Utils.base64Encode(vod_data["vod_id"])
vodShort.vod_id = vod_data["vod_id"]
vodShort.vod_name = vod_data["vod_name"]
vodShort.vod_remarks = vod_data["vod_remarks"]
}
if (this.remove18 && vod_data["type_id"] !== this.type_id_18) {
vod_list.push(vodShort)
}
if (!this.remove18 && vod_data["type_id"] === this.type_id_18) {
vod_list.push(vodShort)
}
}
return vod_list
}
parseVodDetail(vod_data) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_data["vod_id"]
vodDetail.vod_name = vod_data["vod_name"]
vodDetail.vod_pic = vod_data["vod_pic"]
vodDetail.vod_remarks = vod_data["vod_remarks"]
vodDetail.vod_area = vod_data["vod_area"]
vodDetail.vod_year = vod_data["vod_year"]
vodDetail.vod_actor = vod_data["vod_actor"]
vodDetail.vod_director = vod_data["vod_director"]
let $ = load(vod_data['vod_content'])
vodDetail.vod_content = $.text()
if (vod_data["vod_down_url"] !== undefined) {
if (vod_data["vod_down_url"].length > 0) {
vodDetail.vod_play_from = "直链播放$$$"
vodDetail.vod_play_url = vod_data["vod_down_url"] + "$$$"
}
}
vodDetail.vod_play_from = vodDetail.vod_play_from + vod_data["vod_play_from"]
vodDetail.vod_play_url = vodDetail.vod_play_url + vod_data["vod_play_url"]
vodDetail.type_name = vod_data["type_name"]
return vodDetail
}
async parseVodDetailfromJson(obj) {
let vodDetail;
let vod_data_list = obj["list"]
if (vod_data_list.length > 0) {
let vod_data = vod_data_list[0]
vodDetail = this.parseVodDetail(vod_data)
}
return vodDetail
}
async setClasses() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const class_dic of content_json["class"]) {
if (class_dic["type_pid"] !== 0) {
this.classes.push(this.getTypeDic(class_dic["type_name"], class_dic["type_id"]))
}
}
}
async setFilterObj() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const root_class_dic of this.classes) {
let type_id = root_class_dic["type_id"].toString()
if (type_id !== "最近更新") {
let extend_dic = {"key": "1", "name": "分类", "value": [{"n": "全部", "v": type_id}]}
for (const class_dic of content_json["class"]) {
let type_name = class_dic["type_name"]
if (type_name === this.type_name_18) {
this.type_id_18 = class_dic["type_id"].toString()
}
if (this.remove18) {
if (class_dic["type_pid"] === root_class_dic["type_id"] && type_name !== this.type_name_18) {
extend_dic["value"].push({"n": type_name, "v": class_dic["type_id"].toString()})
}
} else {
if (class_dic["type_pid"] === root_class_dic["type_id"] && type_name === this.type_name_18) {
extend_dic["value"].push({"n": type_name, "v": class_dic["type_id"].toString()})
}
}
}
if (!this.remove18) {
this.classes = [this.getTypeDic("最近更新", "最近更新"), this.getTypeDic(this.type_name_18, this.type_id_18)]
} else {
this.filterObj[type_id] = [extend_dic]
}
}
}
}
async setHomeVod() {
let content = await this.fetch(this.siteUrl + "/index.php/ajax/data", {
"mid": "1"
}, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setDetail(id) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": id
}, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(content))
}
async setCategory(tid, pg, filter, extend) {
tid = extend["1"] ?? tid
let url = this.siteUrl + `/index.php/ajax/data?mid=1&tid=${tid}&page=${pg}&limit=20`
await this.jadeLog.debug(`分类URL:${url}`)
let content = await this.fetch(url, null, this.getHeader())
await this.jadeLog.debug(`分类内容为:${content}`)
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setSearch(wd, quick) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/", {"wd": wd}, this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content), true)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
await this.jadeLog.debug(`反向代理参数为:${url}`)
if (what === 'detail') {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": url
}, this.getHeader())
let vod_detail = await this.parseVodDetailfromJson(JSON.parse(content))
let pic_content = await this.fetch(vod_detail.vod_pic, null, this.getHeader(), false, false, 2)
if (!_.isEmpty(pic_content)) {
return JSON.stringify({
code: 200, buffer: 2, content: pic_content, headers: {},
});
} else {
return JSON.stringify({
code: 500, buffer: 2, content: "", headers: {},
});
}
}
}
}
export {VodSpider}

322
JN/CATJS/js/weixine.js Normal file
View File

@ -0,0 +1,322 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/weixine.js
* @Description: 阿里影视(已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {detailContent, initAli, playContent} from "../lib/ali.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class WeiXineSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.weixine.link';
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
getName() {
return `💂‍┃阿里影视┃💂`
}
getAppName() {
return "阿里影视"
}
getJSName() {
return "weixine"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($(".mobile-play")).find(".lazyload")[0].attribs["data-src"]
let video_info_aux_list = $($(".video-info-aux")).find(".tag-link")[1].children
for (const video_info_aux of video_info_aux_list) {
try {
vodDetail.type_name = vodDetail.type_name + video_info_aux.children[0].data
} catch {
}
}
let video_items = $('.video-info-items')
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const video_info_actor of vidoe_info_actor_list) {
if (video_info_actor.children.length > 0) {
actor_list.push(video_info_actor.children[0].data)
}
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = $(video_items[2]).find("a")[0].children[0].data
vodDetail.vod_remarks = `清晰度:${$(video_items[3]).find("div")[0].children[0].data}, 制作人:Jade`
vodDetail.vod_content = $(video_items[4]).find("p")[0].children[0].data
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "")
const share_url_list = [];
let items = $('.module-row-info')
for (const item of items) {
let aliUrl = $(item).find("p")[0].children[0].data
let matches = aliUrl.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_url_list.push(matches[1])
}
if (share_url_list.length > 0) {
let aliVodDetail = await detailContent(share_url_list)
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
} else {
await this.jadeLog.warning(`获取详情界面失败,失败原因为:没有分享链接`)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src'];
vodShort.vod_remarks = '';
vod_list.push(vodShort);
}
return vod_list
}
get_extend_sort_dic(tid) {
/***
tid为1,2,3的时候,电影,剧情,动漫
urlParams#0表示类别,1表示全部地区,2表示人气评分,3表示全部剧情,4表示全部语言,5表示字母查找,6表示页数,11表示时间
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部语言
#key为4,代表全部时间
#key为5,字幕查找
#key为6,时间排序
https://www.wogg.xyz/index.php/vodshow/1-全部地区-时间排序-全部剧情-全部语言-字幕查找------全部时间.html
tid为4,综艺
#key为1,代表全部地区
#key为2,代表全部时间
#key为3,字幕查找
#key为4,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/4-全部地区-时间排序---字母查找------全部时间.html
tid为5:音乐
#key为1,字幕查找
#key为2,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/5--时间排序---字幕查找------.html
tid为6,短剧
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部时间
#key为4,字幕查找
#key为5,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/6-全部地区-时间排序-全部剧情--字母查找------全部时间.html
*/
let extend_dic = {}
if (tid < 4) {
extend_dic = {
"1": 3, "2": 1, "3": 4, "4": 11, "5": 5, "6": 2
}
} else if (tid === 4) {
extend_dic = {
"1": 1, "2": 11, "3": 5, "4": 2,
}
} else if (tid === 6) {
extend_dic = {
"1": 3, "2": 1, "3": 11, "4": 5, "5": 2,
}
} else if (tid === 5) {
extend_dic = {
"1": 5, "2": 2,
}
}
return extend_dic
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $('.nav-link')
for (const element of elements) {
let type_id = parseInt(element.attribs.href.split("/").slice(-1)[0].split(".html")[0])
let type_name = element.children.slice(-1)[0].data.replaceAll("\n", "").replaceAll(" ", "").replaceAll("玩偶", "").replaceAll("\t", "")
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(), "v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/index.php/vodshow/${type_id}--------1---.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
urlParams[extend_dic[key]] = extend[key]
}
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async play(flag, id, flags) {
return await playContent(flag, id, flags);
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + '/index.php/vodsearch/-------------.html?wd=' + wd;
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new WeiXineSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

314
JN/CATJS/js/wogg.js Normal file
View File

@ -0,0 +1,314 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/wogg.js
* @Description: 玩偶哥哥爬虫类
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {initCloud, detailContent,playContent,getHeaders} from '../lib/cloud.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class WoggSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.wogg.net';
this.woggTypeObj = {"玩偶电影":"电影","玩偶剧集":"电视剧"}
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj)
this.danmuStaus = true
}
getName() {
return "💂‍┃阿里玩偶┃💂"
}
getAppName() {
return "阿里玩偶"
}
getJSName() {
return "wogg"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($(".mobile-play")).find(".lazyload")[0].attribs["data-src"]
vodDetail.type_name = this.woggTypeObj[$("[class=\"video-info-aux\"]").find("a")[0].attribs.title]
let video_items = $('.video-info-items')
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const video_info_actor of vidoe_info_actor_list) {
if (video_info_actor.children.length > 0){
actor_list.push(video_info_actor.children[0].data)
}
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = $(video_items[2]).find("a")[0].children[0].data
vodDetail.vod_remarks = `${$(video_items[3]).find("div")[0].children[0].data}, 制作人:Jade`
vodDetail.vod_content = $(video_items[4]).find("p")[0].children[0].data
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "")
const share_url_list = []
let items = $('.module-row-info')
for (const item of items) {
let shareUrl = $(item).find("p")[0].children[0].data
share_url_list.push(shareUrl)
}
let playVod = await detailContent(share_url_list,vodDetail.type_name)
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src'];
vodShort.vod_remarks = $($(item).find(".video-serial")[0]).text();
vod_list.push(vodShort);
}
return vod_list
}
get_extend_sort_dic(tid) {
/***
tid为1,2,3的时候,电影,剧情,动漫
urlParams#0表示类别,1表示全部地区,2表示人气评分,3表示全部剧情,4表示全部语言,5表示字母查找,6表示页数,11表示时间
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部语言
#key为4,代表全部时间
#key为5,字幕查找
#key为6,时间排序
https://www.wogg.xyz/index.php/vodshow/1-全部地区-时间排序-全部剧情-全部语言-字幕查找------全部时间.html
tid为4,综艺
#key为1,代表全部地区
#key为2,代表全部时间
#key为3,字幕查找
#key为4,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/4-全部地区-时间排序---字母查找------全部时间.html
tid为5:音乐
#key为1,字幕查找
#key为2,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/5--时间排序---字幕查找------.html
tid为6,短剧
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部时间
#key为4,字幕查找
#key为5,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/6-全部地区-时间排序-全部剧情--字母查找------全部时间.html
*/
let extend_dic = {}
if (tid < 4) {
extend_dic = {
"1": 3, "2": 1, "3": 4, "4": 11, "5": 5, "6": 2
}
} else if (tid === 4) {
extend_dic = {
"1": 1, "2": 11, "3": 5, "4": 2,
}
} else if (tid === 6) {
extend_dic = {
"1": 3, "2": 1, "3": 11, "4": 5, "5": 2,
}
} else if (tid === 5) {
extend_dic = {
"1": 5, "2": 2,
}
}
return extend_dic
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $('.nav-link')
for (const element of elements) {
let type_id = parseInt(element.attribs.href.split("/").slice(-1)[0].split(".html")[0])
let type_name = element.children.slice(-1)[0].data.replace("\n", "").replace(" ", "").replace("玩偶", "")
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/index.php/vodshow/${type_id}--------1---.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
urlParams[extend_dic[key]] = extend[key]
}
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + '/index.php/vodsearch/-------------.html?wd=' + wd;
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new WoggSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

304
JN/CATJS/js/xb6v.js Normal file
View File

@ -0,0 +1,304 @@
/*
* @File : xb6v.js
* @Author : jade
* @Date : 2023/12/26 10:13
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class Xb6vSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.xb6v.com";
}
getName() {
return "🧲┃磁力新6V┃🧲"
}
getAppName() {
return "磁力新6V"
}
getJSName() {
return "xb6v"
}
getType() {
return 3
}
async redirect(response) {
await this.jadeLog.debug(`重定向回复值为:${response.content}`)
let matcher = /<a HREF=(.*?)>/.exec(response.content)
if (matcher.length > 1) {
let new_url = this.siteUrl + "/e/search/" + matcher[1].replaceAll("\\", "").replaceAll("\"", "")
await this.jadeLog.info(`重定向url为:${new_url}`)
return await this.fetch(new_url, null, this.getHeader())
}
}
getActorOrDirector(pattern, str) {
return Utils.getStrByRegex(pattern, str)
.replace(/<br>/g, "")
.replace(/&nbsp;./g, "")
.replace(/&amp;/g, "")
.replace(/middot;/g, "・")
.replace(/     /g, ",")
.replace(/      /g, ",")
.replace(/ /g, "");
}
getDescription(pattern, str) {
return Utils.getStrByRegex(pattern, str)
.replace(/<\/?[^>]+>/g, "")
.replace(/\n/g, "")
.replace(/&amp;/g, "")
.replace(/middot;/g, "・")
.replace(/ldquo;/g, "【")
.replace(/rdquo;/g, "】")
.replace(/ /g, "");
}
async parseVodShortListFromDoc($) {
let items = $("#post_container .post_hover");
let vod_list = []
for (const item of items) {
let element = $(item).find("[class=zoom]")[0];
let vodShort = new VodShort()
vodShort.vod_id = element.attribs["href"];
vodShort.vod_name = element.attribs["title"].replaceAll(/<\\?[^>]+>/g, "");
vodShort.vod_pic = $(element).find("img")[0].attribs["src"];
vodShort.vod_remarks = $(item).find("[rel=\"category tag\"]").text().replaceAll("\n", "").replaceAll(" ", "");
vod_list.push(vodShort)
}
return vod_list;
}
async parseVodDetailFromDoc($) {
let sourceList = $("#post_content");
let play_form_list = []
let play_url_list = []
if (!this.catOpenStatus) {
let i = 0
let circuitName = "磁力线路";
for (const source of sourceList) {
let aList = $(source).find("table a")
let vodItems = []
for (const a of aList) {
let episodeUrl = a.attribs["href"]
let episodeName = a.children[0].data
if (!episodeUrl.toLowerCase().startsWith("magnet")) continue;
vodItems.push(episodeName + "$" + episodeUrl);
}
if (vodItems.length > 0) {
i++;
play_form_list.push(circuitName + i)
play_url_list.push(vodItems.join("#"))
}
}
}
let playSourceList = $($(".mainleft")).find("[class=\"widget box row\"]")
for (const source of playSourceList) {
let play_format = $(source).find("h3").text()
let vodItems = []
if (!_.isEmpty(play_format)) {
let urlSourceList = $(source).find("a")
for (const url_source of urlSourceList) {
vodItems.push(url_source.attribs["title"] + "$" + url_source.attribs["href"])
}
play_form_list.push(play_format)
play_url_list.push(vodItems.join("#"))
}
}
let partHTML = $(".context").html();
let vodDetail = new VodDetail();
vodDetail.vod_name = $(".article_container > h1").text();
vodDetail.vod_pic = $("#post_content img").attr("src");
vodDetail.type_name = Utils.getStrByRegex(/◎类  别 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.type_name)) vodDetail.type_name = $("[rel=\"category tag\"]").text();
vodDetail.vod_year = Utils.getStrByRegex(/◎年  代 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_year)) vodDetail.vod_year = Utils.getStrByRegex(/首播:(.*?)<br>"/, partHTML);
vodDetail.vod_area = Utils.getStrByRegex(/◎产  地 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_year)) vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?)<br>"/, partHTML);
vodDetail.vod_remarks = Utils.getStrByRegex(/◎上映日期 (.*?)<br>/, partHTML);
vodDetail.vod_actor = this.getActorOrDirector(/◎演  员 (.*?)<\/p>/, partHTML);
if (_.isEmpty(vodDetail.vod_actor)) vodDetail.vod_actor = this.getActorOrDirector(/◎主  演 (.*?)<\/p>/, partHTML);
if (_.isEmpty(vodDetail.vod_actor)) vodDetail.vod_actor = this.getActorOrDirector(/主演:(.*?)<br>/, partHTML);
vodDetail.vod_director = this.getActorOrDirector(/◎导  演 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_director)) vodDetail.vod_director = this.getActorOrDirector(/导演:(.*?)<br>/, partHTML);
vodDetail.vod_content = this.getDescription(/◎简  介(.*?)<hr>/gi, partHTML);
if (_.isEmpty(vodDetail.vod_content)) vodDetail.vod_content = this.getDescription(/简介(.*?)<\/p>/gi, partHTML);
if (_.isEmpty(vodDetail.vod_content)) vodDetail.vod_content = this.getDescription(/◎简  介(.*?)<br>/gi, partHTML);
vodDetail.vod_play_from = play_form_list.join("$$$")
vodDetail.vod_play_url = play_url_list.join("$$$")
return vodDetail
}
async parseVodPlayFromDoc(flag, $) {
let play_url = ""
let html = $.html()
switch (flag) {
case "播放地址(无插件 极速播放)":
case "播放地址三":
play_url = $($(".video")).find("iframe")[0].attribs["src"] + "/index.m3u8"
break
case "播放地址(无需安装插件)":
let matchers2 = /url: '(.*?)',/gs.exec(html)
if (matchers2.length > 1) {
play_url = matchers2[1]
}
break
case "播放地址四":
let matchers4 = /source: "(.*?)",/gs.exec(html)
if (matchers4.length > 1) {
play_url = matchers4[1]
}
break
default:
await this.jadeLog.warning(`暂不支持当前格式,当前格式为:${flag}`)
break
}
return play_url
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html);
let elements = $('#menus > li > a');
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
if (i < 2 || i === elements.length - 1) continue;
let typeName = element.children[0].data;
let typeId = element.attribs["href"];
this.classes.push({"type_name": typeName, "type_id": typeId})
if (typeName === "电视剧") {
let values = [{"n": "不限", "v": ""}]
for (const a of $(element.next).find("a")) {
values.push({"n": a.children[0].data, "v": a.attribs["href"].replaceAll(typeId, "")})
}
this.filterObj[typeId] = [{
"key": "cateId", "name": "类型", "value": values
}]
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html);
this.homeVodList = await this.parseVodShortListFromDoc($)
} else {
await this.jadeLog.info("首页类别解析失败", true)
}
}
async setCategory(tid, pg, filter, extend) {
let cateId = extend["cateId"] ?? "";
let cateUrl = this.siteUrl + tid + cateId;
this.page = parseInt(pg)
this.count = 0
this.limit = 18;
this.total = 0;
if (this.page !== 1) {
cateUrl += "index_" + pg + ".html";
}
let html = await this.fetch(cateUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
let href_elements = $(".pagination > a")
if (href_elements.length > 0) {
let href = href_elements.slice(-1)[0].attribs["href"];
let patternPageCount = /index_(.*?).html/
let matches = patternPageCount.exec(href)
this.count = parseInt(matches[1])
let items = $("#post_container .post_hover");
this.total = this.page === this.count ? (this.page - 1) * this.limit + items.length : this.count * this.limit;
}
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + "/e/search/index.php";
let params = {
"show": "title", "tempid": "1", "tbname": "article", "mid": "1", "dopost": "search", "keyboard": wd,
}
let html = await this.post(searchUrl, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
if (id.toLowerCase().startsWith("magnet")) {
this.playUrl = id
} else {
let playUrl = this.siteUrl + id
let html = await this.fetch(playUrl, null, this.getHeader())
let $ = load(html)
this.playUrl = await this.parseVodPlayFromDoc(flag, $)
}
}
}
let spider = new Xb6vSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}

268
JN/CATJS/js/yiqikan.js Normal file
View File

@ -0,0 +1,268 @@
/*
* @File : yiqikan.js
* @Author : jade
* @Date : 2024/3/19 18:45
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 一起看 (已失效)
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class YiQiKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.gquaxhce.com"
this.nextObj = {}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true;
}
getRequestId() {
let strArr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
let sb = "";
for (let i = 0; i < 32; i++) {
sb = sb + strArr[_.random(0, strArr.length)];
}
return sb.toString();
}
getName() {
return `🛫┃一起看┃🛫`
}
getAppName() {
return "一起看"
}
getJSName() {
return "yiqikan"
}
getType() {
return 3
}
getHeader() {
let headers = super.getHeader();
headers["Connection"] = "keep-alive"
headers["Host"] = "api.gquaxhce.com"
return headers
}
getParams(ob_params = null) {
let requestId = this.getRequestId()
let appid = "e6ddefe09e0349739874563459f56c54"
let reqDomain = "m.yqktv888.com"
let udid = Utils.getUUID();
let appKey = "3359de478f8d45638125e446a10ec541"
let params = {"appId": appid}
if (!_.isEmpty(ob_params)) {
for (const ob_key of Object.keys(ob_params)) {
if (!_.isEmpty(ob_params[ob_key]) && (ob_key === "epId" || ob_key === "nextCount" || ob_key === "nextVal" || ob_key === "queryValueJson" || ob_key === "keyword")) {
params[ob_key] = ob_params[ob_key]
}
}
}
params["reqDomain"] = reqDomain
params["requestId"] = requestId
params["udid"] = udid
if (!_.isEmpty(ob_params)) {
for (const ob_key of Object.keys(ob_params)) {
if (!_.isEmpty(ob_params[ob_key]) && (ob_key === "vodId" || ob_key === "vodResolution")) {
params[ob_key] = ob_params[ob_key]
}
}
}
params["appKey"] = appKey
params["sign"] = md5X(Utils.objectToStr(params))
delete params["appKey"]
return params
}
async setClasses() {
let response = JSON.parse(await this.post(this.siteUrl + "/v1/api/home/header", this.getParams(), this.getHeader(), "raw"))
for (const data of response["data"]["channelList"]) {
this.classes.push(this.getTypeDic(data["channelName"], data["channelId"]))
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["vodId"]
vodShort.vod_name = data["vodName"]
vodShort.vod_remarks = data["watchingCountDesc"]
vodShort.vod_pic = data["coverImg"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["vodName"]
vodDetail.vod_content = obj["intro"]
vodDetail.vod_area = obj["areaName"]
vodDetail.vod_year = obj["year"]
vodDetail.type_name = obj["channelName"]
vodDetail.vod_remarks = "评分:" + obj["score"].toString()
vodDetail.vod_pic = obj["coverImg"]
vodDetail.vod_actor = Utils.objToList(obj["actorList"], "vodWorkerName")
vodDetail.vod_director = Utils.objToList(obj["directorList"], "vodWorkerName")
let playlist = {}
for (const playDic of obj["playerList"]) {
let vodItems = []
for (const item of playDic["epList"]) {
let playId = item["epId"]
let playName = item["epName"]
vodItems.push(playName + "$" + playId)
}
playlist[playDic["playerName"]] = vodItems.join("#")
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setHomeVod() {
let response = await this.post(this.siteUrl + "/v1/api/home/body", this.getParams(), this.getHeader(), "raw")
let resJson = JSON.parse(response)
if (resJson["result"]) {
this.homeVodList = await this.parseVodShortListFromJson(resJson["data"]["hotVodList"])
} else {
await this.jadeLog.error(`获取首页失败,失败原因为:${resJson["msg"]}`)
}
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + "/v1/api/search/queryNow"
this.limit = 18
let ob_params = {}
if (!_.isEmpty(this.nextObj[tid])) {
ob_params["nextVal"] = this.nextObj[tid]
}
ob_params["nextCount"] = 18
ob_params["queryValueJson"] = JSON.stringify([{
"filerName": "channelId", "filerValue": tid.toString()
}]).replaceAll("\\\\", "")
let response = await this.post(url, this.getParams(ob_params), this.getHeader(), "raw")
let resJson = JSON.parse(response)
if (resJson["result"]) {
if (resJson["data"]["hasNext"]) {
this.nextObj[tid] = resJson["data"]["nextVal"]
}
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["items"])
} else {
await this.jadeLog.error(`获取分类失败,失败原因为:${resJson["msg"]}`)
}
}
async setDetail(id) {
let url = this.siteUrl + "/v1/api/vodInfo/detail"
let ob_params = {"vodId": id}
let response = await this.post(url, this.getParams(ob_params), this.getHeader(), "raw")
let resJson = JSON.parse(response)
if (resJson["result"]) {
this.vodDetail = await this.parseVodDetailfromJson(resJson["data"])
} else {
await this.jadeLog.error(`获取详情失败,失败原因为:${resJson["msg"]}`)
}
}
async setPlay(flag, id, flags) {
let url = this.siteUrl + "/v1/api/vodInfo/getEpDetail"
let ob_params = {"epId": id}
let ep_detail_response = await this.post(url, this.getParams(ob_params), this.getHeader(), "raw")
let ep_detail_resJson = JSON.parse(ep_detail_response)
let vodResolution = "1";
if (ep_detail_resJson["result"]) {
if (ep_detail_resJson["data"]["resolutionItems"].length > 0) {
vodResolution = ep_detail_resJson["data"]["resolutionItems"].slice(-1)[0]["vodResolution"].toString()
let playUrl = this.siteUrl + "/v1/api/vodInfo/getPlayUrl"
let play_params = {"epId": id, "vodResolution": vodResolution}
let play_response = await this.post(playUrl, this.getParams(play_params), this.getHeader(), "raw")
let play_resJson = JSON.parse(play_response)
if (play_resJson["result"]) {
this.playUrl = play_resJson["data"]
}else{
await this.jadeLog.error(`获取播放链接失败,失败原因为:${ep_detail_resJson["msg"]}`)
}
}
} else {
await this.jadeLog.error(`获取播放详情失败,失败原因为:${ep_detail_resJson["msg"]}`)
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/v1/api/search/search"
let ob_prams = {"nextCount":15,"nextVal":"","keyword":wd}
let esponse = await this.post(url, this.getParams(ob_prams), this.getHeader(), "raw")
let resJson = JSON.parse(esponse)
if (resJson["result"]) {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["items"])
} else {
await this.jadeLog.error(`获取详情失败,失败原因为:${resJson["msg"]}`)
}
}
}
let spider = new YiQiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}

190
JN/CATJS/lib/TextDecoder.js Normal file
View File

@ -0,0 +1,190 @@
import Stream, { DEFAULT_ENCODING, getEncoding } from './text_decoder_index.js'
import { end_of_stream, finished, codePointsToString } from './text_decoder_utils.js'
import { decoders } from './table.js'
// 8.1 Interface TextDecoder
class TextDecoder {
/**
* @param {string=} label The label of the encoding; defaults to 'utf-8'.
* @param {Object=} options
*/
constructor(label = DEFAULT_ENCODING, options = {}) {
// A TextDecoder object has an associated encoding, decoder,
// stream, ignore BOM flag (initially unset), BOM seen flag
// (initially unset), error mode (initially replacement), and do
// not flush flag (initially unset).
/** @private */
this._encoding = null
/** @private @type {?Decoder} */
this._decoder = null
/** @private @type {boolean} */
this._ignoreBOM = false
/** @private @type {boolean} */
this._BOMseen = false
/** @private @type {string} */
this._error_mode = 'replacement'
/** @private @type {boolean} */
this._do_not_flush = false
// 1. Let encoding be the result of getting an encoding from
// label.
const encoding = getEncoding(label)
// 2. If encoding is failure or replacement, throw a RangeError.
if (encoding === null || encoding.name == 'replacement')
throw RangeError('Unknown encoding: ' + label)
if (!decoders[encoding.name]) {
throw Error('Decoder not present.' +
' Did you forget to include encoding-indexes.js first?')
}
// 4. Set dec's encoding to encoding.
this._encoding = encoding
// 5. If options's fatal member is true, set dec's error mode to
// fatal.
if (options['fatal'])
this._error_mode = 'fatal'
// 6. If options's ignoreBOM member is true, set dec's ignore BOM
// flag.
if (options['ignoreBOM'])
this._ignoreBOM = true
}
get encoding() {
return this._encoding.name.toLowerCase()
}
get fatal() {
return this._error_mode === 'fatal'
}
get ignoreBOM() {
return this._ignoreBOM
}
/**
* @param {BufferSource=} input The buffer of bytes to decode.
* @param {Object=} options
* @return The decoded string.
*/
decode(input, options = {}) {
let bytes
if (typeof input === 'object' && input instanceof ArrayBuffer) {
bytes = new Uint8Array(input)
} else if (typeof input === 'object' && 'buffer' in input &&
input.buffer instanceof ArrayBuffer) {
bytes = new Uint8Array(input.buffer,
input.byteOffset,
input.byteLength)
} else {
bytes = new Uint8Array(0)
}
// 1. If the do not flush flag is unset, set decoder to a new
// encoding's decoder, set stream to a new stream, and unset the
// BOM seen flag.
if (!this._do_not_flush) {
this._decoder = decoders[this._encoding.name]({
fatal: this._error_mode === 'fatal' })
this._BOMseen = false
}
// 2. If options's stream is true, set the do not flush flag, and
// unset the do not flush flag otherwise.
this._do_not_flush = Boolean(options['stream'])
// 3. If input is given, push a copy of input to stream.
// TODO: Align with spec algorithm - maintain stream on instance.
const input_stream = new Stream(bytes)
// 4. Let output be a new stream.
const output = []
/** @type {?(number|!Array.<number>)} */
let result
// 5. While true:
while (true) {
// 1. Let token be the result of reading from stream.
const token = input_stream.read()
// 2. If token is end-of-stream and the do not flush flag is
// set, return output, serialized.
// TODO: Align with spec algorithm.
if (token === end_of_stream)
break
// 3. Otherwise, run these subsubsteps:
// 1. Let result be the result of processing token for decoder,
// stream, output, and error mode.
result = this._decoder.handler(input_stream, token)
// 2. If result is finished, return output, serialized.
if (result === finished)
break
if (result !== null) {
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
}
// 3. Otherwise, if result is error, throw a TypeError.
// (Thrown in handler)
// 4. Otherwise, do nothing.
}
// TODO: Align with spec algorithm.
if (!this._do_not_flush) {
do {
result = this._decoder.handler(input_stream, input_stream.read())
if (result === finished)
break
if (result === null)
continue
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
} while (!input_stream.endOfStream())
this._decoder = null
}
return this.serializeStream(output)
}
// A TextDecoder object also has an associated serialize stream
// algorithm...
/**
* @param {!Array.<number>} stream
*/
serializeStream(stream) {
// 1. Let token be the result of reading from stream.
// (Done in-place on array, rather than as a stream)
// 2. If encoding is UTF-8, UTF-16BE, or UTF-16LE, and ignore
// BOM flag and BOM seen flag are unset, run these subsubsteps:
if (['UTF-8', 'UTF-16LE', 'UTF-16BE'].includes(this._encoding.name) &&
!this._ignoreBOM && !this._BOMseen) {
if (stream.length > 0 && stream[0] === 0xFEFF) {
// 1. If token is U+FEFF, set BOM seen flag.
this._BOMseen = true
stream.shift()
} else if (stream.length > 0) {
// 2. Otherwise, if token is not end-of-stream, set BOM seen
// flag and append token to stream.
this._BOMseen = true
} else {
// 3. Otherwise, if token is not end-of-stream, append token
// to output.
// (no-op)
}
}
// 4. Otherwise, return output.
return codePointsToString(stream)
}
}
export {TextDecoder}

107
JN/CATJS/lib/TextEncoder.js Normal file
View File

@ -0,0 +1,107 @@
import Stream, { DEFAULT_ENCODING, getEncoding } from './text_decoder_index.js'
import { end_of_stream, finished, stringToCodePoints } from './text_decoder_utils.js'
import { encoders } from './table.js'
// 8.2 Interface TextEncoder
class TextEncoder {
/**
* @param {string=} label The label of the encoding. NONSTANDARD.
* @param {Object=} [options] NONSTANDARD.
*/
constructor(label, options = {}) {
// A TextEncoder object has an associated encoding and encoder.
/** @private */
this._encoding = null
/** @private @type {?Encoder} */
this._encoder = null
// Non-standard
/** @private @type {boolean} */
this._do_not_flush = false
/** @private @type {string} */
this._fatal = options['fatal'] ? 'fatal' : 'replacement'
// 2. Set enc's encoding to UTF-8's encoder.
if (options['NONSTANDARD_allowLegacyEncoding']) {
// NONSTANDARD behavior.
label = label !== undefined ? String(label) : DEFAULT_ENCODING
var encoding = getEncoding(label)
if (encoding === null || encoding.name === 'replacement')
throw RangeError('Unknown encoding: ' + label)
if (!encoders[encoding.name]) {
throw Error('Encoder not present.' +
' Did you forget to include encoding-indexes.js first?')
}
this._encoding = encoding
} else {
// Standard behavior.
this._encoding = getEncoding('utf-8')
if (label !== undefined && 'console' in global) {
console.warn('TextEncoder constructor called with encoding label, '
+ 'which is ignored.')
}
}
}
get encoding() {
return this._encoding.name.toLowerCase()
}
/**
* @param {string=} opt_string The string to encode.
* @param {Object=} options
*/
encode(opt_string = '', options = {}) {
// NOTE: This option is nonstandard. None of the encodings
// permitted for encoding (i.e. UTF-8, UTF-16) are stateful when
// the input is a USVString so streaming is not necessary.
if (!this._do_not_flush)
this._encoder = encoders[this._encoding.name]({
fatal: this._fatal === 'fatal' })
this._do_not_flush = Boolean(options['stream'])
// 1. Convert input to a stream.
const input = new Stream(stringToCodePoints(opt_string))
// 2. Let output be a new stream
const output = []
/** @type {?(number|!Array.<number>)} */
var result
// 3. While true, run these substeps:
while (true) {
// 1. Let token be the result of reading from input.
var token = input.read()
if (token === end_of_stream)
break
// 2. Let result be the result of processing token for encoder,
// input, output.
result = this._encoder.handler(input, token)
if (result === finished)
break
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
}
// TODO: Align with spec algorithm.
if (!this._do_not_flush) {
while (true) {
result = this._encoder.handler(input, input.read())
if (result === finished)
break
if (Array.isArray(result))
output.push.apply(output, /**@type {!Array.<number>}*/(result))
else
output.push(result)
}
this._encoder = null
}
// 3. If result is finished, convert output into a byte sequence,
// and then return a Uint8Array object wrapping an ArrayBuffer
// containing output.
return new Uint8Array(output)
}
}
export {TextEncoder}

86
JN/CATJS/lib/ali.js Normal file
View File

@ -0,0 +1,86 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: lib/ali.js
* @Description: 阿里云盘Spider公共
*/
import {
initSome,
clearFile,
playerContent,
playerContentByFlag,
setShareId,
setToken,
getFileByShare, getTempFileId
} from './ali_api.js';
import {JadeLogging} from "./log.js";
const aliName = "阿里云盘"
const JadeLog = new JadeLogging(aliName)
const aliPlayFormatList = ["原画", "超清", "高清", "标清"]
async function initAli(token) {
await initSome();
await setToken(token);
await getTempFileId();
// await clearFile();
await JadeLog.info("阿里云盘初始化完成", true)
}
function getShareId(share_url) {
let patternAli = /https:\/\/www\.alipan\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?|https:\/\/www\.aliyundrive\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?/
let matches = patternAli.exec(share_url)
const filteredArr = matches.filter(item => item !== undefined);
if (filteredArr.length > 1) {
return filteredArr[1]
} else {
return ""
}
}
async function detailContentAli(share_url_list, type_name = "电影") {
try {
let video_items = [], sub_items = []
for (let i=0;i<share_url_list.length;i++){
let share_url = share_url_list[i]
let share_id = getShareId(share_url)
let share_token = await setShareId(share_id)
if (share_token !== undefined) {
await getFileByShare(i+1,share_token, share_url, video_items, sub_items)
}
}
if (video_items.length > 0) {
await JadeLog.info(`获取播放链接成功,分享链接为:${share_url_list.join("\t")}`)
} else {
await JadeLog.error(`获取播放链接失败,检查分享链接为:${share_url_list.join("\t")}`)
}
return {"video_items":video_items,"sub_items":sub_items}
} catch (e) {
await JadeLog.error('获取阿里视频失败,失败原因为:' + e.message + ' 行数为:' + e.lineNumber);
}
}
async function playContentAli(flag, id, flags) {
if (flags.length > 0) {
await JadeLog.info(`准备播放,播放类型为:${flag},播放文件Id为:${id},播放所有类型为:${flags.join("")}`)
} else {
await JadeLog.info(`准备播放,播放类型为:${flag},播放文件Id为:${id},播放所有类型为:${flags.join("")}`)
}
let file_id_list = id.split("+")
let share_id = file_id_list[1]
let file_id = file_id_list[0]
let share_token = file_id_list[2]
return flag === "原画" ? await playerContent(file_id, share_id, share_token) : await playerContentByFlag(file_id, flag, share_id, share_token);
}
export {
initAli,
detailContentAli,
playContentAli,
aliPlayFormatList,
aliName,
};

670
JN/CATJS/lib/ali_api.js Normal file
View File

@ -0,0 +1,670 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: /lib/ali_api.js
* @Description: 阿里云盘Api
*/
import {_, jinja2} from "./cat.js";
import * as Utils from "./utils.js";
import {JadeLogging} from "./log.js";
import {
Code, Drive, getHeader, getOAuthCache, getUserCache, Item, OAuth, post, postJson, Sub, User, CLIENT_ID
} from "./ali_object.js";
let quality = {}, tempIds = [], shareToken = "", shareId = "", oauth = new OAuth(), user = new User(),
driveInfo = new Drive(), tmpFolderName = "TV", curTmpFolderFileId = "",
JadeLog = new JadeLogging("阿里云盘", "INFO");
async function initSome() {
let user_cache_str = await getUserCache();
user = User.objectFrom(user_cache_str);
if (!_.isEmpty(user.getRefreshToken())) {
await JadeLog.info("读取用户缓存成功", true);
} else {
await JadeLog.error("读取用户缓存失败", true);
}
let oauth_cache_str = await getOAuthCache();
oauth = OAuth.objectFrom(oauth_cache_str);
if (!_.isEmpty(oauth.getAccessToken())) {
await JadeLog.info("读取授权成功", true)
} else {
await JadeLog.error("读取授权失败", true)
}
// quality = {
// "4K": "UHD", "2k": "QHD", "超清": "FHD", "高清": "HD", "标清": "SD", "流畅": "LD"
// };
quality = {
"4K": "UHD", "2k": "QHD", "超清": "QHD", "高清": "HD", "标清": "SD", "流畅": "LD"
};
await JadeLog.info("阿里Api初始化完成")
}
async function getTempFileId() {
curTmpFolderFileId = await createTmpFolder();
}
async function clearFile() {
try {
await deleteTmpFolderAndRecreate();
} catch (e) {
await JadeLog.error("清空缓存文件失败,失败原因为:{}" + e)
}
await cleanRecord()
}
async function cleanRecord() {
await local.set("file", "file_id", JSON.stringify({}))
}
async function setShareId(share_id) {
getOAuthCache().length === 0 && (await oauth.clean().save());
getUserCache().length === 0 && (await user.clean().save());
shareId = share_id;
return await refreshShareToken();
}
function getHeaderAuth(shareToken) {
const params = {};
params["x-share-token"] = shareToken;
params["X-Canary"] = "client=Android,app=adrive,version=v4.3.1";
if (user.isAuthed()) {
params.authorization = user.getAuthorization();
}
return params;
}
function getHeaderShare() {
const params = getHeader();
params["x-share-token"] = shareToken;
params["X-Canary"] = "client=Android,app=adrive,version=v4.3.1";
return params;
}
function getHeaderOpen() {
const params = {};
params.authorization = oauth.getAuthorization();
return params;
}
function aliExpection(data_str) {
if (data_str.indexOf("TooManyRequests") > -1) {
Utils.sleep(1)
return {code: 429, content: data_str}
} else if (data_str.indexOf("AccessTokenInvalid") > -1) {
return {code: 400, content: data_str}
} else if (data_str.indexOf("AccessTokenExpired") > -1) {
return {code: 401, content: data_str}
} else if (data_str.indexOf("BadRequest") > -1) {
return {code: 402, content: data_str}
} else if (data_str.indexOf("NotFound.File") > -1 || data_str.indexOf("ForbiddenFileInTheRecycleBin") > -1) {
return {code: 403, content: data_str}
} else if (data_str.indexOf("ForbiddenNoPermission.File") > -1) {
return {code: 500, content: data_str}
} else if (data_str.indexOf("InvalidParameter.ToParentFileId") > -1) {
return {code: 501, content: data_str}
} else if (data_str.indexOf("NotFound.ParentFileId") > -1) {
return {code: 502, content: data_str}
} else if (data_str.indexOf("The resource drive has exceeded the limit. File size exceeded drive capacity") > -1) {
return {code: 503, content: data_str}
}
return {code: 200, content: data_str}
}
async function alistManyRequest(data_str) {
if (!(data_str.indexOf("Too Many Requests") > -1)) {
return false;
}
await oauth.clean().save();
return true;
}
// Alist Token获取
async function alist(url_param, params) {
let url = "https://api-cf.nn.ci/alist/ali_open/" + url_param;
let response = await postJson(url, params, getHeader()), response_content = response.content;
if (await alistManyRequest(response_content)) {
await JadeLog.error(`Alist授权Token失败,失败原因为:太多请求,失败详情为:${response_content}`)
return false;
}
oauth = await OAuth.objectFrom(response_content).save();
return true;
}
// 阿里云盘用户Api
async function auth(url, params, shareToken, retry) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
let response = await postJson(url, params, getHeaderAuth(shareToken));
await JadeLog.debug(`正在请求需要阿里登录的url:${url},参数为:${JSON.stringify(params)}`)
response = aliExpection(response.content)
if (retry && (response.code === 400)) {
await JadeLog.error("登录阿里云盘失败,失败原因为:登录Token无效,准备重新授权,失败详情:" + response.content)
await refreshAccessToken("")
return await auth(url, params, shareToken, false);
}
await JadeLog.debug(`完成请求需要阿里登录的url:${url},参数为:${JSON.stringify(params)},请求结果为${response.content}`)
return response.content;
}
// 需要授权的Api
async function oauthFunc(url, params, retry) {
url = url.startsWith("https") ? url : "https://open.aliyundrive.com/adrive/v1.0/" + url;
await JadeLog.debug(`正在请求需要阿里授权的url:${url},参数为:${JSON.stringify(params)}`)
let open_header = getHeaderOpen();
let response = await postJson(url, params, open_header);
response = aliExpection(response.content)
if (retry && (response.code === 400 || response.code === 401 || response.code === 429 || response.code === 402 || response.code === 403)) {
if (response.code === 400) {
await JadeLog.error("阿里授权失败,失败原因为:授权Token无效,准备重新授权,失败详情:" + response.content)
await activateRefreshOpenToken()
} else if (response.code === 401) {
await JadeLog.error("阿里授权失败,失败原因为:授权Token失效,准备重新授权,失败详情:" + response.content)
await activateRefreshOpenToken()
} else if (response.code === 402) {
await JadeLog.error("阿里授权失败,失败原因为:授权Token失效,准备重新授权,失败详情:" + response.content)
return await oauthFunc(url, params, true)
} else if (response.code === 403) {
await JadeLog.error("阿里授权失败,失败原因为:没有找到缓存文件,失败详情:" + response.content)
await cleanRecord()
return "retry"
} else if (response.code === 429) {
await JadeLog.error(`正在请求需要阿里授权的url:${url},请求过于频繁,稍后重试,10分钟后再重试`)
Utils.sleep(10 * 60)
return await oauthFunc(url, params, true)
}
return await oauthFunc(url, params, false)
}
await JadeLog.debug(`完成请求需要阿里授权的url:${url},参数为:${JSON.stringify(params)},请求结果为:${JSON.stringify(response)}`)
return response.content;
}
async function shareFunc(url, params) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
let headers = getHeaderShare(), response = await postJson(url, params, headers);
return response.content;
}
//主动刷新授权Token
async function activateRefreshOpenToken() {
await oauth.clean().save()
await refreshOpenToken()
}
async function refreshShareToken() {
try {
let params = {};
params.share_id = shareId;
params.share_pwd = "";
let response_content = await post("v2/share_link/get_share_token", params),
response_json = JSON.parse(response_content);
if (response_json["code"] === "ShareLink.Cancelled") {
await JadeLog.error("分享链接被取消了")
}
shareToken = response_json.share_token;
return shareToken
} catch (e) {
await JadeLog.error("刷新Share Token失败" + e)
}
}
//支持切换Token
async function refreshAccessToken(token) {
try {
if (_.isEmpty(user.getAccessToken()) || user.getRefreshToken() !== token) {
let refresh_token_params = {};
refresh_token_params.refresh_token = user.getRefreshToken();
refresh_token_params.grant_type = "refresh_token";
await JadeLog.info(`准备登录阿里云盘,登录Token为:${user.getRefreshToken()}`)
let response_conetent = await post("https://auth.aliyundrive.com/v2/account/token", refresh_token_params);
if (response_conetent.indexOf("InvalidParameter.RefreshToken") > 1 || _.isEmpty(response_conetent)) {
if (_.isEmpty(response_conetent)) {
await JadeLog.error(`登录阿里云盘失败,登录Token为:${user.getRefreshToken()},失败原因为:检查Token是否正确`)
} else {
await JadeLog.error(`登录阿里云盘失败,登录Token为:${user.getRefreshToken()},失败原因为:检查Token是否正确,返回结果为:${response_conetent}`)
}
} else {
await JadeLog.info(`登录阿里云盘成功,登录Token为:${user.getRefreshToken()}`)
user = await User.objectFrom(response_conetent).save();
}
} else {
await JadeLog.info(`阿里云盘已登录,无需重复登录,登录Token为:${user.getRefreshToken()}`)
}
return true;
} catch (e) {
await JadeLog.error(`登录阿里云盘失败,登录Token为:${user.getRefreshToken()},失败原因为:${e}`)
await user.clean().save();
return true;
}
}
async function oauthRequest() {
try {
let params = {};
params.authorize = 1;
params.scope = "user:base,file:all:read,file:all:write";
let url = "https://open.aliyundrive.com/oauth/users/authorize?client_id=" + CLIENT_ID + "&redirect_uri=https://alist.nn.ci/tool/aliyundrive/callback&scope=user:base,file:all:read,file:all:write&state="
await JadeLog.debug(`正在请求获取阿里授权码的url:${url},参数为:${params}`)
let response_str = await auth(url, params, shareToken, true);
await JadeLog.debug(`完成请求获取阿里授权码的url:${url},参数为:${params},返回值为:${response_str}`)
if (_.isEmpty(response_str) || response_str.indexOf("AccessTokenInvalid") > -1) {
if (_.isEmpty(response_str)) {
await JadeLog.error(`请求获取阿里授权码失败,失败原因为:还未登录`)
} else {
await JadeLog.error(`请求获取阿里授权码失败,失败原因为:还未登录,失败详情为:${response_str}`)
}
} else {
await JadeLog.info(`请求获取阿里授权码成功,返回值为:${response_str}`)
return await oauthRedirect(Code.objectFrom(response_str).getCode());
}
} catch (e) {
await JadeLog.error(`请求获取阿里授权失败,失败原因为:${e}`)
return false;
}
}
async function oauthRedirect(code) {
try {
let params = {};
params.code = code;
params.grant_type = "authorization_code";
return await alist("code", params);
} catch (e) {
// // console.debug(_0x114c46);
await oauth.clean().save();
return false;
}
}
async function refreshOpenToken() {
try {
// 刷新 Refresh Token
if (_.isEmpty(oauth.getRefreshToken())) {
return await oauthRequest();
}
// 刷新Access Token
if (_.isEmpty(oauth.getAccessToken())) {
let params = {};
params.grant_type = "refresh_token";
params.refresh_token = oauth.getRefreshToken();
return await alist("token", params);
}
return true;
} catch (e) {
await JadeLog.error("刷新授权Token失败,失败原因为:" + e);
await oauth.clean().save();
return false;
}
}
async function getFileByShare(index,share_token, share_url, video_item_list, sub_item_list) {
let params = {};
params.share_id = shareId;
let file_id = share_url.split("folder/").slice(-1)[0]
if (file_id.length !== 40) {
file_id = ""
}
let response_str = await post("adrive/v3/share_link/get_share_by_anonymous", params),
response_json = JSON.parse(response_str), item_file_id = getParentFileId(file_id, response_json),
item = new Item(item_file_id);
await listFiles(index,item, video_item_list, sub_item_list, share_token);
}
async function listFiles(index,item, video_item_list, sub_item_list, share_token) {
return await listFilesMarker(index,item, video_item_list, sub_item_list, "", share_token);
}
async function listFilesMarker(index,item, video_item_list, sub_item_list, netxt_markers, share_token) {
let new_item = {}, file_list = [];
new_item.limit = 200;
new_item.share_id = shareId;
new_item.share_token = share_token
new_item.parent_file_id = item.getFileId();
new_item.order_by = "name";
new_item.order_direction = "ASC";
new_item.share_index = index
if (netxt_markers.length > 0) {
new_item.marker = netxt_markers;
}
let items = Item.objectFrom(await shareFunc("adrive/v2/file/list_by_share", new_item), shareToken,index);
for (const r_item of items.getItems()) {
if (r_item.getType() === "folder") {
file_list.push(r_item);
} else {
if ((r_item.getCategory() === "video" || r_item.getCategory() === "audio")) {
//判断数组中是否有file_id
//
let is_video_file_exists = false
for (const video_item of video_item_list) {
if (r_item.getFileId() === video_item.getFileId()) {
is_video_file_exists = true
await JadeLog.debug('视频分享文件重复,无需添加')
}
}
if (!is_video_file_exists) {
if (r_item.getCategory() === "video" && r_item.size / 1000000 > 10) {
video_item_list.push(r_item.parentFunc(item.getName()));
}
}
} else {
if (Utils.isSub(r_item.getExt())) {
let is_sub_file_exists = false
for (const sub_item of sub_item_list) {
if (r_item.getFileId() === sub_item.getFileId()) {
is_sub_file_exists = true
await JadeLog.debug('字幕分享文件重复,无需添加')
}
}
if (!is_sub_file_exists) {
sub_item_list.push(r_item);
}
}
}
}
}
items.getNextMarker().length > 0 && (await listFilesMarker(index,item, video_item_list, sub_item_list, items.getNextMarker()));
for (const file of file_list) {
await listFiles(index,file, video_item_list, sub_item_list);
}
}
function getParentFileId(file_id, items) {
let file_infos = items.file_infos;
if (!_.isEmpty(file_id)) {
return file_id;
}
if (file_infos.length === 0) {
return "";
}
let item = file_infos[0];
if (item.type === "folder") {
return item.file_id;
}
if (item.type === "file" && item.category === "video") {
return "root";
}
return "";
}
async function getSubs(sub_list, share_id) {
let sub_url_list = [];
for (const sub_str of sub_list) {
if (!(sub_str.indexOf("@@@") > -1)) {
continue;
}
let sub_split_list = sub_str.split("@@@"), sub_name = sub_split_list[0], sub_ext = sub_split_list[1],
sub_file_id = sub_split_list[2], sub_url = await getDownloadUrl(sub_file_id, share_id);
sub_url_list.push(Sub.create().setName(sub_name).setExt(sub_ext).setUrl(sub_url));
}
return sub_url_list;
}
async function getDriveInfo() {
if (!_.isEmpty(driveInfo) && !_.isEmpty(driveInfo.default_drive_id)) {
return driveInfo;
}
let _0x3740f3 = await oauthFunc("user/getDriveInfo", {}, true), _0x56fde5 = JSON.parse(_0x3740f3);
driveInfo = {
default_drive_id: _0x56fde5.default_drive_id,
resource_drive_id: _0x56fde5.resource_drive_id,
backup_drive_id: _0x56fde5.backup_drive_id
};
return driveInfo;
}
async function getDriveId() {
if (_.isEmpty(user.getDriveId())) {
let drive = await getDriveInfo();
return drive.resource_drive_id;
}
return user.getDriveId();
}
async function getDownloadUrl(file_id, share_id, share_token) {
let drive_id = await getDriveId();
tempIds.unshift(await copy(file_id, share_id, share_token));
let params = {};
params.file_id = tempIds[0];
params.drive_id = drive_id;
if (tempIds[0] !== null) {
let response_str = await oauthFunc("openFile/getDownloadUrl", params, true);
if (response_str === "retry") {
await JadeLog.info("尝试重新获取下载链接");
return await getDownloadUrl(file_id, share_id)
} else {
await JadeLog.info("获取下载链接成功:返回结果为:" + response_str + "请求参数为:" + JSON.stringify(params));
return JSON.parse(response_str).url;
}
} else {
await JadeLog.error("获取下载链接失败:失败原因:请检查转存文件失败原因")
return null;
}
}
async function getVideoPreviewPlayInfo(file_id, share_id, shareToken) {
let drive_id = await getDriveId();
tempIds.unshift(await copy(file_id, share_id, shareToken));
let params = {};
params.file_id = tempIds[0];
params.drive_id = drive_id;
params.category = "live_transcoding";
params.url_expire_sec = "14400";
let response_str = await oauthFunc("openFile/getVideoPreviewPlayInfo", params, true);
return JSON.parse(response_str).video_preview_play_info;
}
async function playerContent(file_id, share_id, share_token) {
try {
await JadeLog.info("正在获取原画的播放地址和字幕下载链接", true)
let download_url = await getDownloadUrl(file_id, share_id, share_token);
// let sub_list = await getSubs(file_id_list,share_id);
await JadeLog.info("获取原画的播放地址和字幕下载链接成功", true)
await JadeLog.info(`下载地址为:${download_url}`)
return download_url;
} catch (e) {
await JadeLog.error("获取原画的播放地址和字幕下载链接失败:失败原因为:" + e);
}
}
// 转码头的Url和字幕
async function playerContentByFlag(file_id, flag, share_id, shareToken) {
try {
await JadeLog.info("正在获取转码后的播放地址和字幕下载链接", true)
let video_preview_play_info = await getVideoPreviewPlayInfo(file_id, share_id, shareToken),
video_preview_url = getPreviewUrl(video_preview_play_info, flag);
// let sub_list = await getSubs(file_id_list,share_id),
// sub_p_list = getSubsByPlayInfo(video_preview_play_info);
// for (const sub_p of sub_p_list) {
// sub_list.push(sub_p);
// }
await JadeLog.info("获取转码后的播放地址和字幕下载链接成功", true)
await JadeLog.info(`下载地址为:${video_preview_url}`)
return video_preview_url;
} catch (e) {
await JadeLog.error(`获取转码后的播放地址和字幕下载链接失败,失败原因为:${e}`)
}
}
function getPreviewUrl(video_preview_play_info, flag) {
if (!video_preview_play_info.hasOwnProperty("live_transcoding_task_list")) {
return "";
}
let live_transcoding_task_list = video_preview_play_info.live_transcoding_task_list;
for (let index = 0; index < live_transcoding_task_list.length; ++index) {
let live_transcoding_task = live_transcoding_task_list[index];
if (live_transcoding_task.template_id === quality[flag]) {
return live_transcoding_task.url;
}
}
return live_transcoding_task_list.slice(-1)[0].url;
}
function getSubsByPlayInfo(video_preview_play_info) {
if (!video_preview_play_info.hasOwnProperty("live_transcoding_subtitle_task_list")) {
return [];
}
let live_transcoding_subtitle_task_list = video_preview_play_info.live_transcoding_subtitle_task_list,
sub_p_list = [];
for (let index = 0; index < live_transcoding_subtitle_task_list.length; ++index) {
let live_transcoding_subtitle_task = live_transcoding_subtitle_task_list[index],
language = live_transcoding_subtitle_task.language, url = live_transcoding_subtitle_task.url;
sub_p_list.push(Sub.create().setUrl(url).setName(language).setLang(language).setExt("vtt"));
}
return sub_p_list;
}
async function copy(file_id, shareId, shareToken) {
let copy_file_id
let cache_dic = {}
try {
cache_dic = JSON.parse(await local.get("file", "file_id"))
} catch (e) {
}
copy_file_id = cache_dic[file_id]
if (typeof (copy_file_id) == "string") {
await JadeLog.info(`file id为:${file_id},已经缓存过,copy file id为:${copy_file_id}`)
} else {
let params_str = "{\"requests\":[{\"body\":{\"file_id\":\"{{data.fileId}}\",\"share_id\":\"{{data.shareId}}\",\"auto_rename\":true,\"to_parent_file_id\":\"{{data.tmpFolderFileId}}\",\"to_drive_id\":\"{{data.driveId}}\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"0\",\"method\":\"POST\",\"url\":\"/file/copy\"}],\"resource\":\"file\"}",
drive_id = await getDriveId(), params = {
fileId: file_id, shareId: shareId, driveId: drive_id, tmpFolderFileId: curTmpFolderFileId
};
params_str = jinja2(params_str, {
data: params
});
await JadeLog.debug(`正在转存文件,文件id为:${file_id}`, true)
let response_str = await auth("adrive/v2/batch", JSON.parse(params_str), shareToken, true);
let response = aliExpection(response_str)
if (response.code === 500 || response.code === 501 || response.code === 502 || response.code === 503 || response.code === 403) {
if (response.code === 500) {
await JadeLog.error("转存文件失败,失败详情:" + response.content)
return copy(file_id);
} else if (response.code === 501) {
await JadeLog.error("转存文件失败,失败详情:" + response.content)
return copy(file_id)
} else if (response.code === 502) {
await JadeLog.error("转存文件失败,失败原因为:转存文件夹不存在,失败详情:" + response.content)
return null;
} else if (response.code === 503) {
await JadeLog.error("转存文件失败,失败原因为:转存文件夹大小被限制" + response.content)
await clearFile()
return copy(file_id)
} else if (response.code === 403) {
await JadeLog.error("转存文件失败,失败原因为:没有找到File Id,失败详情:" + response.content)
return null;
}
}
await JadeLog.debug(`转存文件成功,文件id为:${file_id},请求结果为:${response_str}`)
copy_file_id = JSON.parse(response_str).responses[0].body.file_id;
let file_dic = {}
try {
JSON.parse(await local.get("file", "file_id"))
} catch (e) {
}
file_dic[file_id] = copy_file_id
await local.set("file", "file_id", JSON.stringify(file_dic))
}
return copy_file_id;
}
async function deleteTmpFolderAndRecreate() {
// 删除缓存文件夹
let file_id = await tmpFolderExistsFunc();
file_id && (await trashFile(file_id), await recyclebinClear());
await getTempFileId();
}
//放入回车站
async function trashFile(file_id) {
let params_str = "{\"requests\":[{\"body\":{\"file_id\":\"{{data.fileId}}\",\"drive_id\":\"{{data.driveId}}\"},\"headers\":{\"Content-Type\":\"application/json\"},\"id\":\"0\",\"method\":\"POST\",\"url\":\"/recyclebin/trash\"}],\"resource\":\"file\"}",
drive_id = await getDriveId(), params = {
fileId: file_id, driveId: drive_id
};
params_str = jinja2(params_str, {
data: params
});
await JadeLog.debug(`正在准备删除文件,文件id为:${file_id}`, true)
let response = await auth("v2/batch", JSON.parse(params_str), shareToken, true);
await JadeLog.debug(`删除文件成功,文件id为:${file_id},请求结果为:${response}`)
return true;
}
//清空回车站
async function recyclebinClear() {
let drive_id = await getDriveId(), params = {
drive_id: drive_id
};
await auth("v2/recyclebin/clear", params, shareToken, true);
await JadeLog.info("清空回车站成功", true)
return true;
}
async function createTmpFolder() {
//创建文件夹
let file_id = await tmpFolderExistsFunc();
if (file_id) {
await JadeLog.info("文件夹存在,无需重新创建")
return file_id;
}
await JadeLog.debug("文件夹不存在,重新创建文件夹")
let drive_id = await getDriveId(), params = {
check_name_mode: "refuse", drive_id: drive_id, name: tmpFolderName, parent_file_id: "root", type: "folder"
}, response_str = await oauthFunc("openFile/create", params, true);
let response_json = JSON.parse(response_str);
if (_.isEmpty(response_json.drive_id)) {
await JadeLog.error(`创建文件夹失败,失败原因为:${response_str}`)
return null;
}
await JadeLog.info(`创建文件夹成功`, true)
return response_json.file_id;
}
async function tmpFolderExistsFunc() {
let drive_id = await getDriveId(), params = {
drive_id: drive_id, parent_file_id: "root", limit: 100, order_by: "updated_at", order_direction: "DESC"
}, response_str = await oauthFunc("openFile/list", params, true);
let response_json = JSON.parse(response_str);
if (_.isEmpty(response_json.items)) {
return false;
}
for (const item of response_json.items) {
if (item.name === tmpFolderName) {
return item.file_id;
}
}
return false;
}
async function setToken(token) {
// Token设置
user.setRefreshToken(token);
await refreshAccessToken(token);
await refreshOpenToken();
}
export {
initSome, setToken, clearFile, setShareId, getFileByShare, playerContent, playerContentByFlag, getTempFileId
};

516
JN/CATJS/lib/ali_object.js Normal file
View File

@ -0,0 +1,516 @@
/*
* @Author: samples jadehh@live.com
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples jadehh@live.com
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: /lib/ali_object.js
* @Description: 阿里云盘基础类
*/
import {_} from "./cat.js";
const UA = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
const CLIENT_ID = "76917ccccd4441c39457a04f6084fb2f";
import * as Utils from "./utils.js";
// 引用会导致出错
// import qs from "qs";
// import axios from "axios";
// import https from "https";
function getHeader() {
const params = {};
params["User-Agent"] = UA;
params.Referer = "https://www.aliyundrive.com/";
return params;
}
class User {
constructor() {
this.driveId = "";
this.userId = "";
this.tokenType = "";
this.accessToken = "";
this.refreshToken = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new User();
}
let resonse = JSON.parse(json_str), user = new User();
user.driveId = resonse.default_drive_id;
user.userId = resonse.user_id;
user.tokenType = resonse.token_type;
user.accessToken = resonse.access_token;
user.refreshToken = resonse.refresh_token; // 刷新Token记录原有的Token
return user;
}
getDriveId() {
return _.isEmpty(this.driveId) ? "" : this.driveId;
}
getUserId() {
return _.isEmpty(this.userId) ? "" : this.userId;
}
getTokenType() {
return _.isEmpty(this.tokenType) ? "" : this.tokenType;
}
getAccessToken() {
return _.isEmpty(this.accessToken) ? "" : this.accessToken;
}
getRefreshToken() {
return _.isEmpty(this.refreshToken) ? "" : this.refreshToken;
}
setRefreshToken(refresh_token) {
this.refreshToken = refresh_token
}
getAuthorization() {
return this.getTokenType() + " " + this.getAccessToken();
}
isAuthed() {
return this.getTokenType().length > 0 && this.getAccessToken().length > 0;
}
clean() {
this.refreshToken = "";
this.accessToken = "";
return this;
}
async save() {
await local.set("ali", "aliyundrive_user", this.toString());
return this;
}
toString() {
return JSON.stringify(this.toDict());
}
toDict() {
return {
default_drive_id: this.getDriveId(),
user_id: this.getUserId(),
token_type: this.getTokenType(),
access_token: this.getAccessToken(),
refresh_token: this.getRefreshToken()
};
}
}
class OAuth {
constructor() {
this.tokenType = "";
this.accessToken = "";
this.refreshToken = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new OAuth();
}
let oauth_json = JSON.parse(json_str), oAuth = new OAuth();
oAuth.tokenType = oauth_json.token_type;
oAuth.accessToken = oauth_json.access_token;
oAuth.refreshToken = oauth_json.refresh_token;
return oAuth;
}
getTokenType() {
return _.isEmpty(this.tokenType) ? "" : this.tokenType;
}
getAccessToken() {
return _.isEmpty(this.accessToken) ? "" : this.accessToken;
}
getRefreshToken() {
return _.isEmpty(this.refreshToken) ? "" : this.refreshToken;
}
getAuthorization() {
return this.getTokenType() + " " + this.getAccessToken();
}
clean() {
this.refreshToken = "";
this.accessToken = "";
return this;
}
async save() {
await local.set("ali", "aliyundrive_oauth", this.toString());
return this;
}
toString() {
return JSON.stringify(this.toDict());
}
toDict() {
return {
token_type: this.getTokenType(), access_token: this.getAccessToken(), refresh_token: this.getRefreshToken()
};
}
}
class Drive {
constructor() {
this.defaultDriveId = "";
this.resourceDriveId = "";
this.backupDriveId = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new Drive();
}
let obj = JSON.parse(json_str), drive = new Drive();
drive.defaultDriveId = obj.default_drive_id;
drive.resourceDriveId = obj.resource_drive_id;
drive.backupDriveId = obj.backup_drive_id;
return drive;
}
getDefaultDriveId() {
return _.isEmpty(this.defaultDriveId) ? "" : this.defaultDriveId;
}
getResourceDriveId() {
return _.isEmpty(this.resourceDriveId) ? "" : this.resourceDriveId;
}
getBackupDriveId() {
return _.isEmpty(this.backupDriveId) ? "" : this.backupDriveId;
}
clean() {
this.defaultDriveId = "";
this.backupDriveId = "";
this.resourceDriveId = "";
return this;
}
async save() {
await local.set("ali", "aliyundrive_drive", this.toString());
return this;
}
toString() {
const params = {
default_drive_id: this.getDefaultDriveId(),
resource_drive_id: this.getResourceDriveId(),
backup_drive_id: this.getBackupDriveId()
};
return JSON.stringify(params);
}
}
class Code {
constructor() {
this.redirectUri = "";
}
static objectFrom(json_str) {
if (_.isEmpty(json_str)) {
return new Code();
}
let code_json = JSON.parse(json_str), code = new Code();
code.redirectUri = code_json.redirectUri;
return code;
}
getRedirectUri() {
return _.isEmpty(this.redirectUri) ? "" : this.redirectUri;
}
getCode() {
return this.getRedirectUri().split("code=")[1];
}
}
class Item {
constructor(file_id) {
this.items = [];
this.nextMarker = "";
this.fileId = file_id;
this.shareId = "";
this.name = "";
this.type = "";
this.fileExtension = "";
this.category = "";
this.size = "";
this.parent = "";
this.shareToken = "";
this.shareIndex = 0;
}
static objectFrom(json_str, shareToken,shareIndex) {
if (_.isEmpty(json_str)) {
return new Item();
}
let item_json = JSON.parse(json_str), item = new Item();
item.nextMarker = typeof item_json.next_marker == "undefined" ? "" : item_json.next_marker;
item.fileId = typeof item_json.file_id == "undefined" ? "" : item_json.file_id;
item.shareId = typeof item_json.share_id == "undefined" ? "" : item_json.share_id;
item.shareToken = shareToken
item.name = typeof item_json.name == "undefined" ? "" : item_json.name;
item.type = typeof item_json.type == "undefined" ? "" : item_json.type;
item.fileExtension = typeof item_json.file_extension == "undefined" ? "" : item_json.file_extension;
item.category = typeof item_json.category == "undefined" ? "" : item_json.category;
item.size = typeof item_json.size == "undefined" ? "" : item_json.size;
item.parent = typeof item_json.parent_file_id == "undefined" ? "" : item_json.parent_file_id;
item.shareIndex = shareIndex
typeof item.items != "undefined" && Array.isArray(item_json.items) && !_.isEmpty(item_json.items) && item_json.items.forEach(function (x) {
let new_item = Item.objectFrom(JSON.stringify((x)), shareToken,shareIndex)
item.items.push(new_item);
});
return item;
}
getItems() {
return _.isEmpty(this.items) ? [] : this.items;
}
getNextMarker() {
return _.isEmpty(this.nextMarker) ? "" : this.nextMarker;
}
getFileId() {
return _.isEmpty(this.fileId) ? "" : this.fileId;
}
getShareId() {
return _.isEmpty(this.shareId) ? "" : this.shareId;
}
getFileExtension() {
return _.isEmpty(this.fileExtension) ? "" : this.fileExtension;
}
getName() {
return _.isEmpty(this.name) ? "" : this.name;
}
getType() {
return _.isEmpty(this.type) ? "" : this.type;
}
getExt() {
return _.isEmpty(this.fileExtension) ? "" : this.fileExtension;
}
getCategory() {
return _.isEmpty(this.category) ? "" : this.category;
}
getSize() {
return this.size === 0 ? "" : "[" + Utils.getSize(this.size) + "]";
}
getParent() {
return _.isEmpty(this.parent) ? "" : "[" + this.parent + "]";
}
getShareIndex(){
return this.shareIndex
}
parentFunc(item) {
this.parent = item;
return this;
}
getDisplayName(type_name) {
let name = this.getName();
name = name.replaceAll("玩偶哥 q 频道:【神秘的哥哥们】", "")
if (type_name === "电视剧") {
let replaceNameList = ["4k", "4K"]
name = name.replaceAll("." + this.getFileExtension(), "")
name = name.replaceAll(" ", "").replaceAll(" ", "")
for (const replaceName of replaceNameList) {
name = name.replaceAll(replaceName, "")
}
name = Utils.getStrByRegexDefault(/\.S01E(.*?)\./, name)
const numbers = name.match(/\d+/g);
if (!_.isEmpty(numbers) && numbers.length > 0) {
name = numbers[0]
}
}
return name + " " + this.getParent() + " " + this.getSize();
}
getEpisodeUrl(type_name){
return this.getDisplayName(type_name) + "$" + this.getFileId() + "+" + this.shareId + "+" + this.shareToken
}
}
class Sub {
constructor() {
this.url = "";
this.name = "";
this.lang = "";
this.format = "";
}
static create() {
return new Sub();
}
setName(name) {
this.name = name;
return this;
}
setUrl(url) {
this.url = url;
return this;
}
setLang(lang) {
this.lang = lang;
return this;
}
setFormat(format) {
this.format = format;
return this;
}
setExt(ext) {
switch (ext) {
case "vtt":
return this.setFormat("text/vtt");
case "ass":
case "ssa":
return this.setFormat("text/x-ssa");
default:
return this.setFormat("application/x-subrip");
}
}
}
async function getUserCache() {
return await local.get("ali", "aliyundrive_user");
}
async function getOAuthCache() {
return await local.get("ali", "aliyundrive_oauth");
}
function getShareId(share_url) {
let patternAli = /https:\/\/www\.alipan\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?|https:\/\/www\.aliyundrive\.com\/s\/([^\\/]+)(\/folder\/([^\\/]+))?/
let matches = patternAli.exec(share_url)
const filteredArr = matches.filter(item => item !== undefined);
if (filteredArr.length > 1) {
return matches[1]
} else {
return ""
}
}
async function ali_request(url, opt) {
let resp;
let data;
try {
data = opt ? opt.data || null : null;
const postType = opt ? opt.postType || null : null;
const returnBuffer = opt ? opt.buffer || 0 : 0;
const timeout = opt ? opt.timeout || 5000 : 5000;
const headers = opt ? opt.headers || {} : {};
if (postType === 'form') {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
if (data != null) {
data = qs.stringify(data, {encode: false});
}
}
let respType = returnBuffer === 1 || returnBuffer === 2 ? 'arraybuffer' : undefined;
resp = await axios(url, {
responseType: respType,
method: opt ? opt.method || 'get' : 'get',
headers: headers,
data: data,
timeout: timeout,
httpsAgent: https.Agent({
rejectUnauthorized: false,
}),
});
data = resp.data;
const resHeader = {};
for (const hks of resp.headers) {
const v = hks[1];
resHeader[hks[0]] = Array.isArray(v) ? (v.length === 1 ? v[0] : v) : v;
}
if (!returnBuffer) {
if (typeof data === 'object') {
data = JSON.stringify(data);
}
} else if (returnBuffer === 1) {
return {code: resp.status, headers: resHeader, content: data};
} else if (returnBuffer === 2) {
return {code: resp.status, headers: resHeader, content: data.toString('base64')};
}
return {code: resp.status, headers: resHeader, content: data};
} catch (error) {
// await Utils.log(`请求失败,URL为:${url},失败原因为:${error}`)
resp = error.response
try {
return {code: resp.status, headers: resp.headers, content: JSON.stringify(resp.data)};
} catch (err) {
return {headers: {}, content: ''};
}
}
}
async function post(url, params) {
url = url.startsWith("https") ? url : "https://api.aliyundrive.com/" + url;
let response = await postJson(url, params, getHeader());
return response.content;
}
async function postJson(url, params, headers) {
params["Content-Type"] = "application/json";
return await req(url, {
headers: headers, method: "post", data: params
});
}
export {
UA,
CLIENT_ID,
OAuth,
Code,
Sub,
User,
Item,
Drive,
getHeader,
getShareId,
getOAuthCache,
getUserCache,
post,
postJson
};

154
JN/CATJS/lib/big5.js Normal file
View File

@ -0,0 +1,154 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, { indexBig5PointerFor, indexCodePointFor } from './text_decoder_indexes.js'
//
// 12. Legacy multi-byte Chinese (traditional) encodings
//
// 12.1 Big5
// 12.1.1 Big5 decoder
/**
* @implements {Decoder}
*/
export class Big5Decoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// Big5's decoder has an associated Big5 lead (initially 0x00).
this.Big5_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and Big5 lead is not 0x00, set
// Big5 lead to 0x00 and return error.
if (bite === end_of_stream && this.Big5_lead !== 0x00) {
this.Big5_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and Big5 lead is 0x00, return
// finished.
if (bite === end_of_stream && this.Big5_lead === 0x00)
return finished
// 3. If Big5 lead is not 0x00, let lead be Big5 lead, let
// pointer be null, set Big5 lead to 0x00, and then run these
// substeps:
if (this.Big5_lead !== 0x00) {
const lead = this.Big5_lead
let pointer = null
this.Big5_lead = 0x00
// 1. Let offset be 0x40 if byte is less than 0x7F and 0x62
// otherwise.
const offset = bite < 0x7F ? 0x40 : 0x62
// 2. If byte is in the range 0x40 to 0x7E, inclusive, or 0xA1
// to 0xFE, inclusive, set pointer to (lead 0x81) × 157 +
// (byte offset).
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0xA1, 0xFE))
pointer = (lead - 0x81) * 157 + (bite - offset)
// 3. If there is a row in the table below whose first column
// is pointer, return the two code points listed in its second
// column
// Pointer | Code points
// --------+--------------
// 1133 | U+00CA U+0304
// 1135 | U+00CA U+030C
// 1164 | U+00EA U+0304
// 1166 | U+00EA U+030C
switch (pointer) {
case 1133: return [0x00CA, 0x0304]
case 1135: return [0x00CA, 0x030C]
case 1164: return [0x00EA, 0x0304]
case 1166: return [0x00EA, 0x030C]
}
// 4. Let code point be null if pointer is null and the index
// code point for pointer in index Big5 otherwise.
const code_point = (pointer === null) ? null :
indexCodePointFor(pointer, index('big5'))
// 5. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (code_point === null && isASCIIByte(bite))
stream.prepend(bite)
// 6. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 7. Return a code point whose value is code point.
return code_point
}
// 4. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 5. If byte is in the range 0x81 to 0xFE, inclusive, set Big5
// lead to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.Big5_lead = bite
return null
}
// 6. Return error.
return decoderError(this.fatal)
}
}
// 12.1.2 Big5 encoder
/**
* @implements {Encoder}
*/
export class Big5Encoder {
constructor() {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
this.handler = function(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. Let pointer be the index Big5 pointer for code point.
const pointer = indexBig5PointerFor(code_point)
// 4. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 5. Let lead be floor(pointer / 157) + 0x81.
const lead = floor(pointer / 157) + 0x81
// 6. If lead is less than 0xA1, return error with code point.
if (lead < 0xA1)
return encoderError(code_point)
// 7. Let trail be pointer % 157.
const trail = pointer % 157
// 8. Let offset be 0x40 if trail is less than 0x3F and 0x62
// otherwise.
const offset = trail < 0x3F ? 0x40 : 0x62
// Return two bytes whose values are lead and trail + offset.
return [lead, trail + offset]
}
}
}

View File

@ -0,0 +1,31 @@
/*
* @File : bilibili_ASS_Danmaku_Downloader.js
* @Author : jade
* @Date : 2024/3/14 13:19
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
function parseXML(json) {
let list = [];
/**
* <d p="{time},{type},{size},{color},{timestamp},{pool},{uid_crc32},{row_id}">
*
* {Text}
* time为弹幕在视频里的时间 -->
* type为弹幕类型 -->
* size为字体大小 -->
* color为十进制的RGB颜色16进制转10进制 -->
* timestamp为弹幕发送时间戳unix时间戳 -->
* pool为弹幕池 -->
* uid_crc32为发送者uid的crc32 -->
*/
Array.from(json.danmuku).forEach(x => {
let start = Number(x[0]);
let content = x[4];
list.push(`<d p="${start},1,25,16777215,1659282294,0,8b53b65c,1108899274487246080"><![CDATA[${content}]]></d>`)
});
return String.raw`<?xml version="1.0" encoding="UTF-8"?><i><chatserver>chat.bilibili.com</chatserver><chatid>52175602</chatid><mission>0</mission><maxlimit>1000</maxlimit><state>0</state><real_name>0</real_name><source>k-v</source>` + list.join('') + "</i>"
}
export {parseXML}

76
JN/CATJS/lib/book.js Normal file
View File

@ -0,0 +1,76 @@
/*
* @File : book.js
* @Author : jade
* @Date : 2024/1/30 17:01
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
export class BookShort {
constructor() {
this.book_id = "" //id
this.book_name = "" //名称
this.book_pic = "" //图片
this.book_remarks = "" //备注
}
to_dict() {
return JSON.stringify(this);
}
load_dic(json_str) {
let obj = JSON.parse(json_str)
for (let propName in obj) {
this[propName] = obj[propName];
}
}
}
export class BookDetail extends BookShort {
/**
* let book = {
* book_name: $('[property$=book_name]')[0].attribs.content,
* book_year: $('[property$=update_time]')[0].attribs.content,
* book_director: $('[property$=author]')[0].attribs.content,
* book_content: $('[property$=description]')[0].attribs.content,
* };
* $ = await this.getHtml(this.siteUrl + id + `list.html`);
* let urls = [];
* const links = $('dl>dd>a[href*="/html/"]');
* for (const l of links) {
* const name = $(l).text().trim();
* const link = l.attribs.href;
* urls.push(name + '$' + link);
* }
* book.volumes = '全卷';
* book.urls = urls.join('#');
* return book
* */
constructor() {
super();
this.book_year = ""
this.book_director = ""
this.book_content = ""
this.volumes = ""
this.urls = ""
}
to_short() {
let bookShort = new BookShort()
bookShort.load_dic(this.to_dict())
return bookShort.to_dict()
}
load_dic(json_str) {
let obj = JSON.parse(json_str)
for (let propName in obj) {
this[propName] = obj[propName];
console.log(propName);//打印👉属性名-->name age gender address
}
}
}

15158
JN/CATJS/lib/cat.js Normal file

File diff suppressed because one or more lines are too long

106
JN/CATJS/lib/cloud.js Normal file
View File

@ -0,0 +1,106 @@
/**
* File: h:\PycharmProjects\Github\TVSpider\lib\cloud.js
* Project: h:\PycharmProjects\Github\TVSpider
* Created Date: Tuesday, May 21st 2024, 2:01:09 pm
* Author: jade
* -----
* Last Modified: Tue May 21 2024
* Modified By: jade
* -----
* Copyright (c) 2024 samples
* ------------------------------------
* Javascript will save your soul!
*/
import {initAli,detailContentAli,playContentAli, aliPlayFormatList,aliName} from "./ali.js"
import { initQuark,detailContentQuark,playContentQuark,quarkPlayFormatList,quarkName,getQuarkHeaders} from "./quark.js"
import * as Utils from "./utils.js";
import {_} from "../lib/cat.js";
async function initCloud(cfg){
initAli(cfg["aliToken"])
initQuark(cfg["quarkCookie"])
}
async function detailContent(share_url_list,type_name="电影"){
let ali_share_url_list = [],quark_share_url_list = []
const playVod = {}
for (const shareUrl of share_url_list){
let aliMatches = shareUrl.match(Utils.patternAli);
if (!_.isEmpty(aliMatches)) {
ali_share_url_list.push(aliMatches[1])
}
let quarkMatches = shareUrl.match(Utils.patternQuark);
if (!_.isEmpty(quarkMatches)){
quark_share_url_list.push(quarkMatches[1])
}
}
let aliItems = await detailContentAli(ali_share_url_list)
let quarkItems = await detailContentQuark(quark_share_url_list)
await getVod(aliPlayFormatList,aliName,playVod,aliItems.video_items,aliItems.sub_items,type_name)
await getVod(quarkPlayFormatList,quarkName,playVod,quarkItems.video_items,quarkItems.sub_items,type_name)
return playVod
}
async function getVod(play_foramt_list,cloud_name,playVod,video_item_list, sub_item_list, type_name) {
if (video_item_list.length ==0){
return
}
for (let i=0; i<video_item_list.slice(-1)[0].shareIndex;i++){
for (let index = 0; index < play_foramt_list.length; index++) {
let vodItems = []
for (const video_item of video_item_list) {
if (video_item.shareIndex === i + 1){
vodItems.push( video_item.getEpisodeUrl(type_name)+ findSubs(video_item.getName(), sub_item_list)); }
}
playVod[`${cloud_name}-${i+1}-${play_foramt_list[index]}`] = vodItems.join("#")
}
}
}
//字幕匹配
function pair(name, item_list, sub_item_list) {
for (const item of item_list) {
const sub_name = Utils.removeExt(item.getName()).toLowerCase();
if (name.indexOf(sub_name) > -1 || sub_name.indexOf(name) > -1) {
sub_item_list.push(item);
}
}
}
//找出所有字幕
function findSubs(name, item_list) {
let sub_item_list = [];
pair(Utils.removeExt(name).toLowerCase(), item_list, sub_item_list);
if (sub_item_list.length === 0) {
for (const item of item_list) {
sub_item_list.push(item);
}
}
let sub_str = "";
for (const item of sub_item_list) {
sub_str += "+" + Utils.removeExt(item.getName()) + "@@@" + item.getExt() + "@@@" + item.getFileId();
}
return sub_str;
}
async function playContent(flag,id,flags){
if (flag.indexOf(aliName) > -1) {
return await playContentAli(flag, id, flags)
}else if (flag.indexOf(quarkName) > -1){
return await playContentQuark(flag,id,flags)
}
}
function getHeaders(flag){
if (flag.indexOf(aliName) > -1) {
return {}
}else if (flag.indexOf(quarkName) > -1){
return getQuarkHeaders()
}
}
export {initCloud,detailContent,playContent,getHeaders,aliName,quarkName}

188
JN/CATJS/lib/danmuSpider.js Normal file
View File

@ -0,0 +1,188 @@
/*
* @File : danmuSpider.js
* @Author : jade
* @Date : 2024/3/13 13:39
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {_, load, Uri} from "./cat.js";
import * as Utils from "./utils.js";
import {JadeLogging} from "./log.js";
import {VodDetail, VodShort} from "./vod.js";
import {parseXML} from "./bilibili_ASS_Danmaku_Downloader.js";
class DanmuSpider {
constructor() {
this.siteUrl = "https://search.youku.com"
this.reconnectTimes = 0
this.maxReconnectTimes = 5
this.jadeLog = new JadeLogging(this.getAppName(), "DEBUG")
}
getAppName() {
return "弹幕"
}
getHeader() {
return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/"};
}
async reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer) {
await this.jadeLog.error("请求失败,请检查url:" + reqUrl + ",两秒后重试")
Utils.sleep(2)
if (this.reconnectTimes < this.maxReconnectTimes) {
this.reconnectTimes = this.reconnectTimes + 1
return await this.fetch(reqUrl, params, headers, redirect_url, return_cookie, buffer)
} else {
await this.jadeLog.error("请求失败,重连失败")
return null
}
}
async getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response) {
{
if (response.headers["location"] !== undefined) {
if (redirect_url) {
await this.jadeLog.debug(`返回重定向连接:${response.headers["location"]}`)
return response.headers["location"]
} else {
return this.fetch(response.headers["location"], params, headers, redirect_url, return_cookie, buffer)
}
} else if (response.content.length > 0) {
this.reconnectTimes = 0
if (return_cookie) {
return {"cookie": response.headers["set-cookie"], "content": response.content}
} else {
return response.content
}
} else if (buffer === 1) {
this.reconnectTimes = 0
return response.content
} else {
await this.jadeLog.error(`请求失败,请求url为:${reqUrl},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
}
}
}
async fetch(reqUrl, params, headers, redirect_url = false, return_cookie = false, buffer = 0) {
let data = Utils.objectToStr(params)
let url = reqUrl
if (!_.isEmpty(data)) {
url = reqUrl + "?" + data
}
let uri = new Uri(url);
let response;
response = await req(uri.toString(), {method: "get", headers: headers, buffer: buffer, data: null})
if (response.code === 201 || response.code === 200 || response.code === 302 || response.code === 301 || return_cookie) {
return await this.getResponse(reqUrl, params, headers, redirect_url, return_cookie, buffer, response)
} else {
await this.jadeLog.error(`请求失败,失败原因为:状态码出错,请求url为:${uri},回复内容为:${JSON.stringify(response)}`)
return await this.reconnnect(reqUrl, params, headers, redirect_url, return_cookie, buffer)
}
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
let html = await this.fetch(url, null, headers)
if (!_.isEmpty(html)) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
async parseVodShortListFromJson(obj, vodDetail) {
for (const componentObj of obj["pageComponentList"]) {
if (componentObj["commonData"] !== undefined) {
let searchVodDetail = new VodDetail()
let commonData = componentObj["commonData"]
searchVodDetail.type_name = commonData["feature"]
if (commonData["notice"] !== undefined) {
searchVodDetail.vod_actor = commonData["notice"].replaceAll("演员:", "").replaceAll(" ", "")
}
if (commonData["director"] !== undefined) {
searchVodDetail.vod_director = commonData["director"].replaceAll("导演:", "").replaceAll(" ", "")
}
if (vodDetail.type_name === "电影") {
searchVodDetail.vod_id = commonData["leftButtonDTO"]["action"]["value"]
} else {
searchVodDetail.vod_id = commonData["showId"]
}
searchVodDetail.vod_name = commonData["titleDTO"]["displayName"]
if ( searchVodDetail.vod_name === vodDetail.vod_name || searchVodDetail.type_name.indexOf(vodDetail.vod_year) > -1 || searchVodDetail.type_name.indexOf(vodDetail.type_name) > -1 || searchVodDetail.vod_director === vodDetail.vod_director) {
await this.jadeLog.debug(`匹配视频网站成功,名称为:${searchVodDetail.vod_name},类型为:${searchVodDetail.type_name},导演为:${searchVodDetail.vod_director}`, true)
return searchVodDetail
}
}
}
await this.jadeLog.warning("没有匹配到弹幕网站")
return null
}
async parseVodUrlFromJsonByEpisodeId(obj, episodeId) {
for (const serises of obj["serisesList"]) {
if (Utils.isNumeric(episodeId["episodeId"])) {
if (parseInt(episodeId["episodeId"]).toString() === serises["displayName"]) {
return serises["action"]["value"]
}
}
}
await this.jadeLog.error("没有找到匹配的集数")
return ""
}
async downloadDanmu(url) {
// 如果没有找到弹幕的话,容易导致卡在这一步,从而导致结果加载不出来
let response = await req(url,{headers:this.getHeader()})
if (response.code === 200){
let xml = parseXML(JSON.parse(response.content))
let params = {"do": "set", "key": "danmu", "value": xml}
await req("http://127.0.0.1:9978/cache", {method: "post", data: params, postType: "form-data"});
return "http://127.0.0.1:9978/cache?do=get&key=danmu"
}
else{
this.jadeLog.error(`弹幕请求失败,返回结果为:${JSON.stringify(response)}`)
return ""
}
}
async search(vodDetail, episodeId) {
let params = {"pg": "1", "keyword": vodDetail.vod_name}
let searchObj = JSON.parse(await this.fetch(this.siteUrl + "/api/search", params, this.getHeader()))
let searchDetail = await this.parseVodShortListFromJson(searchObj, vodDetail)
if (!_.isEmpty(searchDetail)){
return await this.getVideoUrl(searchDetail.vod_id, episodeId)
}else{
return ""
}
}
async getVideoUrl(showId, episodeId) {
let url = "";
if (!_.isEmpty(showId)) {
if (showId.startsWith("http")) {
url = showId
} else {
let params = {"appScene": "show_episode", "showIds": showId}
let matchObj = JSON.parse(await this.fetch(this.siteUrl + "/api/search", params, this.getHeader()))
url = await this.parseVodUrlFromJsonByEpisodeId(matchObj, episodeId)
}
if (!_.isEmpty(url)) {
await this.jadeLog.debug(`弹幕视频播放连接为:${url}`)
return await this.downloadDanmu("https://dmku.thefilehosting.com/?ac=dm&url=" + url)
}
}
return url
}
async getDammu(voddetail, episodeId) {
return await this.search(voddetail, episodeId)
}
}
export {DanmuSpider}

File diff suppressed because one or more lines are too long

460
JN/CATJS/lib/encodings.js Normal file
View File

@ -0,0 +1,460 @@
/**
* Encodings table: https://encoding.spec.whatwg.org/encodings.json
*/
const encodings = [
{
encodings: [
{
labels: [
"unicode-1-1-utf-8",
"utf-8",
"utf8",
],
name: "UTF-8",
},
],
heading: "The Encoding",
},
{
encodings: [
{
labels: [
"866",
"cp866",
"csibm866",
"ibm866",
],
name: "IBM866",
},
{
labels: [
"csisolatin2",
"iso-8859-2",
"iso-ir-101",
"iso8859-2",
"iso88592",
"iso_8859-2",
"iso_8859-2:1987",
"l2",
"latin2",
],
name: "ISO-8859-2",
},
{
labels: [
"csisolatin3",
"iso-8859-3",
"iso-ir-109",
"iso8859-3",
"iso88593",
"iso_8859-3",
"iso_8859-3:1988",
"l3",
"latin3",
],
name: "ISO-8859-3",
},
{
labels: [
"csisolatin4",
"iso-8859-4",
"iso-ir-110",
"iso8859-4",
"iso88594",
"iso_8859-4",
"iso_8859-4:1988",
"l4",
"latin4",
],
name: "ISO-8859-4",
},
{
labels: [
"csisolatincyrillic",
"cyrillic",
"iso-8859-5",
"iso-ir-144",
"iso8859-5",
"iso88595",
"iso_8859-5",
"iso_8859-5:1988",
],
name: "ISO-8859-5",
},
{
labels: [
"arabic",
"asmo-708",
"csiso88596e",
"csiso88596i",
"csisolatinarabic",
"ecma-114",
"iso-8859-6",
"iso-8859-6-e",
"iso-8859-6-i",
"iso-ir-127",
"iso8859-6",
"iso88596",
"iso_8859-6",
"iso_8859-6:1987",
],
name: "ISO-8859-6",
},
{
labels: [
"csisolatingreek",
"ecma-118",
"elot_928",
"greek",
"greek8",
"iso-8859-7",
"iso-ir-126",
"iso8859-7",
"iso88597",
"iso_8859-7",
"iso_8859-7:1987",
"sun_eu_greek",
],
name: "ISO-8859-7",
},
{
labels: [
"csiso88598e",
"csisolatinhebrew",
"hebrew",
"iso-8859-8",
"iso-8859-8-e",
"iso-ir-138",
"iso8859-8",
"iso88598",
"iso_8859-8",
"iso_8859-8:1988",
"visual",
],
name: "ISO-8859-8",
},
{
labels: [
"csiso88598i",
"iso-8859-8-i",
"logical",
],
name: "ISO-8859-8-I",
},
{
labels: [
"csisolatin6",
"iso-8859-10",
"iso-ir-157",
"iso8859-10",
"iso885910",
"l6",
"latin6",
],
name: "ISO-8859-10",
},
{
labels: [
"iso-8859-13",
"iso8859-13",
"iso885913",
],
name: "ISO-8859-13",
},
{
labels: [
"iso-8859-14",
"iso8859-14",
"iso885914",
],
name: "ISO-8859-14",
},
{
labels: [
"csisolatin9",
"iso-8859-15",
"iso8859-15",
"iso885915",
"iso_8859-15",
"l9",
],
name: "ISO-8859-15",
},
{
labels: [
"iso-8859-16",
],
name: "ISO-8859-16",
},
{
labels: [
"cskoi8r",
"koi",
"koi8",
"koi8-r",
"koi8_r",
],
name: "KOI8-R",
},
{
labels: [
"koi8-ru",
"koi8-u",
],
name: "KOI8-U",
},
{
labels: [
"csmacintosh",
"mac",
"macintosh",
"x-mac-roman",
],
name: "macintosh",
},
{
labels: [
"dos-874",
"iso-8859-11",
"iso8859-11",
"iso885911",
"tis-620",
"windows-874",
],
name: "windows-874",
},
{
labels: [
"cp1250",
"windows-1250",
"x-cp1250",
],
name: "windows-1250",
},
{
labels: [
"cp1251",
"windows-1251",
"x-cp1251",
],
name: "windows-1251",
},
{
labels: [
"ansi_x3.4-1968",
"ascii",
"cp1252",
"cp819",
"csisolatin1",
"ibm819",
"iso-8859-1",
"iso-ir-100",
"iso8859-1",
"iso88591",
"iso_8859-1",
"iso_8859-1:1987",
"l1",
"latin1",
"us-ascii",
"windows-1252",
"x-cp1252",
],
name: "windows-1252",
},
{
labels: [
"cp1253",
"windows-1253",
"x-cp1253",
],
name: "windows-1253",
},
{
labels: [
"cp1254",
"csisolatin5",
"iso-8859-9",
"iso-ir-148",
"iso8859-9",
"iso88599",
"iso_8859-9",
"iso_8859-9:1989",
"l5",
"latin5",
"windows-1254",
"x-cp1254",
],
name: "windows-1254",
},
{
labels: [
"cp1255",
"windows-1255",
"x-cp1255",
],
name: "windows-1255",
},
{
labels: [
"cp1256",
"windows-1256",
"x-cp1256",
],
name: "windows-1256",
},
{
labels: [
"cp1257",
"windows-1257",
"x-cp1257",
],
name: "windows-1257",
},
{
labels: [
"cp1258",
"windows-1258",
"x-cp1258",
],
name: "windows-1258",
},
{
labels: [
"x-mac-cyrillic",
"x-mac-ukrainian",
],
name: "x-mac-cyrillic",
},
],
heading: "Legacy single-byte encodings",
},
{
encodings: [
{
labels: [
"chinese",
"csgb2312",
"csiso58gb231280",
"gb2312",
"gb_2312",
"gb_2312-80",
"gbk",
"iso-ir-58",
"x-gbk",
],
name: "GBK",
},
{
labels: [
"gb18030",
],
name: "gb18030",
},
],
heading: "Legacy multi-byte Chinese (simplified) encodings",
},
{
encodings: [
{
labels: [
"big5",
"big5-hkscs",
"cn-big5",
"csbig5",
"x-x-big5",
],
name: "Big5",
},
],
heading: "Legacy multi-byte Chinese (traditional) encodings",
},
{
encodings: [
{
labels: [
"cseucpkdfmtjapanese",
"euc-jp",
"x-euc-jp",
],
name: "EUC-JP",
},
{
labels: [
"csiso2022jp",
"iso-2022-jp",
],
name: "ISO-2022-JP",
},
{
labels: [
"csshiftjis",
"ms932",
"ms_kanji",
"shift-jis",
"shift_jis",
"sjis",
"windows-31j",
"x-sjis",
],
name: "Shift_JIS",
},
],
heading: "Legacy multi-byte Japanese encodings",
},
{
encodings: [
{
labels: [
"cseuckr",
"csksc56011987",
"euc-kr",
"iso-ir-149",
"korean",
"ks_c_5601-1987",
"ks_c_5601-1989",
"ksc5601",
"ksc_5601",
"windows-949",
],
name: "EUC-KR",
},
],
heading: "Legacy multi-byte Korean encodings",
},
{
encodings: [
{
labels: [
"csiso2022kr",
"hz-gb-2312",
"iso-2022-cn",
"iso-2022-cn-ext",
"iso-2022-kr",
],
name: "replacement",
},
{
labels: [
"utf-16be",
],
name: "UTF-16BE",
},
{
labels: [
"utf-16",
"utf-16le",
],
name: "UTF-16LE",
},
{
labels: [
"x-user-defined",
],
name: "x-user-defined",
},
],
heading: "Legacy miscellaneous encodings",
},
]
export default encodings

166
JN/CATJS/lib/euc-jp.js Normal file
View File

@ -0,0 +1,166 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
//
// 13. Legacy multi-byte Japanese encodings
//
// 13.1 euc-jp
// 13.1.1 euc-jp decoder
/**
* @implements {Decoder}
*/
export class EUCJPDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// euc-jp's decoder has an associated euc-jp jis0212 flag
// (initially unset) and euc-jp lead (initially 0x00).
this.eucjp_jis0212_flag = false
this.eucjp_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and euc-jp lead is not 0x00, set
// euc-jp lead to 0x00, and return error.
if (bite === end_of_stream && this.eucjp_lead !== 0x00) {
this.eucjp_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and euc-jp lead is 0x00, return
// finished.
if (bite === end_of_stream && this.eucjp_lead === 0x00)
return finished
// 3. If euc-jp lead is 0x8E and byte is in the range 0xA1 to
// 0xDF, inclusive, set euc-jp lead to 0x00 and return a code
// point whose value is 0xFF61 0xA1 + byte.
if (this.eucjp_lead === 0x8E && inRange(bite, 0xA1, 0xDF)) {
this.eucjp_lead = 0x00
return 0xFF61 - 0xA1 + bite
}
// 4. If euc-jp lead is 0x8F and byte is in the range 0xA1 to
// 0xFE, inclusive, set the euc-jp jis0212 flag, set euc-jp lead
// to byte, and return continue.
if (this.eucjp_lead === 0x8F && inRange(bite, 0xA1, 0xFE)) {
this.eucjp_jis0212_flag = true
this.eucjp_lead = bite
return null
}
// 5. If euc-jp lead is not 0x00, let lead be euc-jp lead, set
// euc-jp lead to 0x00, and run these substeps:
if (this.eucjp_lead !== 0x00) {
const lead = this.eucjp_lead
this.eucjp_lead = 0x00
// 1. Let code point be null.
let code_point = null
// 2. If lead and byte are both in the range 0xA1 to 0xFE,
// inclusive, set code point to the index code point for (lead
// 0xA1) × 94 + byte 0xA1 in index jis0208 if the euc-jp
// jis0212 flag is unset and in index jis0212 otherwise.
if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) {
code_point = indexCodePointFor(
(lead - 0xA1) * 94 + (bite - 0xA1),
index(!this.eucjp_jis0212_flag ? 'jis0208' : 'jis0212'))
}
// 3. Unset the euc-jp jis0212 flag.
this.eucjp_jis0212_flag = false
// 4. If byte is not in the range 0xA1 to 0xFE, inclusive,
// prepend byte to stream.
if (!inRange(bite, 0xA1, 0xFE))
stream.prepend(bite)
// 5. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 6. Return a code point whose value is code point.
return code_point
}
// 6. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 7. If byte is 0x8E, 0x8F, or in the range 0xA1 to 0xFE,
// inclusive, set euc-jp lead to byte and return continue.
if (bite === 0x8E || bite === 0x8F || inRange(bite, 0xA1, 0xFE)) {
this.eucjp_lead = bite
return null
}
// 8. Return error.
return decoderError(this.fatal)
}
}
// 13.1.2 euc-jp encoder
/**
* @implements {Encoder}
*/
export class EUCJPEncoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. If code point is U+00A5, return byte 0x5C.
if (code_point === 0x00A5)
return 0x5C
// 4. If code point is U+203E, return byte 0x7E.
if (code_point === 0x203E)
return 0x7E
// 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
// return two bytes whose values are 0x8E and code point
// 0xFF61 + 0xA1.
if (inRange(code_point, 0xFF61, 0xFF9F))
return [0x8E, code_point - 0xFF61 + 0xA1]
// 6. If code point is U+2212, set it to U+FF0D.
if (code_point === 0x2212)
code_point = 0xFF0D
// 7. Let pointer be the index pointer for code point in index
// jis0208.
const pointer = indexPointerFor(code_point, index('jis0208'))
// 8. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 9. Let lead be floor(pointer / 94) + 0xA1.
const lead = floor(pointer / 94) + 0xA1
// 10. Let trail be pointer % 94 + 0xA1.
const trail = pointer % 94 + 0xA1
// 11. Return two bytes whose values are lead and trail.
return [lead, trail]
}
}

124
JN/CATJS/lib/euc-kr.js Normal file
View File

@ -0,0 +1,124 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
//
// 14. Legacy multi-byte Korean encodings
//
// 14.1 euc-kr
// 14.1.1 euc-kr decoder
/**
* @implements {Decoder}
*/
export class EUCKRDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// euc-kr's decoder has an associated euc-kr lead (initially 0x00).
this.euckr_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and euc-kr lead is not 0x00, set
// euc-kr lead to 0x00 and return error.
if (bite === end_of_stream && this.euckr_lead !== 0) {
this.euckr_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and euc-kr lead is 0x00, return
// finished.
if (bite === end_of_stream && this.euckr_lead === 0)
return finished
// 3. If euc-kr lead is not 0x00, let lead be euc-kr lead, let
// pointer be null, set euc-kr lead to 0x00, and then run these
// substeps:
if (this.euckr_lead !== 0x00) {
const lead = this.euckr_lead
let pointer = null
this.euckr_lead = 0x00
// 1. If byte is in the range 0x41 to 0xFE, inclusive, set
// pointer to (lead 0x81) × 190 + (byte 0x41).
if (inRange(bite, 0x41, 0xFE))
pointer = (lead - 0x81) * 190 + (bite - 0x41)
// 2. Let code point be null, if pointer is null, and the
// index code point for pointer in index euc-kr otherwise.
const code_point = (pointer === null)
? null : indexCodePointFor(pointer, index('euc-kr'))
// 3. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (pointer === null && isASCIIByte(bite))
stream.prepend(bite)
// 4. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 5. Return a code point whose value is code point.
return code_point
}
// 4. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 5. If byte is in the range 0x81 to 0xFE, inclusive, set
// euc-kr lead to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.euckr_lead = bite
return null
}
// 6. Return error.
return decoderError(this.fatal)
}
}
// 14.1.2 euc-kr encoder
/**
* @implements {Encoder}
*/
export class EUCKREncoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return {(number|!Array.<number>)} Byte(s) to emit.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. Let pointer be the index pointer for code point in index
// euc-kr.
const pointer = indexPointerFor(code_point, index('euc-kr'))
// 4. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 5. Let lead be floor(pointer / 190) + 0x81.
const lead = floor(pointer / 190) + 0x81
// 6. Let trail be pointer % 190 + 0x41.
const trail = (pointer % 190) + 0x41
// 7. Return two bytes whose values are lead and trail.
return [lead, trail]
}
}

480
JN/CATJS/lib/ffm3u8_open.js Normal file
View File

@ -0,0 +1,480 @@
/*
* @File : ffm3u8_open.js.js
* @Author : jade
* @Date : 2024/2/5 16:06
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import { _ } from './cat.js';
import * as HLS from './hls.js';
let key = 'ffm3u8';
let url = '';
let categories = [];
let siteKey = '';
let siteType = 0;
async function request(reqUrl, agentSp) {
let res = await req(reqUrl, {
method: 'get',
});
return JSON.parse(res.content);
}
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
url = cfg.ext.url;
categories = cfg.ext.categories;
}
async function home(filter) {
const data = await request(url);
let classes = [];
for (const cls of data.class) {
const n = cls.type_name.toString().trim();
if (categories && categories.length > 0) {
if (categories.indexOf(n) < 0) continue;
}
classes.push({
type_id: cls.type_id.toString(),
type_name: n,
});
}
if (categories && categories.length > 0) {
classes = _.sortBy(classes, (p) => {
return categories.indexOf(p.type_name);
});
}
return {
class: classes,
};
}
async function homeVod() {
return '{}';
}
async function category(tid, pg, filter, extend) {
let page = pg || 1;
if (page == 0) page = 1;
const data = await request(url + `?ac=detail&t=${tid}&pg=${page}`);
let videos = [];
for (const vod of data.list) {
videos.push({
vod_id: vod.vod_id.toString(),
vod_name: vod.vod_name.toString(),
vod_pic: vod.vod_pic,
vod_remarks: vod.vod_remarks,
});
}
return {
page: parseInt(data.page),
pagecount: data.pagecount,
total: data.total,
list: videos,
};
}
async function detail(id) {
const data = (await request(url + `?ac=detail&ids=${id}`)).list[0];
let vod = {
vod_id: data.vod_id,
vod_name: data.vod_name,
vod_pic: data.vod_pic,
type_name: data.type_name,
vod_year: data.vod_year,
vod_area: data.vod_area,
vod_remarks: data.vod_remarks,
vod_actor: data.vod_actor,
vod_director: data.vod_director,
vod_content: data.vod_content.trim(),
vod_play_from: data.vod_play_from,
vod_play_url: data.vod_play_url,
};
return {
list: [vod],
};
}
async function proxy(segments, headers, reqHeaders) {
let what = segments[0];
let segs = decodeURIComponent(segments[1]);
if (what == 'hls') {
function hlsHeader(data, hls) {
let hlsHeaders = {};
if (data.headers['content-length']) {
Object.assign(hlsHeaders, data.headers, { 'content-length': hls.length.toString() });
} else {
Object.assign(hlsHeaders, data.headers);
}
delete hlsHeaders['transfer-encoding'];
if (hlsHeaders['content-encoding'] == 'gzip') {
delete hlsHeaders['content-encoding'];
}
return hlsHeaders;
}
const hlsData = await hlsCache(segs, headers);
if (hlsData.variants) {
// variants -> variants -> .... ignore
const hls = HLS.stringify(hlsData.plist);
return {
code: hlsData.code,
content: hls,
headers: hlsHeader(hlsData, hls),
};
} else {
const hls = HLS.stringify(hlsData.plist, (segment) => {
return js2Proxy(false, siteType, siteKey, 'ts/' + encodeURIComponent(hlsData.key + '/' + segment.mediaSequenceNumber.toString()), headers);
});
return {
code: hlsData.code,
content: hls,
headers: hlsHeader(hlsData, hls),
};
}
} else if (what == 'ts') {
const info = segs.split('/');
const hlsKey = info[0];
const segIdx = parseInt(info[1]);
return await tsCache(hlsKey, segIdx, headers);
}
return '{}';
}
async function play(flag, id, flags) {
try {
const pUrls = await hls2Urls(id, {});
for (let index = 1; index < pUrls.length; index += 2) {
pUrls[index] = js2Proxy(false, siteType, siteKey, 'hls/' + encodeURIComponent(pUrls[index]), {});
}
pUrls.push('original');
pUrls.push(id);
return {
parse: 0,
url: pUrls,
};
} catch (e) {
return {
parse: 0,
url: id,
};
}
}
async function search(wd, quick, pg) {
let page = pg || 1;
if (page == 0) page = 1;
const data = await request(url + `?ac=detail&wd=${wd}`);
let videos = [];
for (const vod of data.list) {
videos.push({
vod_id: vod.vod_id.toString(),
vod_name: vod.vod_name.toString(),
vod_pic: vod.vod_pic,
vod_remarks: vod.vod_remarks,
});
}
return {
page: parseInt(data.page),
pagecount: data.pagecount,
total: data.total,
list: videos,
};
}
const cacheRoot = 'hls_cache';
const hlsKeys = [];
const hlsPlistCaches = {};
const interrupts = {};
const downloadTask = {};
let currentDownloadHlsKey = '';
function hlsCacheInsert(key, data) {
hlsKeys.push(key);
hlsPlistCaches[key] = data;
if (hlsKeys.length > 5) {
const rmKey = hlsKeys.shift();
hlsCacheRemove(rmKey);
}
}
function hlsCacheRemove(key) {
delete hlsPlistCaches[key];
delete hlsKeys[key];
new JSFile(cacheRoot + '/' + key).delete();
}
function plistUriResolve(baseUrl, plist) {
if (plist.variants) {
for (const v of plist.variants) {
if (!v.uri.startsWith('http')) {
v.uri = relative2Absolute(baseUrl, v.uri);
}
}
}
if (plist.segments) {
for (const s of plist.segments) {
if (!s.uri.startsWith('http')) {
s.uri = relative2Absolute(baseUrl, s.uri);
}
if (s.key && s.key.uri && !s.key.uri.startsWith('http')) {
s.key.uri = relative2Absolute(baseUrl, s.key.uri);
}
}
}
return plist;
}
async function hls2Urls(url, headers) {
let urls = [];
let resp = {};
let tmpUrl = url;
while (true) {
resp = await req(tmpUrl, {
headers: headers,
redirect: 0,
});
if (resp.headers['location']) {
tmpUrl = resp.headers['location'];
} else {
break;
}
}
if (resp.code == 200) {
var hls = resp.content;
const plist = plistUriResolve(tmpUrl, HLS.parse(hls));
if (plist.variants) {
for (const vari of _.sortBy(plist.variants, (v) => -1 * v.bandwidth)) {
urls.push(`proxy_${vari.resolution.width}x${vari.resolution.height}`);
urls.push(vari.uri);
}
} else {
urls.push('proxy');
urls.push(url);
const hlsKey = md5X(url);
hlsCacheInsert(hlsKey, {
code: resp.code,
plist: plist,
key: hlsKey,
headers: resp.headers,
});
}
}
return urls;
}
async function hlsCache(url, headers) {
const hlsKey = md5X(url);
if (hlsPlistCaches[hlsKey]) {
return hlsPlistCaches[hlsKey];
}
let resp = {};
let tmpUrl = url;
while (true) {
resp = await req(tmpUrl, {
headers: headers,
redirect: 0,
});
if (resp.headers['location']) {
tmpUrl = resp.headers['location'];
} else {
break;
}
}
if (resp.code == 200) {
var hls = resp.content;
const plist = plistUriResolve(tmpUrl, HLS.parse(hls));
hlsCacheInsert(hlsKey, {
code: resp.code,
plist: plist,
key: hlsKey,
headers: resp.headers,
});
return hlsPlistCaches[hlsKey];
}
return {};
}
async function tsCache(hlsKey, segmentIndex, headers) {
if (!hlsPlistCaches[hlsKey]) {
return {};
}
const plist = hlsPlistCaches[hlsKey].plist;
const segments = plist.segments;
let startFirst = !downloadTask[hlsKey];
if (startFirst) {
downloadTask[hlsKey] = {};
for (const seg of segments) {
const tk = md5X(seg.uri + seg.mediaSequenceNumber.toString());
downloadTask[hlsKey][tk] = {
file: cacheRoot + '/' + hlsKey + '/' + tk,
uri: seg.uri,
key: tk,
index: seg.mediaSequenceNumber,
order: seg.mediaSequenceNumber,
state: -1,
read: false,
};
}
}
// sort task
for (const tk in downloadTask[hlsKey]) {
const task = downloadTask[hlsKey][tk];
if (task.index >= segmentIndex) {
task.order = task.index - segmentIndex;
} else {
task.order = segments.length - segmentIndex + task.index;
}
}
if (startFirst) {
fixedCachePool(hlsKey, 5, headers);
}
const segment = segments[segmentIndex];
const tsKey = md5X(segment.uri + segment.mediaSequenceNumber.toString());
const task = downloadTask[hlsKey][tsKey];
if (task.state == 1 || task.state == -1) {
const file = new JSFile(task.file);
if (await file.exist()) {
task.state = 1;
// download finish
return {
buffer: 3,
code: 200,
headers: {
connection: 'close',
'content-type': 'video/mp2t',
},
content: file,
};
} else {
// file miss?? retry
task.state = -1;
}
}
if (task.state == -1) {
// start download
startTsTask(hlsKey, task, headers);
}
// wait read dwonload
if (task.state == 0) {
var stream = new JSProxyStream();
stream.head(200, {
connection: 'close',
'content-type': 'video/mp2t',
});
let downloaded = 0;
task.read = true;
new Promise(async function (resolve, reject) {
const f = new JSFile(task.file + '.dl');
await f.open('r');
(async function waitReadFile() {
const s = await f.size();
if (s > downloaded) {
var downloadBuf = await f.read(s - downloaded, downloaded);
await stream.write(downloadBuf);
downloaded = s;
}
if (task.state == 1 || task.state < 0) {
// finish error or done
stream.done();
await f.close();
await f.delete();
task.read = false;
resolve();
return;
}
setTimeout(waitReadFile, 5);
})();
});
return {
buffer: 3,
content: stream,
};
}
}
async function startTsTask(hlsKey, task, headers) {
if (task.state >= 0) return;
if (!interrupts[hlsKey]) {
return;
}
task.state = 0;
if (await new JSFile(task.file).exist()) {
task.state = 1;
return;
}
const file = new JSFile(task.file + '.dl');
await file.open('w');
const resp = await req(task.uri, {
buffer: 3,
headers: headers,
stream: file,
timeout: [5000, 10000],
});
if (resp.error || resp.code >= 300) {
await file.close();
if (!task.read) {
await file.delete();
}
task.state = -1;
return;
}
await file.close();
if (task.read) {
await file.copy(task.file);
} else {
await file.move(task.file);
}
task.state = 1;
}
async function fixedCachePool(hlsKey, limit, headers) {
// keep last cache task only
if (currentDownloadHlsKey && currentDownloadHlsKey != hlsKey) {
delete interrupts[currentDownloadHlsKey];
}
currentDownloadHlsKey = hlsKey;
interrupts[hlsKey] = true;
for (let index = 0; index < limit; index++) {
if (!interrupts[hlsKey]) break;
new Promise(function (resolve, reject) {
(async function doTask() {
if (!interrupts[hlsKey]) {
resolve();
return;
}
const tasks = _.pickBy(downloadTask[hlsKey], function (o) {
return o.state == -1;
});
const task = _.minBy(Object.values(tasks), function (o) {
return o.order;
});
if (!task) {
resolve();
return;
}
await startTsTask(hlsKey, task, headers);
setTimeout(doTask, 5);
})();
});
}
}
function relative2Absolute(base, relative) {
var stack = base.split('/'),
parts = relative.split('/');
stack.pop();
for (var i = 0; i < parts.length; i++) {
if (parts[i] == '.') continue;
if (parts[i] == '..') stack.pop();
else stack.push(parts[i]);
}
return stack.join('/');
}
export {hls2Urls,hlsCache,tsCache}

251
JN/CATJS/lib/gb18030.js Normal file
View File

@ -0,0 +1,251 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, isASCIIByte, floor } from './text_decoder_utils.js'
import index, {
indexGB18030RangesCodePointFor, indexGB18030RangesPointerFor,
indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
// 11.2 gb18030
// 11.2.1 gb18030 decoder
/**
* @constructor
* @implements {Decoder}
* @param {{fatal: boolean}} options
*/
export class GB18030Decoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// gb18030's decoder has an associated gb18030 first, gb18030
// second, and gb18030 third (all initially 0x00).
this.gb18030_first = 0x00
this.gb18030_second = 0x00,
this.gb18030_third = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
* @return The next code point(s) decoded, or null if not enough data exists in the input stream to decode a complete code point.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and gb18030 first, gb18030
// second, and gb18030 third are 0x00, return finished.
if (bite === end_of_stream && this.gb18030_first === 0x00 &&
this.gb18030_second === 0x00 && this.gb18030_third === 0x00) {
return finished
}
// 2. If byte is end-of-stream, and gb18030 first, gb18030
// second, or gb18030 third is not 0x00, set gb18030 first,
// gb18030 second, and gb18030 third to 0x00, and return error.
if (bite === end_of_stream &&
(this.gb18030_first !== 0x00 || this.gb18030_second !== 0x00 ||
this.gb18030_third !== 0x00)) {
this.gb18030_first = 0x00
this.gb18030_second = 0x00
this.gb18030_third = 0x00
decoderError(this.fatal)
}
var code_point
// 3. If gb18030 third is not 0x00, run these substeps:
if (this.gb18030_third !== 0x00) {
// 1. Let code point be null.
code_point = null
// 2. If byte is in the range 0x30 to 0x39, inclusive, set
// code point to the index gb18030 ranges code point for
// (((gb18030 first 0x81) × 10 + gb18030 second 0x30) ×
// 126 + gb18030 third 0x81) × 10 + byte 0x30.
if (inRange(bite, 0x30, 0x39)) {
code_point = indexGB18030RangesCodePointFor(
(((this.gb18030_first - 0x81) * 10 + this.gb18030_second - 0x30) * 126 +
this.gb18030_third - 0x81) * 10 + bite - 0x30)
}
// 3. Let buffer be a byte sequence consisting of gb18030
// second, gb18030 third, and byte, in order.
var buffer = [this.gb18030_second, this.gb18030_third, bite]
// 4. Set gb18030 first, gb18030 second, and gb18030 third to
// 0x00.
this.gb18030_first = 0x00
this.gb18030_second = 0x00
this.gb18030_third = 0x00
// 5. If code point is null, prepend buffer to stream and
// return error.
if (code_point === null) {
stream.prepend(buffer)
return decoderError(this.fatal)
}
// 6. Return a code point whose value is code point.
return code_point
}
// 4. If gb18030 second is not 0x00, run these substeps:
if (this.gb18030_second !== 0x00) {
// 1. If byte is in the range 0x81 to 0xFE, inclusive, set
// gb18030 third to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.gb18030_third = bite
return null
}
// 2. Prepend gb18030 second followed by byte to stream, set
// gb18030 first and gb18030 second to 0x00, and return error.
stream.prepend([this.gb18030_second, bite])
this.gb18030_first = 0x00
this.gb18030_second = 0x00
return decoderError(this.fatal)
}
// 5. If gb18030 first is not 0x00, run these substeps:
if (this.gb18030_first !== 0x00) {
// 1. If byte is in the range 0x30 to 0x39, inclusive, set
// gb18030 second to byte and return continue.
if (inRange(bite, 0x30, 0x39)) {
this.gb18030_second = bite
return null
}
// 2. Let lead be gb18030 first, let pointer be null, and set
// gb18030 first to 0x00.
var lead = this.gb18030_first
var pointer = null
this.gb18030_first = 0x00
// 3. Let offset be 0x40 if byte is less than 0x7F and 0x41
// otherwise.
var offset = bite < 0x7F ? 0x40 : 0x41
// 4. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
// to 0xFE, inclusive, set pointer to (lead 0x81) × 190 +
// (byte offset).
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFE))
pointer = (lead - 0x81) * 190 + (bite - offset)
// 5. Let code point be null if pointer is null and the index
// code point for pointer in index gb18030 otherwise.
code_point = pointer === null ? null :
indexCodePointFor(pointer, index('gb18030'))
// 6. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (code_point === null && isASCIIByte(bite))
stream.prepend(bite)
// 7. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 8. Return a code point whose value is code point.
return code_point
}
// 6. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 7. If byte is 0x80, return code point U+20AC.
if (bite === 0x80)
return 0x20AC
// 8. If byte is in the range 0x81 to 0xFE, inclusive, set
// gb18030 first to byte and return continue.
if (inRange(bite, 0x81, 0xFE)) {
this.gb18030_first = bite
return null
}
// 9. Return error.
return decoderError(this.fatal)
}
}
// 11.2.2 gb18030 encoder
/**
* @implements {Encoder}
*/
export class GB18030Encoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return Byte(s) to emit.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. If code point is U+E5E5, return error with code point.
if (code_point === 0xE5E5)
return encoderError(code_point)
// 4. If the gbk flag is set and code point is U+20AC, return
// byte 0x80.
if (this.gbk_flag && code_point === 0x20AC)
return 0x80
// 5. Let pointer be the index pointer for code point in index
// gb18030.
var pointer = indexPointerFor(code_point, index('gb18030'))
// 6. If pointer is not null, run these substeps:
if (pointer !== null) {
// 1. Let lead be floor(pointer / 190) + 0x81.
var lead = floor(pointer / 190) + 0x81
// 2. Let trail be pointer % 190.
var trail = pointer % 190
// 3. Let offset be 0x40 if trail is less than 0x3F and 0x41 otherwise.
var offset = trail < 0x3F ? 0x40 : 0x41
// 4. Return two bytes whose values are lead and trail + offset.
return [lead, trail + offset]
}
// 7. If gbk flag is set, return error with code point.
if (this.gbk_flag)
return encoderError(code_point)
// 8. Set pointer to the index gb18030 ranges pointer for code
// point.
pointer = indexGB18030RangesPointerFor(code_point)
// 9. Let byte1 be floor(pointer / 10 / 126 / 10).
var byte1 = floor(pointer / 10 / 126 / 10)
// 10. Set pointer to pointer byte1 × 10 × 126 × 10.
pointer = pointer - byte1 * 10 * 126 * 10
// 11. Let byte2 be floor(pointer / 10 / 126).
var byte2 = floor(pointer / 10 / 126)
// 12. Set pointer to pointer byte2 × 10 × 126.
pointer = pointer - byte2 * 10 * 126
// 13. Let byte3 be floor(pointer / 10).
var byte3 = floor(pointer / 10)
// 14. Let byte4 be pointer byte3 × 10.
var byte4 = pointer - byte3 * 10
// 15. Return four bytes whose values are byte1 + 0x81, byte2 +
// 0x30, byte3 + 0x81, byte4 + 0x30.
return [byte1 + 0x81,
byte2 + 0x30,
byte3 + 0x81,
byte4 + 0x30]
}
constructor(options = {}, gbk_flag = false) {
// gb18030's decoder has an associated gbk flag (initially unset).
this.gbk_flag = gbk_flag
}
}

32194
JN/CATJS/lib/gbk_us.js Normal file

File diff suppressed because it is too large Load Diff

940
JN/CATJS/lib/hls.js Normal file
View File

@ -0,0 +1,940 @@
/*
* @File : hls.js.js
* @Author : jade
* @Date : 2024/2/5 16:07
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
let t = {};
function e(e) {
if (t.strictMode) throw e;
t.silent || console.error(e.message)
}
function s(t, ...s) {
for (const [i, n] of s.entries()) n || e(new Error(`${t} : Failed at [${i}]`))
}
function i(...t) {
for (const [s, [i, n]] of t.entries()) i && (n || e(new Error(`Conditional Assert : Failed at [${s}]`)))
}
function n(...t) {
for (const [s, i] of t.entries()) void 0 === i && e(new Error(`Param Check : Failed at [${s}]`))
}
function a(...t) {
for (const [s, [i, n]] of t.entries()) i && void 0 === n && e(new Error(`Conditional Param Check : Failed at [${s}]`))
}
function r(t) {
e(new Error(`Invalid Playlist : ${t}`))
}
function o(t, e = 10) {
if ("number" == typeof t) return t;
const s = 10 === e ? Number.parseFloat(t) : Number.parseInt(t, e);
return Number.isNaN(s) ? 0 : s
}
function E(t) {
(t.startsWith("0x") || t.startsWith("0X")) && (t = t.slice(2));
const e = new Uint8Array(t.length / 2);
for (let s = 0; s < t.length; s += 2) e[s / 2] = o(t.slice(s, s + 2), 16);
return e
}
function T(t, s = 0, i = t.length) {
i <= s && e(new Error(`end must be larger than start : start=${s}, end=${i}`));
const n = [];
for (let e = s; e < i; e++) n.push(`0${(255 & t[e]).toString(16).toUpperCase()}`.slice(-2));
return `0x${n.join("")}`
}
function u(t, e, s = 0) {
let i = -1;
for (let n = 0, a = 0; n < t.length; n++) if (t[n] === e) {
if (a++ === s) return [t.slice(0, n), t.slice(n + 1)];
i = n
}
return -1 !== i ? [t.slice(0, i), t.slice(i + 1)] : [t]
}
function c(t) {
const e = [];
let s = !1;
for (const i of t) "-" !== i && "_" !== i ? s ? (e.push(i.toUpperCase()), s = !1) : e.push(i.toLowerCase()) : s = !0;
return e.join("")
}
function l(t) {
return `${t.getUTCFullYear()}-${("0" + (t.getUTCMonth() + 1)).slice(-2)}-${("0" + t.getUTCDate()).slice(-2)}T${("0" + t.getUTCHours()).slice(-2)}:${("0" + t.getUTCMinutes()).slice(-2)}:${("0" + t.getUTCSeconds()).slice(-2)}.${("00" + t.getUTCMilliseconds()).slice(-3)}Z`
}
function h(e = {}) {
t = Object.assign(t, e)
}
function X() {
return Object.assign({}, t)
}
function p(t, e) {
e = Math.trunc(e) || 0;
const s = t.length >>> 0;
if (e < 0 && (e = s + e), !(e < 0 || e >= s)) return t[e]
}
class I {
constructor({
type: t,
uri: e,
groupId: s,
language: a,
assocLanguage: r,
name: o,
isDefault: E,
autoselect: T,
forced: u,
instreamId: c,
characteristics: l,
channels: h
}) {
n(t, s, o), i(["SUBTITLES" === t, e], ["CLOSED-CAPTIONS" === t, c], ["CLOSED-CAPTIONS" === t, !e], [u, "SUBTITLES" === t]), this.type = t, this.uri = e, this.groupId = s, this.language = a, this.assocLanguage = r, this.name = o, this.isDefault = E, this.autoselect = T, this.forced = u, this.instreamId = c, this.characteristics = l, this.channels = h
}
}
class N {
constructor({
uri: t,
isIFrameOnly: e = !1,
bandwidth: s,
averageBandwidth: i,
score: a,
codecs: r,
resolution: o,
frameRate: E,
hdcpLevel: T,
allowedCpc: u,
videoRange: c,
stableVariantId: l,
programId: h,
audio: X = [],
video: p = [],
subtitles: I = [],
closedCaptions: N = [],
currentRenditions: d = {audio: 0, video: 0, subtitles: 0, closedCaptions: 0}
}) {
n(t, s), this.uri = t, this.isIFrameOnly = e, this.bandwidth = s, this.averageBandwidth = i, this.score = a, this.codecs = r, this.resolution = o, this.frameRate = E, this.hdcpLevel = T, this.allowedCpc = u, this.videoRange = c, this.stableVariantId = l, this.programId = h, this.audio = X, this.video = p, this.subtitles = I, this.closedCaptions = N, this.currentRenditions = d
}
}
class d {
constructor({id: t, value: e, uri: i, language: a}) {
n(t, e || i), s("SessionData cannot have both value and uri, shoud be either.", !(e && i)), this.id = t, this.value = e, this.uri = i, this.language = a
}
}
class A {
constructor({method: t, uri: e, iv: s, format: r, formatVersion: o}) {
n(t), a(["NONE" !== t, e]), i(["NONE" === t, !(e || s || r || o)]), this.method = t, this.uri = e, this.iv = s, this.format = r, this.formatVersion = o
}
}
class f {
constructor({hint: t = !1, uri: e, mimeType: s, byterange: i}) {
n(e), this.hint = t, this.uri = e, this.mimeType = s, this.byterange = i
}
}
class S {
constructor({
id: t,
classId: e,
start: s,
end: r,
duration: o,
plannedDuration: E,
endOnNext: T,
attributes: u = {}
}) {
n(t), a([!0 === T, e]), i([r, s], [r, s <= r], [o, o >= 0], [E, E >= 0]), this.id = t, this.classId = e, this.start = s, this.end = r, this.duration = o, this.plannedDuration = E, this.endOnNext = T, this.attributes = u
}
}
class R {
constructor({type: t, duration: e, tagName: s, value: i}) {
n(t), a(["OUT" === t, e]), a(["RAW" === t, s]), this.type = t, this.duration = e, this.tagName = s, this.value = i
}
}
class m {
constructor(t) {
n(t), this.type = t
}
}
class g extends m {
constructor({isMasterPlaylist: t, uri: e, version: s, independentSegments: i = !1, start: a, source: r}) {
super("playlist"), n(t), this.isMasterPlaylist = t, this.uri = e, this.version = s, this.independentSegments = i, this.start = a, this.source = r
}
}
class O extends g {
constructor(t = {}) {
super(Object.assign(Object.assign({}, t), {isMasterPlaylist: !0}));
const {variants: e = [], currentVariant: s, sessionDataList: i = [], sessionKeyList: n = []} = t;
this.variants = e, this.currentVariant = s, this.sessionDataList = i, this.sessionKeyList = n
}
}
class D extends g {
constructor(t = {}) {
super(Object.assign(Object.assign({}, t), {isMasterPlaylist: !1}));
const {
targetDuration: e,
mediaSequenceBase: s = 0,
discontinuitySequenceBase: i = 0,
endlist: n = !1,
playlistType: a,
isIFrame: r,
segments: o = [],
prefetchSegments: E = [],
lowLatencyCompatibility: T,
partTargetDuration: u,
renditionReports: c = [],
skip: l = 0,
hash: h
} = t;
this.targetDuration = e, this.mediaSequenceBase = s, this.discontinuitySequenceBase = i, this.endlist = n, this.playlistType = a, this.isIFrame = r, this.segments = o, this.prefetchSegments = E, this.lowLatencyCompatibility = T, this.partTargetDuration = u, this.renditionReports = c, this.skip = l, this.hash = h
}
}
class P extends m {
constructor({
uri: t,
mimeType: e,
data: s,
duration: i,
title: n,
byterange: a,
discontinuity: r,
mediaSequenceNumber: o = 0,
discontinuitySequence: E = 0,
key: T,
map: u,
programDateTime: c,
dateRange: l,
markers: h = [],
parts: X = []
}) {
super("segment"), this.uri = t, this.mimeType = e, this.data = s, this.duration = i, this.title = n, this.byterange = a, this.discontinuity = r, this.mediaSequenceNumber = o, this.discontinuitySequence = E, this.key = T, this.map = u, this.programDateTime = c, this.dateRange = l, this.markers = h, this.parts = X
}
}
class y extends m {
constructor({hint: t = !1, uri: e, duration: s, independent: i, byterange: a, gap: r}) {
super("part"), n(e), this.hint = t, this.uri = e, this.duration = s, this.independent = i, this.duration = s, this.byterange = a, this.gap = r
}
}
class C extends m {
constructor({uri: t, discontinuity: e, mediaSequenceNumber: s = 0, discontinuitySequence: i = 0, key: a}) {
super("prefetch"), n(t), this.uri = t, this.discontinuity = e, this.mediaSequenceNumber = s, this.discontinuitySequence = i, this.key = a
}
}
class U {
constructor({uri: t, lastMSN: e, lastPart: s}) {
n(t), this.uri = t, this.lastMSN = e, this.lastPart = s
}
}
var M = Object.freeze({
__proto__: null,
Rendition: I,
Variant: N,
SessionData: d,
Key: A,
MediaInitializationSection: f,
DateRange: S,
SpliceInfo: R,
Playlist: g,
MasterPlaylist: O,
MediaPlaylist: D,
Segment: P,
PartialSegment: y,
PrefetchSegment: C,
RenditionReport: U
});
function b(t) {
return function (t, e = " ") {
return t ? (t = t.trim(), " " === e || (t.startsWith(e) && (t = t.slice(1)), t.endsWith(e) && (t = t.slice(0, -1))), t) : t
}(t, '"')
}
function L(t) {
const e = u(t, ",");
return {duration: o(e[0]), title: decodeURIComponent(escape(e[1]))}
}
function v(t) {
const e = u(t, "@");
return {length: o(e[0]), offset: e[1] ? o(e[1]) : -1}
}
function $(t) {
const e = u(t, "x");
return {width: o(e[0]), height: o(e[1])}
}
function Y(t) {
const e = "ALLOWED-CPC: Each entry must consit of KEYFORMAT and Content Protection Configuration", s = t.split(",");
0 === s.length && r(e);
const i = [];
for (const t of s) {
const [s, n] = u(t, ":");
s && n ? i.push({format: s, cpcList: n.split("/")}) : r(e)
}
return i
}
function F(t) {
const e = E(t);
return 16 !== e.length && r("IV must be a 128-bit unsigned integer"), e
}
function G(t, e) {
e.IV && t.compatibleVersion < 2 && (t.compatibleVersion = 2), (e.KEYFORMAT || e.KEYFORMATVERSIONS) && t.compatibleVersion < 5 && (t.compatibleVersion = 5)
}
function V(t) {
const e = {};
for (const i of function (t) {
const e = [];
let s = !0, i = 0;
const n = [];
for (let a = 0; a < t.length; a++) {
const r = t[a];
s && "," === r ? (e.push(t.slice(i, a).trim()), i = a + 1) : '"' !== r && "'" !== r || (s ? (n.push(r), s = !1) : r === p(n, -1) ? (n.pop(), s = !0) : n.push(r))
}
return e.push(t.slice(i).trim()), e
}(t)) {
const [t, n] = u(i, "="), a = b(n);
switch (t) {
case"URI":
e[t] = a;
break;
case"START-DATE":
case"END-DATE":
e[t] = new Date(a);
break;
case"IV":
e[t] = F(a);
break;
case"BYTERANGE":
e[t] = v(a);
break;
case"RESOLUTION":
e[t] = $(a);
break;
case"ALLOWED-CPC":
e[t] = Y(a);
break;
case"END-ON-NEXT":
case"DEFAULT":
case"AUTOSELECT":
case"FORCED":
case"PRECISE":
case"CAN-BLOCK-RELOAD":
case"INDEPENDENT":
case"GAP":
e[t] = "YES" === a;
break;
case"DURATION":
case"PLANNED-DURATION":
case"BANDWIDTH":
case"AVERAGE-BANDWIDTH":
case"FRAME-RATE":
case"TIME-OFFSET":
case"CAN-SKIP-UNTIL":
case"HOLD-BACK":
case"PART-HOLD-BACK":
case"PART-TARGET":
case"BYTERANGE-START":
case"BYTERANGE-LENGTH":
case"LAST-MSN":
case"LAST-PART":
case"SKIPPED-SEGMENTS":
case"SCORE":
case"PROGRAM-ID":
e[t] = o(a);
break;
default:
t.startsWith("SCTE35-") ? e[t] = E(a) : t.startsWith("X-") ? e[t] = (s = n).startsWith('"') ? b(s) : s.startsWith("0x") || s.startsWith("0X") ? E(s) : o(s) : ("VIDEO-RANGE" === t && "SDR" !== a && "HLG" !== a && "PQ" !== a && r(`VIDEO-RANGE: unknown value "${a}"`), e[t] = a)
}
}
var s;
return e
}
function w() {
r("The file contains both media and master playlist tags.")
}
function B(t, e, s) {
const i = function ({attributes: t}) {
return new I({
type: t.TYPE,
uri: t.URI,
groupId: t["GROUP-ID"],
language: t.LANGUAGE,
assocLanguage: t["ASSOC-LANGUAGE"],
name: t.NAME,
isDefault: t.DEFAULT,
autoselect: t.AUTOSELECT,
forced: t.FORCED,
instreamId: t["INSTREAM-ID"],
characteristics: t.CHARACTERISTICS,
channels: t.CHANNELS
})
}(e), n = t[c(s)], a = function (t, e) {
let s = !1;
for (const i of t) {
if (i.name === e.name) return "All EXT-X-MEDIA tags in the same Group MUST have different NAME attributes.";
i.isDefault && (s = !0)
}
return s && e.isDefault ? "EXT-X-MEDIA A Group MUST NOT have more than one member with a DEFAULT attribute of YES." : ""
}(n, i);
a && r(a), n.push(i), i.isDefault && (t.currentRenditions[c(s)] = n.length - 1)
}
function H(t, e, s, i, n) {
const a = new N({
uri: s,
bandwidth: e.BANDWIDTH,
averageBandwidth: e["AVERAGE-BANDWIDTH"],
score: e.SCORE,
codecs: e.CODECS,
resolution: e.RESOLUTION,
frameRate: e["FRAME-RATE"],
hdcpLevel: e["HDCP-LEVEL"],
allowedCpc: e["ALLOWED-CPC"],
videoRange: e["VIDEO-RANGE"],
stableVariantId: e["STABLE-VARIANT-ID"],
programId: e["PROGRAM-ID"]
});
for (const s of t) if ("EXT-X-MEDIA" === s.name) {
const t = s.attributes, i = t.TYPE;
if (i && t["GROUP-ID"] || r("EXT-X-MEDIA TYPE attribute is REQUIRED."), e[i] === t["GROUP-ID"] && (B(a, s, i), "CLOSED-CAPTIONS" === i)) for (const {instreamId: t} of a.closedCaptions) if (t && t.startsWith("SERVICE") && n.compatibleVersion < 7) {
n.compatibleVersion = 7;
break
}
}
return function (t, e, s) {
for (const i of ["AUDIO", "VIDEO", "SUBTITLES", "CLOSED-CAPTIONS"]) "CLOSED-CAPTIONS" === i && "NONE" === t[i] ? (s.isClosedCaptionsNone = !0, e.closedCaptions = []) : t[i] && !e[c(i)].some((e => e.groupId === t[i])) && r(`${i} attribute MUST match the value of the GROUP-ID attribute of an EXT-X-MEDIA tag whose TYPE attribute is ${i}.`)
}(e, a, n), a.isIFrameOnly = i, a
}
function K(t, e) {
if (t.method !== e.method) return !1;
if (t.uri !== e.uri) return !1;
if (t.iv) {
if (!e.iv) return !1;
if (t.iv.length !== e.iv.length) return !1;
for (let s = 0; s < t.iv.length; s++) if (t.iv[s] !== e.iv[s]) return !1
} else if (e.iv) return !1;
return t.format === e.format && t.formatVersion === e.formatVersion
}
function k(t, e, s, i, n, a, o) {
const E = new P({uri: e, mediaSequenceNumber: n, discontinuitySequence: a});
let T = !1, u = !1;
for (let e = s; e <= i; e++) {
const {name: s, value: i, attributes: n} = t[e];
if ("EXTINF" === s) !Number.isInteger(i.duration) && o.compatibleVersion < 3 && (o.compatibleVersion = 3), Math.round(i.duration) > o.targetDuration && r("EXTINF duration, when rounded to the nearest integer, MUST be less than or equal to the target duration"), E.duration = i.duration, E.title = i.title; else if ("EXT-X-BYTERANGE" === s) o.compatibleVersion < 4 && (o.compatibleVersion = 4), E.byterange = i; else if ("EXT-X-DISCONTINUITY" === s) E.parts.length > 0 && r("EXT-X-DISCONTINUITY must appear before the first EXT-X-PART tag of the Parent Segment."), E.discontinuity = !0; else if ("EXT-X-KEY" === s) E.parts.length > 0 && r("EXT-X-KEY must appear before the first EXT-X-PART tag of the Parent Segment."), G(o, n), E.key = new A({
method: n.METHOD,
uri: n.URI,
iv: n.IV,
format: n.KEYFORMAT,
formatVersion: n.KEYFORMATVERSIONS
}); else if ("EXT-X-MAP" === s) E.parts.length > 0 && r("EXT-X-MAP must appear before the first EXT-X-PART tag of the Parent Segment."), o.compatibleVersion < 5 && (o.compatibleVersion = 5), o.hasMap = !0, E.map = new f({
uri: n.URI,
byterange: n.BYTERANGE
}); else if ("EXT-X-PROGRAM-DATE-TIME" === s) E.programDateTime = i; else if ("EXT-X-DATERANGE" === s) {
const t = {};
for (const e of Object.keys(n)) (e.startsWith("SCTE35-") || e.startsWith("X-")) && (t[e] = n[e]);
E.dateRange = new S({
id: n.ID,
classId: n.CLASS,
start: n["START-DATE"],
end: n["END-DATE"],
duration: n.DURATION,
plannedDuration: n["PLANNED-DURATION"],
endOnNext: n["END-ON-NEXT"],
attributes: t
})
} else if ("EXT-X-CUE-OUT" === s) E.markers.push(new R({
type: "OUT",
duration: n && n.DURATION || i
})); else if ("EXT-X-CUE-IN" === s) E.markers.push(new R({type: "IN"})); else if ("EXT-X-CUE-OUT-CONT" === s || "EXT-X-CUE" === s || "EXT-OATCLS-SCTE35" === s || "EXT-X-ASSET" === s || "EXT-X-SCTE35" === s) E.markers.push(new R({
type: "RAW",
tagName: s,
value: i
})); else if ("EXT-X-PRELOAD-HINT" !== s || n.TYPE) if ("EXT-X-PRELOAD-HINT" === s && "PART" === n.TYPE && u) r("Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist."); else if ("EXT-X-PART" !== s && "EXT-X-PRELOAD-HINT" !== s || n.URI) {
if ("EXT-X-PRELOAD-HINT" === s && "MAP" === n.TYPE) T && r("Servers should not add more than one EXT-X-PRELOAD-HINT tag with the same TYPE attribute to a Playlist."), T = !0, o.hasMap = !0, E.map = new f({
hint: !0,
uri: n.URI,
byterange: {length: n["BYTERANGE-LENGTH"], offset: n["BYTERANGE-START"] || 0}
}); else if ("EXT-X-PART" === s || "EXT-X-PRELOAD-HINT" === s && "PART" === n.TYPE) {
"EXT-X-PART" !== s || n.DURATION || r("EXT-X-PART: DURATION attribute is mandatory"), "EXT-X-PRELOAD-HINT" === s && (u = !0);
const t = new y({
hint: "EXT-X-PRELOAD-HINT" === s,
uri: n.URI,
byterange: "EXT-X-PART" === s ? n.BYTERANGE : {
length: n["BYTERANGE-LENGTH"],
offset: n["BYTERANGE-START"] || 0
},
duration: n.DURATION,
independent: n.INDEPENDENT,
gap: n.GAP
});
E.parts.push(t)
}
} else r("EXT-X-PART / EXT-X-PRELOAD-HINT: URI attribute is mandatory"); else r("EXT-X-PRELOAD-HINT: TYPE attribute is mandatory")
}
return E
}
function W(t, e, s, i, n, a, o) {
const E = new C({uri: e, mediaSequenceNumber: n, discontinuitySequence: a});
for (let e = s; e <= i; e++) {
const {name: s, attributes: i} = t[e];
"EXTINF" === s ? r("A prefetch segment must not be advertised with an EXTINF tag.") : "EXT-X-DISCONTINUITY" === s ? r("A prefetch segment must not be advertised with an EXT-X-DISCONTINUITY tag.") : "EXT-X-PREFETCH-DISCONTINUITY" === s ? E.discontinuity = !0 : "EXT-X-KEY" === s ? (G(o, i), E.key = new A({
method: i.METHOD,
uri: i.URI,
iv: i.IV,
format: i.KEYFORMAT,
formatVersion: i.KEYFORMATVERSIONS
})) : "EXT-X-MAP" === s && r("Prefetch segments must not be advertised with an EXT-X-MAP tag.")
}
return E
}
function q(t, e) {
var s;
const i = new D;
let n = -1, a = 0, o = !1, E = !1, T = 0, u = null, c = null, l = !1;
for (const [s, h] of t.entries()) {
const {name: X, value: p, attributes: I, category: N} = h;
if ("Segment" !== N) {
if ("EXT-X-VERSION" === X) void 0 === i.version ? i.version = p : r("A Playlist file MUST NOT contain more than one EXT-X-VERSION tag."); else if ("EXT-X-TARGETDURATION" === X) i.targetDuration = e.targetDuration = p; else if ("EXT-X-MEDIA-SEQUENCE" === X) i.segments.length > 0 && r("The EXT-X-MEDIA-SEQUENCE tag MUST appear before the first Media Segment in the Playlist."), i.mediaSequenceBase = a = p; else if ("EXT-X-DISCONTINUITY-SEQUENCE" === X) i.segments.length > 0 && r("The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before the first Media Segment in the Playlist."), o && r("The EXT-X-DISCONTINUITY-SEQUENCE tag MUST appear before any EXT-X-DISCONTINUITY tag."), i.discontinuitySequenceBase = T = p; else if ("EXT-X-ENDLIST" === X) i.endlist = !0; else if ("EXT-X-PLAYLIST-TYPE" === X) i.playlistType = p; else if ("EXT-X-I-FRAMES-ONLY" === X) e.compatibleVersion < 4 && (e.compatibleVersion = 4), i.isIFrame = !0; else if ("EXT-X-INDEPENDENT-SEGMENTS" === X) i.independentSegments && r("EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist"), i.independentSegments = !0; else if ("EXT-X-START" === X) i.start && r("EXT-X-START tag MUST NOT appear more than once in a Playlist"), "number" != typeof I["TIME-OFFSET"] && r("EXT-X-START: TIME-OFFSET attribute is REQUIRED"), i.start = {
offset: I["TIME-OFFSET"],
precise: I.PRECISE || !1
}; else if ("EXT-X-SERVER-CONTROL" === X) I["CAN-BLOCK-RELOAD"] || r("EXT-X-SERVER-CONTROL: CAN-BLOCK-RELOAD=YES is mandatory for Low-Latency HLS"), i.lowLatencyCompatibility = {
canBlockReload: I["CAN-BLOCK-RELOAD"],
canSkipUntil: I["CAN-SKIP-UNTIL"],
holdBack: I["HOLD-BACK"],
partHoldBack: I["PART-HOLD-BACK"]
}; else if ("EXT-X-PART-INF" === X) I["PART-TARGET"] || r("EXT-X-PART-INF: PART-TARGET attribute is mandatory"), i.partTargetDuration = I["PART-TARGET"]; else if ("EXT-X-RENDITION-REPORT" === X) I.URI || r("EXT-X-RENDITION-REPORT: URI attribute is mandatory"), 0 === I.URI.search(/^[a-z]+:/) && r("EXT-X-RENDITION-REPORT: URI must be relative to the playlist uri"), i.renditionReports.push(new U({
uri: I.URI,
lastMSN: I["LAST-MSN"],
lastPart: I["LAST-PART"]
})); else if ("EXT-X-SKIP" === X) I["SKIPPED-SEGMENTS"] || r("EXT-X-SKIP: SKIPPED-SEGMENTS attribute is mandatory"), e.compatibleVersion < 9 && (e.compatibleVersion = 9), i.skip = I["SKIPPED-SEGMENTS"], a += i.skip; else if ("EXT-X-PREFETCH" === X) {
const r = W(t, p, -1 === n ? s : n, s - 1, a++, T, e);
r && (r.discontinuity && (r.discontinuitySequence++, T = r.discontinuitySequence), r.key ? u = r.key : r.key = u, i.prefetchSegments.push(r)), E = !0, n = -1
} else if ("string" == typeof h) {
-1 === n && r("A URI line is not preceded by any segment tags"), i.targetDuration || r("The EXT-X-TARGETDURATION tag is REQUIRED"), E && r("These segments must appear after all complete segments.");
const o = k(t, h, n, s - 1, a++, T, e);
o && ([T, u, c] = x(i, o, T, u, c), !l && o.parts.length > 0 && (l = !0)), n = -1
}
} else -1 === n && (n = s), "EXT-X-DISCONTINUITY" === X && (o = !0)
}
if (-1 !== n) {
const o = k(t, "", n, t.length - 1, a++, T, e);
if (o) {
const {parts: t} = o;
t.length > 0 && !i.endlist && !(null === (s = p(t, -1)) || void 0 === s ? void 0 : s.hint) && r("If the Playlist contains EXT-X-PART tags and does not contain an EXT-X-ENDLIST tag, the Playlist must contain an EXT-X-PRELOAD-HINT tag with a TYPE=PART attribute"), x(i, o, u, c), !l && o.parts.length > 0 && (l = !0)
}
}
return function (t) {
const e = new Map, s = new Map;
let i = !1, n = !1;
for (let a = t.length - 1; a >= 0; a--) {
const {programDateTime: o, dateRange: E} = t[a];
if (o && (n = !0), E && E.start) {
i = !0, E.endOnNext && (E.end || E.duration) && r("An EXT-X-DATERANGE tag with an END-ON-NEXT=YES attribute MUST NOT contain DURATION or END-DATE attributes.");
const t = E.start.getTime(), n = E.duration || 0;
E.end && E.duration && t + 1e3 * n !== E.end.getTime() && r("END-DATE MUST be equal to the value of the START-DATE attribute plus the value of the DURATION"), E.endOnNext && (E.end = e.get(E.classId)), e.set(E.classId, E.start);
const a = E.end ? E.end.getTime() : E.start.getTime() + 1e3 * (E.duration || 0), o = s.get(E.classId);
if (o) {
for (const e of o) (e.start <= t && e.end > t || e.start >= t && e.start < a) && r("DATERANGE tags with the same CLASS should not overlap");
o.push({start: t, end: a})
} else E.classId && s.set(E.classId, [{start: t, end: a}])
}
}
i && !n && r("If a Playlist contains an EXT-X-DATERANGE tag, it MUST also contain at least one EXT-X-PROGRAM-DATE-TIME tag.")
}(i.segments), i.lowLatencyCompatibility && function ({
lowLatencyCompatibility: t,
targetDuration: e,
partTargetDuration: s,
segments: i,
renditionReports: n
}, a) {
const {canSkipUntil: o, holdBack: E, partHoldBack: T} = t;
o < 6 * e && r("The Skip Boundary must be at least six times the EXT-X-TARGETDURATION.");
E < 3 * e && r("HOLD-BACK must be at least three times the EXT-X-TARGETDURATION.");
if (a) {
void 0 === s && r("EXT-X-PART-INF is required if a Playlist contains one or more EXT-X-PART tags"), void 0 === T && r("EXT-X-PART: PART-HOLD-BACK attribute is mandatory"), T < s && r("PART-HOLD-BACK must be at least PART-TARGET");
for (const [t, {parts: e}] of i.entries()) {
e.length > 0 && t < i.length - 3 && r("Remove EXT-X-PART tags from the Playlist after they are greater than three target durations from the end of the Playlist.");
for (const [t, {duration: i}] of e.entries()) void 0 !== i && (i > s && r("PART-TARGET is the maximum duration of any Partial Segment"), t < e.length - 1 && i < .85 * s && r("All Partial Segments except the last part of a segment must have a duration of at least 85% of PART-TARGET"))
}
}
for (const t of n) {
const e = i.at(-1);
null !== t.lastMSN && void 0 !== t.lastMSN || (t.lastMSN = e.mediaSequenceNumber), (null === t.lastPart || void 0 === t.lastPart) && e.parts.length > 0 && (t.lastPart = e.parts.length - 1)
}
}(i, l), i
}
function x(t, e, s, i, n) {
const {discontinuity: a, key: o, map: E, byterange: T, uri: u} = e;
if (a && (e.discontinuitySequence = s + 1), o || (e.key = i), E || (e.map = n), T && -1 === T.offset) {
const {segments: e} = t;
if (e.length > 0) {
const t = p(e, -1);
t.byterange && t.uri === u ? T.offset = t.byterange.offset + t.byterange.length : r("If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST be a sub-range of the same media resource")
} else r("If offset of EXT-X-BYTERANGE is not present, a previous Media Segment MUST appear in the Playlist file")
}
return t.segments.push(e), [e.discontinuitySequence, e.key, e.map]
}
function j(t, e) {
const [s, i] = function (t) {
const e = t.indexOf(":");
return -1 === e ? [t.slice(1).trim(), null] : [t.slice(1, e).trim(), t.slice(e + 1).trim()]
}(t), n = function (t) {
switch (t) {
case"EXTM3U":
case"EXT-X-VERSION":
return "Basic";
case"EXTINF":
case"EXT-X-BYTERANGE":
case"EXT-X-DISCONTINUITY":
case"EXT-X-PREFETCH-DISCONTINUITY":
case"EXT-X-KEY":
case"EXT-X-MAP":
case"EXT-X-PROGRAM-DATE-TIME":
case"EXT-X-DATERANGE":
case"EXT-X-CUE-OUT":
case"EXT-X-CUE-IN":
case"EXT-X-CUE-OUT-CONT":
case"EXT-X-CUE":
case"EXT-OATCLS-SCTE35":
case"EXT-X-ASSET":
case"EXT-X-SCTE35":
case"EXT-X-PART":
case"EXT-X-PRELOAD-HINT":
return "Segment";
case"EXT-X-TARGETDURATION":
case"EXT-X-MEDIA-SEQUENCE":
case"EXT-X-DISCONTINUITY-SEQUENCE":
case"EXT-X-ENDLIST":
case"EXT-X-PLAYLIST-TYPE":
case"EXT-X-I-FRAMES-ONLY":
case"EXT-X-SERVER-CONTROL":
case"EXT-X-PART-INF":
case"EXT-X-PREFETCH":
case"EXT-X-RENDITION-REPORT":
case"EXT-X-SKIP":
return "MediaPlaylist";
case"EXT-X-MEDIA":
case"EXT-X-STREAM-INF":
case"EXT-X-I-FRAME-STREAM-INF":
case"EXT-X-SESSION-DATA":
case"EXT-X-SESSION-KEY":
return "MasterPlaylist";
case"EXT-X-INDEPENDENT-SEGMENTS":
case"EXT-X-START":
return "MediaorMasterPlaylist";
default:
return "Unknown"
}
}(s);
if (function (t, e) {
if ("Segment" === t || "MediaPlaylist" === t) return void 0 === e.isMasterPlaylist ? void (e.isMasterPlaylist = !1) : void (e.isMasterPlaylist && w());
if ("MasterPlaylist" === t) {
if (void 0 === e.isMasterPlaylist) return void (e.isMasterPlaylist = !0);
!1 === e.isMasterPlaylist && w()
}
}(n, e), "Unknown" === n) return null;
"MediaPlaylist" === n && "EXT-X-RENDITION-REPORT" !== s && "EXT-X-PREFETCH" !== s && (e.hash[s] && r("There MUST NOT be more than one Media Playlist tag of each type in any Media Playlist"), e.hash[s] = !0);
const [a, E] = function (t, e) {
switch (t) {
case"EXTM3U":
case"EXT-X-DISCONTINUITY":
case"EXT-X-ENDLIST":
case"EXT-X-I-FRAMES-ONLY":
case"EXT-X-INDEPENDENT-SEGMENTS":
case"EXT-X-CUE-IN":
return [null, null];
case"EXT-X-VERSION":
case"EXT-X-TARGETDURATION":
case"EXT-X-MEDIA-SEQUENCE":
case"EXT-X-DISCONTINUITY-SEQUENCE":
return [o(e), null];
case"EXT-X-CUE-OUT":
return Number.isNaN(Number(e)) ? [null, V(e)] : [o(e), null];
case"EXT-X-KEY":
case"EXT-X-MAP":
case"EXT-X-DATERANGE":
case"EXT-X-MEDIA":
case"EXT-X-STREAM-INF":
case"EXT-X-I-FRAME-STREAM-INF":
case"EXT-X-SESSION-DATA":
case"EXT-X-SESSION-KEY":
case"EXT-X-START":
case"EXT-X-SERVER-CONTROL":
case"EXT-X-PART-INF":
case"EXT-X-PART":
case"EXT-X-PRELOAD-HINT":
case"EXT-X-RENDITION-REPORT":
case"EXT-X-SKIP":
return [null, V(e)];
case"EXTINF":
return [L(e), null];
case"EXT-X-BYTERANGE":
return [v(e), null];
case"EXT-X-PROGRAM-DATE-TIME":
return [new Date(e), null];
default:
return [e, null]
}
}(s, i);
return {name: s, category: n, value: a, attributes: E}
}
function Q(t, e) {
let s;
return e.isMasterPlaylist ? s = function (t, e) {
const s = new O;
let i = !1;
for (const [n, {
name: a,
value: o,
attributes: E
}] of t.entries()) if ("EXT-X-VERSION" === a) s.version = o; else if ("EXT-X-STREAM-INF" === a) {
const a = t[n + 1];
("string" != typeof a || a.startsWith("#EXT")) && r("EXT-X-STREAM-INF must be followed by a URI line");
const o = H(t, E, a, !1, e);
o && ("number" == typeof o.score && (i = !0, o.score < 0 && r("SCORE attribute on EXT-X-STREAM-INF must be positive decimal-floating-point number.")), s.variants.push(o))
} else if ("EXT-X-I-FRAME-STREAM-INF" === a) {
const i = H(t, E, E.URI, !0, e);
i && s.variants.push(i)
} else if ("EXT-X-SESSION-DATA" === a) {
const t = new d({id: E["DATA-ID"], value: E.VALUE, uri: E.URI, language: E.LANGUAGE});
s.sessionDataList.some((e => e.id === t.id && e.language === t.language)) && r("A Playlist MUST NOT contain more than one EXT-X-SESSION-DATA tag with the same DATA-ID attribute and the same LANGUAGE attribute."), s.sessionDataList.push(t)
} else if ("EXT-X-SESSION-KEY" === a) {
"NONE" === E.METHOD && r("EXT-X-SESSION-KEY: The value of the METHOD attribute MUST NOT be NONE");
const t = new A({
method: E.METHOD,
uri: E.URI,
iv: E.IV,
format: E.KEYFORMAT,
formatVersion: E.KEYFORMATVERSIONS
});
s.sessionKeyList.some((e => K(e, t))) && r("A Master Playlist MUST NOT contain more than one EXT-X-SESSION-KEY tag with the same METHOD, URI, IV, KEYFORMAT, and KEYFORMATVERSIONS attribute values."), G(e, E), s.sessionKeyList.push(t)
} else "EXT-X-INDEPENDENT-SEGMENTS" === a ? (s.independentSegments && r("EXT-X-INDEPENDENT-SEGMENTS tag MUST NOT appear more than once in a Playlist"), s.independentSegments = !0) : "EXT-X-START" === a && (s.start && r("EXT-X-START tag MUST NOT appear more than once in a Playlist"), "number" != typeof E["TIME-OFFSET"] && r("EXT-X-START: TIME-OFFSET attribute is REQUIRED"), s.start = {
offset: E["TIME-OFFSET"],
precise: E.PRECISE || !1
});
if (i) for (const t of s.variants) "number" != typeof t.score && r("If any Variant Stream contains the SCORE attribute, then all Variant Streams in the Master Playlist SHOULD have a SCORE attribute");
if (e.isClosedCaptionsNone) for (const t of s.variants) t.closedCaptions.length > 0 && r("If there is a variant with CLOSED-CAPTIONS attribute of NONE, all EXT-X-STREAM-INF tags MUST have this attribute with a value of NONE");
return s
}(t, e) : (s = q(t, e), !s.isIFrame && e.hasMap && e.compatibleVersion < 6 && (e.compatibleVersion = 6)), e.compatibleVersion > 1 && (!s.version || s.version < e.compatibleVersion) && r(`EXT-X-VERSION needs to be ${e.compatibleVersion} or higher.`), s
}
function _(t) {
const e = {
version: void 0,
isMasterPlaylist: void 0,
hasMap: !1,
targetDuration: 0,
compatibleVersion: 1,
isClosedCaptionsNone: !1,
hash: {}
}, s = function (t, e) {
const s = [];
for (const i of t.split("\n")) {
const t = i.trim();
if (t) if (t.startsWith("#")) {
if (t.startsWith("#EXT")) {
const i = j(t, e);
i && s.push(i)
}
} else s.push(t)
}
return 0 !== s.length && "EXTM3U" === s[0].name || r("The EXTM3U tag MUST be the first line."), s
}(t, e), i = Q(s, e);
return i.source = t, i
}
const z = ["#EXTINF", "#EXT-X-BYTERANGE", "#EXT-X-DISCONTINUITY", "#EXT-X-STREAM-INF", "#EXT-X-CUE-OUT", "#EXT-X-CUE-IN", "#EXT-X-KEY", "#EXT-X-MAP"],
Z = ["#EXT-X-MEDIA"];
class J extends Array {
constructor(t) {
super(), this.baseUri = t
}
push(...t) {
for (const e of t) if (e.startsWith("#")) if (z.some((t => e.startsWith(t)))) super.push(e); else {
if (this.includes(e)) {
if (Z.some((t => e.startsWith(t)))) continue;
r(`Redundant item (${e})`)
}
super.push(e)
} else super.push(e);
return this.length
}
}
function tt(t, e) {
let s = 1e3;
e && (s = Math.pow(10, e));
const i = Math.round(t * s) / s;
return e ? i.toFixed(e) : i
}
function et(t) {
const e = [`DATA-ID="${t.id}"`];
return t.language && e.push(`LANGUAGE="${t.language}"`), t.value ? e.push(`VALUE="${t.value}"`) : t.uri && e.push(`URI="${t.uri}"`), `#EXT-X-SESSION-DATA:${e.join(",")}`
}
function st(t, e) {
const s = e ? "#EXT-X-SESSION-KEY" : "#EXT-X-KEY", i = [`METHOD=${t.method}`];
return t.uri && i.push(`URI="${t.uri}"`), t.iv && (16 !== t.iv.length && r("IV must be a 128-bit unsigned integer"), i.push(`IV=${T(t.iv)}`)), t.format && i.push(`KEYFORMAT="${t.format}"`), t.formatVersion && i.push(`KEYFORMATVERSIONS="${t.formatVersion}"`), `${s}:${i.join(",")}`
}
function it(t, e) {
const s = e.isIFrameOnly ? "#EXT-X-I-FRAME-STREAM-INF" : "#EXT-X-STREAM-INF", i = [`BANDWIDTH=${e.bandwidth}`];
if (e.averageBandwidth && i.push(`AVERAGE-BANDWIDTH=${e.averageBandwidth}`), e.isIFrameOnly && i.push(`URI="${e.uri}"`), e.codecs && i.push(`CODECS="${e.codecs}"`), e.resolution && i.push(`RESOLUTION=${e.resolution.width}x${e.resolution.height}`), e.frameRate && i.push(`FRAME-RATE=${tt(e.frameRate, 3)}`), e.hdcpLevel && i.push(`HDCP-LEVEL=${e.hdcpLevel}`), e.audio.length > 0) {
i.push(`AUDIO="${e.audio[0].groupId}"`);
for (const s of e.audio) t.push(nt(s))
}
if (e.video.length > 0) {
i.push(`VIDEO="${e.video[0].groupId}"`);
for (const s of e.video) t.push(nt(s))
}
if (e.subtitles.length > 0) {
i.push(`SUBTITLES="${e.subtitles[0].groupId}"`);
for (const s of e.subtitles) t.push(nt(s))
}
if (X().allowClosedCaptionsNone && 0 === e.closedCaptions.length) i.push("CLOSED-CAPTIONS=NONE"); else if (e.closedCaptions.length > 0) {
i.push(`CLOSED-CAPTIONS="${e.closedCaptions[0].groupId}"`);
for (const s of e.closedCaptions) t.push(nt(s))
}
if (e.score && i.push(`SCORE=${e.score}`), e.allowedCpc) {
const t = [];
for (const {format: s, cpcList: i} of e.allowedCpc) t.push(`${s}:${i.join("/")}`);
i.push(`ALLOWED-CPC="${t.join(",")}"`)
}
e.videoRange && i.push(`VIDEO-RANGE=${e.videoRange}`), e.stableVariantId && i.push(`STABLE-VARIANT-ID="${e.stableVariantId}"`), e.programId && i.push(`PROGRAM-ID=${e.programId}`), t.push(`${s}:${i.join(",")}`), e.isIFrameOnly || t.push(`${e.uri}`)
}
function nt(t) {
const e = [`TYPE=${t.type}`, `GROUP-ID="${t.groupId}"`, `NAME="${t.name}"`];
return void 0 !== t.isDefault && e.push("DEFAULT=" + (t.isDefault ? "YES" : "NO")), void 0 !== t.autoselect && e.push("AUTOSELECT=" + (t.autoselect ? "YES" : "NO")), void 0 !== t.forced && e.push("FORCED=" + (t.forced ? "YES" : "NO")), t.language && e.push(`LANGUAGE="${t.language}"`), t.assocLanguage && e.push(`ASSOC-LANGUAGE="${t.assocLanguage}"`), t.instreamId && e.push(`INSTREAM-ID="${t.instreamId}"`), t.characteristics && e.push(`CHARACTERISTICS="${t.characteristics}"`), t.channels && e.push(`CHANNELS="${t.channels}"`), t.uri && e.push(`URI="${t.uri}"`), `#EXT-X-MEDIA:${e.join(",")}`
}
function at(t, e, s, i, n = 1, a = null) {
let r = !1, o = "";
if (e.discontinuity && t.push("#EXT-X-DISCONTINUITY"), e.key) {
const i = st(e.key);
i !== s && (t.push(i), s = i)
}
if (e.map) {
const s = function (t) {
const e = [`URI="${t.uri}"`];
t.byterange && e.push(`BYTERANGE="${rt(t.byterange)}"`);
return `#EXT-X-MAP:${e.join(",")}`
}(e.map);
s !== i && (t.push(s), i = s)
}
if (e.programDateTime && t.push(`#EXT-X-PROGRAM-DATE-TIME:${l(e.programDateTime)}`), e.dateRange && t.push(function (t) {
const e = [`ID="${t.id}"`];
t.start && e.push(`START-DATE="${l(t.start)}"`);
t.end && e.push(`END-DATE="${l(t.end)}"`);
t.duration && e.push(`DURATION=${t.duration}`);
t.plannedDuration && e.push(`PLANNED-DURATION=${t.plannedDuration}`);
t.classId && e.push(`CLASS="${t.classId}"`);
t.endOnNext && e.push("END-ON-NEXT=YES");
for (const s of Object.keys(t.attributes)) s.startsWith("X-") ? "number" == typeof t.attributes[s] ? e.push(`${s}=${t.attributes[s]}`) : e.push(`${s}="${t.attributes[s]}"`) : s.startsWith("SCTE35-") && e.push(`${s}=${T(t.attributes[s])}`);
return `#EXT-X-DATERANGE:${e.join(",")}`
}(e.dateRange)), e.markers.length > 0 && (o = function (t, e) {
let s = "";
for (const i of e) if ("OUT" === i.type) s = "OUT", t.push(`#EXT-X-CUE-OUT:DURATION=${i.duration}`); else if ("IN" === i.type) s = "IN", t.push("#EXT-X-CUE-IN"); else if ("RAW" === i.type) {
const e = i.value ? `:${i.value}` : "";
t.push(`#${i.tagName}${e}`)
}
return s
}(t, e.markers)), e.parts.length > 0 && (r = function (t, e) {
let s = !1;
for (const i of e) if (i.hint) {
const e = [];
if (e.push("TYPE=PART", `URI="${i.uri}"`), i.byterange) {
const {offset: t, length: s} = i.byterange;
e.push(`BYTERANGE-START=${t}`), s && e.push(`BYTERANGE-LENGTH=${s}`)
}
t.push(`#EXT-X-PRELOAD-HINT:${e.join(",")}`), s = !0
} else {
const e = [];
e.push(`DURATION=${i.duration}`, `URI="${i.uri}"`), i.byterange && e.push(`BYTERANGE=${rt(i.byterange)}`), i.independent && e.push("INDEPENDENT=YES"), i.gap && e.push("GAP=YES"), t.push(`#EXT-X-PART:${e.join(",")}`)
}
return s
}(t, e.parts)), r) return [s, i];
const E = n < 3 ? Math.round(e.duration) : tt(e.duration, function (t) {
const e = t.toString(10), s = e.indexOf(".");
return -1 === s ? 0 : e.length - s - 1
}(e.duration));
return t.push(`#EXTINF:${E},${unescape(encodeURIComponent(e.title || ""))}`), e.byterange && t.push(`#EXT-X-BYTERANGE:${rt(e.byterange)}`), null != a ? Array.prototype.push.call(t, a(e)) : Array.prototype.push.call(t, `${e.uri}`), [s, i, o]
}
function rt({offset: t, length: e}) {
return `${e}@${t}`
}
function ot(t, e = null) {
n(t), s("Not a playlist", "playlist" === t.type);
const i = new J(t.uri);
return i.push("#EXTM3U"), t.version && i.push(`#EXT-X-VERSION:${t.version}`), t.independentSegments && i.push("#EXT-X-INDEPENDENT-SEGMENTS"), t.start && i.push(`#EXT-X-START:TIME-OFFSET=${tt(t.start.offset)}${t.start.precise ? ",PRECISE=YES" : ""}`), t.isMasterPlaylist ? function (t, e) {
for (const s of e.sessionDataList) t.push(et(s));
for (const s of e.sessionKeyList) t.push(st(s, !0));
for (const s of e.variants) it(t, s)
}(i, t) : function (t, e, s = null) {
let i = "", n = "", a = !1;
if (e.targetDuration && t.push(`#EXT-X-TARGETDURATION:${e.targetDuration}`), e.lowLatencyCompatibility) {
const {canBlockReload: s, canSkipUntil: i, holdBack: n, partHoldBack: a} = e.lowLatencyCompatibility,
r = [];
r.push("CAN-BLOCK-RELOAD=" + (s ? "YES" : "NO")), void 0 !== i && r.push(`CAN-SKIP-UNTIL=${i}`), void 0 !== n && r.push(`HOLD-BACK=${n}`), void 0 !== a && r.push(`PART-HOLD-BACK=${a}`), t.push(`#EXT-X-SERVER-CONTROL:${r.join(",")}`)
}
e.partTargetDuration && t.push(`#EXT-X-PART-INF:PART-TARGET=${e.partTargetDuration}`), e.mediaSequenceBase && t.push(`#EXT-X-MEDIA-SEQUENCE:${e.mediaSequenceBase}`), e.discontinuitySequenceBase && t.push(`#EXT-X-DISCONTINUITY-SEQUENCE:${e.discontinuitySequenceBase}`), e.playlistType && t.push(`#EXT-X-PLAYLIST-TYPE:${e.playlistType}`), e.isIFrame && t.push("#EXT-X-I-FRAMES-ONLY"), e.skip > 0 && t.push(`#EXT-X-SKIP:SKIPPED-SEGMENTS=${e.skip}`);
for (const r of e.segments) {
let o = "";
[i, n, o] = at(t, r, i, n, e.version, s), "OUT" === o ? a = !0 : "IN" === o && a && (a = !1)
}
"VOD" === e.playlistType && a && t.push("#EXT-X-CUE-IN"), e.prefetchSegments.length > 2 && r("The server must deliver no more than two prefetch segments");
for (const s of e.prefetchSegments) s.discontinuity && t.push("#EXT-X-PREFETCH-DISCONTINUITY"), t.push(`#EXT-X-PREFETCH:${s.uri}`);
e.endlist && t.push("#EXT-X-ENDLIST");
for (const s of e.renditionReports) {
const e = [];
e.push(`URI="${s.uri}"`, `LAST-MSN=${s.lastMSN}`), void 0 !== s.lastPart && e.push(`LAST-PART=${s.lastPart}`), t.push(`#EXT-X-RENDITION-REPORT:${e.join(",")}`)
}
}(i, t, e), i.join("\n")
}
export {X as getOptions, _ as parse, h as setOptions, ot as stringify, M as types};

441
JN/CATJS/lib/iso-2022-jp.js Normal file
View File

@ -0,0 +1,441 @@
import { inRange, decoderError, encoderError, isASCIICodePoint,
end_of_stream, finished, floor } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexPointerFor } from './text_decoder_indexes.js'
// 13.2 iso-2022-jp
// 13.2.1 iso-2022-jp decoder
/**
* @implements {Decoder}
*/
export class ISO2022JPDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
/** @enum */
this.states = {
ASCII: 0,
Roman: 1,
Katakana: 2,
LeadByte: 3,
TrailByte: 4,
EscapeStart: 5,
Escape: 6,
}
// iso-2022-jp's decoder has an associated iso-2022-jp decoder
// state (initially ASCII), iso-2022-jp decoder output state
// (initially ASCII), iso-2022-jp lead (initially 0x00), and
// iso-2022-jp output flag (initially unset).
this.iso2022jp_decoder_state = this.states.ASCII
this.iso2022jp_decoder_output_state = this.states.ASCII,
this.iso2022jp_lead = 0x00
this.iso2022jp_output_flag = false
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// switching on iso-2022-jp decoder state:
switch (this.iso2022jp_decoder_state) {
default:
case this.states.ASCII:
// ASCII
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x00 to 0x7F, excluding 0x0E, 0x0F, and 0x1B
if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E
&& bite !== 0x0F && bite !== 0x1B) {
// Unset the iso-2022-jp output flag and return a code point
// whose value is byte.
this.iso2022jp_output_flag = false
return bite
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.Roman:
// Roman
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x5C
if (bite === 0x5C) {
// Unset the iso-2022-jp output flag and return code point
// U+00A5.
this.iso2022jp_output_flag = false
return 0x00A5
}
// 0x7E
if (bite === 0x7E) {
// Unset the iso-2022-jp output flag and return code point
// U+203E.
this.iso2022jp_output_flag = false
return 0x203E
}
// 0x00 to 0x7F, excluding 0x0E, 0x0F, 0x1B, 0x5C, and 0x7E
if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E && bite !== 0x0F
&& bite !== 0x1B && bite !== 0x5C && bite !== 0x7E) {
// Unset the iso-2022-jp output flag and return a code point
// whose value is byte.
this.iso2022jp_output_flag = false
return bite
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.Katakana:
// Katakana
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x21 to 0x5F
if (inRange(bite, 0x21, 0x5F)) {
// Unset the iso-2022-jp output flag and return a code point
// whose value is 0xFF61 0x21 + byte.
this.iso2022jp_output_flag = false
return 0xFF61 - 0x21 + bite
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.LeadByte:
// Lead byte
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return null
}
// 0x21 to 0x7E
if (inRange(bite, 0x21, 0x7E)) {
// Unset the iso-2022-jp output flag, set iso-2022-jp lead
// to byte, iso-2022-jp decoder state to trail byte, and
// return continue.
this.iso2022jp_output_flag = false
this.iso2022jp_lead = bite
this.iso2022jp_decoder_state = this.states.TrailByte
return null
}
// end-of-stream
if (bite === end_of_stream) {
// Return finished.
return finished
}
// Otherwise
// Unset the iso-2022-jp output flag and return error.
this.iso2022jp_output_flag = false
return decoderError(this.fatal)
case this.states.TrailByte:
// Trail byte
// Based on byte:
// 0x1B
if (bite === 0x1B) {
// Set iso-2022-jp decoder state to escape start and return
// continue.
this.iso2022jp_decoder_state = this.states.EscapeStart
return decoderError(this.fatal)
}
// 0x21 to 0x7E
if (inRange(bite, 0x21, 0x7E)) {
// 1. Set the iso-2022-jp decoder state to lead byte.
this.iso2022jp_decoder_state = this.states.LeadByte
// 2. Let pointer be (iso-2022-jp lead 0x21) × 94 + byte 0x21.
const pointer = (this.iso2022jp_lead - 0x21) * 94 + bite - 0x21
// 3. Let code point be the index code point for pointer in
// index jis0208.
const code_point = indexCodePointFor(pointer, index('jis0208'))
// 4. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 5. Return a code point whose value is code point.
return code_point
}
// end-of-stream
if (bite === end_of_stream) {
// Set the iso-2022-jp decoder state to lead byte, prepend
// byte to stream, and return error.
this.iso2022jp_decoder_state = this.states.LeadByte
stream.prepend(bite)
return decoderError(this.fatal)
}
// Otherwise
// Set iso-2022-jp decoder state to lead byte and return
// error.
this.iso2022jp_decoder_state = this.states.LeadByte
return decoderError(this.fatal)
case this.states.EscapeStart:
// Escape start
// 1. If byte is either 0x24 or 0x28, set iso-2022-jp lead to
// byte, iso-2022-jp decoder state to escape, and return
// continue.
if (bite === 0x24 || bite === 0x28) {
this.iso2022jp_lead = bite
this.iso2022jp_decoder_state = this.states.Escape
return null
}
// 2. Prepend byte to stream.
stream.prepend(bite)
// 3. Unset the iso-2022-jp output flag, set iso-2022-jp
// decoder state to iso-2022-jp decoder output state, and
// return error.
this.iso2022jp_output_flag = false
this.iso2022jp_decoder_state = this.iso2022jp_decoder_output_state
return decoderError(this.fatal)
case this.states.Escape: {
// Escape
// 1. Let lead be iso-2022-jp lead and set iso-2022-jp lead to
// 0x00.
const lead = this.iso2022jp_lead
this.iso2022jp_lead = 0x00
// 2. Let state be null.
let state = null
// 3. If lead is 0x28 and byte is 0x42, set state to ASCII.
if (lead === 0x28 && bite === 0x42)
state = this.states.ASCII
// 4. If lead is 0x28 and byte is 0x4A, set state to Roman.
if (lead === 0x28 && bite === 0x4A)
state = this.states.Roman
// 5. If lead is 0x28 and byte is 0x49, set state to Katakana.
if (lead === 0x28 && bite === 0x49)
state = this.states.Katakana
// 6. If lead is 0x24 and byte is either 0x40 or 0x42, set
// state to lead byte.
if (lead === 0x24 && (bite === 0x40 || bite === 0x42))
state = this.states.LeadByte
// 7. If state is non-null, run these substeps:
if (state !== null) {
// 1. Set iso-2022-jp decoder state and iso-2022-jp decoder
// output state to this.states.
this.iso2022jp_decoder_state = this.iso2022jp_decoder_state = state
// 2. Let output flag be the iso-2022-jp output flag.
const output_flag = this.iso2022jp_output_flag
// 3. Set the iso-2022-jp output flag.
this.iso2022jp_output_flag = true
// 4. Return continue, if output flag is unset, and error
// otherwise.
return !output_flag ? null : decoderError(this.fatal)
}
// 8. Prepend lead and byte to stream.
stream.prepend([lead, bite])
// 9. Unset the iso-2022-jp output flag, set iso-2022-jp
// decoder state to iso-2022-jp decoder output state and
// return error.
this.iso2022jp_output_flag = false
this.iso2022jp_decoder_state = this.iso2022jp_decoder_output_state
return decoderError(this.fatal)
}
}
}
}
// 13.2.2 iso-2022-jp encoder
/**
* @implements {Encoder}
*/
export class ISO2022JPEncoder {
constructor() {
// iso-2022-jp's encoder has an associated iso-2022-jp encoder
// state which is one of ASCII, Roman, and jis0208 (initially
// ASCII).
/** @enum */
this.states = {
ASCII: 0,
Roman: 1,
jis0208: 2,
}
this.iso2022jp_state = this.states.ASCII
}
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream and iso-2022-jp encoder
// state is not ASCII, prepend code point to stream, set
// iso-2022-jp encoder state to ASCII, and return three bytes
// 0x1B 0x28 0x42.
if (code_point === end_of_stream &&
this.iso2022jp_state !== this.states.ASCII) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.ASCII
return [0x1B, 0x28, 0x42]
}
// 2. If code point is end-of-stream and iso-2022-jp encoder
// state is ASCII, return finished.
if (code_point === end_of_stream && this.iso2022jp_state === this.states.ASCII)
return finished
// 3. If ISO-2022-JP encoder state is ASCII or Roman, and code
// point is U+000E, U+000F, or U+001B, return error with U+FFFD.
if ((this.iso2022jp_state === this.states.ASCII ||
this.iso2022jp_state === this.states.Roman) &&
(code_point === 0x000E || code_point === 0x000F ||
code_point === 0x001B)) {
return encoderError(0xFFFD)
}
// 4. If iso-2022-jp encoder state is ASCII and code point is an
// ASCII code point, return a byte whose value is code point.
if (this.iso2022jp_state === this.states.ASCII &&
isASCIICodePoint(code_point))
return code_point
// 5. If iso-2022-jp encoder state is Roman and code point is an
// ASCII code point, excluding U+005C and U+007E, or is U+00A5
// or U+203E, run these substeps:
if (this.iso2022jp_state === this.states.Roman &&
((isASCIICodePoint(code_point) &&
code_point !== 0x005C && code_point !== 0x007E) ||
(code_point == 0x00A5 || code_point == 0x203E))) {
// 1. If code point is an ASCII code point, return a byte
// whose value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 2. If code point is U+00A5, return byte 0x5C.
if (code_point === 0x00A5)
return 0x5C
// 3. If code point is U+203E, return byte 0x7E.
if (code_point === 0x203E)
return 0x7E
}
// 6. If code point is an ASCII code point, and iso-2022-jp
// encoder state is not ASCII, prepend code point to stream, set
// iso-2022-jp encoder state to ASCII, and return three bytes
// 0x1B 0x28 0x42.
if (isASCIICodePoint(code_point) &&
this.iso2022jp_state !== this.states.ASCII) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.ASCII
return [0x1B, 0x28, 0x42]
}
// 7. If code point is either U+00A5 or U+203E, and iso-2022-jp
// encoder state is not Roman, prepend code point to stream, set
// iso-2022-jp encoder state to Roman, and return three bytes
// 0x1B 0x28 0x4A.
if ((code_point === 0x00A5 || code_point === 0x203E) &&
this.iso2022jp_state !== this.states.Roman) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.Roman
return [0x1B, 0x28, 0x4A]
}
// 8. If code point is U+2212, set it to U+FF0D.
if (code_point === 0x2212)
code_point = 0xFF0D
// 9. Let pointer be the index pointer for code point in index
// jis0208.
const pointer = indexPointerFor(code_point, index('jis0208'))
// 10. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 11. If iso-2022-jp encoder state is not jis0208, prepend code
// point to stream, set iso-2022-jp encoder state to jis0208,
// and return three bytes 0x1B 0x24 0x42.
if (this.iso2022jp_state !== this.states.jis0208) {
stream.prepend(code_point)
this.iso2022jp_state = this.states.jis0208
return [0x1B, 0x24, 0x42]
}
// 12. Let lead be floor(pointer / 94) + 0x21.
const lead = floor(pointer / 94) + 0x21
// 13. Let trail be pointer % 94 + 0x21.
const trail = pointer % 94 + 0x21
// 14. Return two bytes whose values are lead and trail.
return [lead, trail]
}
}

86
JN/CATJS/lib/log.js Normal file
View File

@ -0,0 +1,86 @@
const level_list = ["DEBUG", "INFO", "WARNING", "ERROR"];
const file_path = "log"
class JadeLogging {
constructor(app_name, level = "DEBUG") {
this.app_name = app_name
this.level = level
this.level_index = level_list.indexOf(level)
}
format(level, message) {
let max_format = 80
switch (level) {
case "INFO":
max_format = max_format + 1
break
case "WARNING":
max_format = max_format - 2
break
default :
break
}
if (message.length < max_format) {
if ((max_format - message.length) % 2 === 0) {
message = "#".repeat(Math.floor((max_format - message.length) / 2)) + message + "#".repeat(Math.floor((max_format - message.length) / 2))
} else {
message = "#".repeat(Math.floor((max_format - message.length) / 2)) + message + "#".repeat(Math.floor((max_format - message.length) / 2) + 1)
}
}
return message
}
getTime() {
const timestamp = new Date();
// 获取当前时间戳
return timestamp.toLocaleDateString().replace(/\//g, "-") + " " + timestamp.toTimeString().substr(0, 8) + "," + timestamp.getMilliseconds().toString()
}
formatMessage(log_level, message, is_format) {
// 获取北京时间
// 格式化消息
//2023-12-13 15:15:21,409 - 阿里玩偶 -
//2023-12-14T01:43:31.278Z
//2023-12-13 15:15:21,409 - 阿里玩偶 - INFO:
//2023-12-13 15:15:21,409 - 阿里玩偶 - ERROR:
if (is_format) {
message = this.format(log_level, message)
}
return `${this.getTime()} - ${this.app_name} - ${log_level}: ${message}`
}
async log(message) {
console.debug(message)
await local.set(file_path,this.getTime(), message);
}
async info(message, is_format=false) {
if (this.level_index <= 1) {
await this.log(this.formatMessage("INFO", message, is_format))
}
}
async warning(message, is_format=false) {
if (this.level_index <= 2) {
await this.log(this.formatMessage("WARNING", message, is_format))
}
}
async error(message, is_format=false) {
if (this.level_index <= 3) {
await this.log(this.formatMessage("ERROR", message, is_format))
}
}
async debug(message, is_format=false) {
if (this.level_index <= 0) {
await this.log(this.formatMessage("DEBUG", message, is_format))
}
}
}
// 测试日志记录函数
export {JadeLogging}

129
JN/CATJS/lib/misc.js Normal file
View File

@ -0,0 +1,129 @@
var charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
export function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export function randStr(len, withNum, onlyNum) {
var _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (var i = 0; i < len; i++) {
let idx = onlyNum ? rand(charStr.length - 10, charStr.length - 1) : rand(0, containsNum ? charStr.length - 1 : charStr.length - 11);
_str += charStr[idx];
}
return _str;
}
export function randUUID() {
return randStr(8).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(12).toLowerCase();
}
export function randMAC() {
return randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase() + ':' + randStr(2).toUpperCase();
}
const deviceBrands = ['Huawei', 'Xiaomi'];
const deviceModels = [
['MHA-AL00', 'HUAWEI Mate 9', 'MHA-TL00', 'HUAWEI Mate 9', 'LON-AL00', 'HUAWEI Mate 9 Pro', 'ALP-AL00', 'HUAWEI Mate 10', 'ALP-TL00', 'HUAWEI Mate 10', 'BLA-AL00', 'HUAWEI Mate 10 Pro', 'BLA-TL00', 'HUAWEI Mate 10 Pro', 'HMA-AL00', 'HUAWEI Mate 20', 'HMA-TL00', 'HUAWEI Mate 20', 'LYA-AL00', 'HUAWEI Mate 20 Pro', 'LYA-AL10', 'HUAWEI Mate 20 Pro', 'LYA-TL00', 'HUAWEI Mate 20 Pro', 'EVR-AL00', 'HUAWEI Mate 20 X', 'EVR-TL00', 'HUAWEI Mate 20 X', 'EVR-AN00', 'HUAWEI Mate 20 X', 'TAS-AL00', 'HUAWEI Mate 30', 'TAS-TL00', 'HUAWEI Mate 30', 'TAS-AN00', 'HUAWEI Mate 30', 'TAS-TN00', 'HUAWEI Mate 30', 'LIO-AL00', 'HUAWEI Mate 30 Pro', 'LIO-TL00', 'HUAWEI Mate 30 Pro', 'LIO-AN00', 'HUAWEI Mate 30 Pro', 'LIO-TN00', 'HUAWEI Mate 30 Pro', 'LIO-AN00m', 'HUAWEI Mate 30E Pro', 'OCE-AN10', 'HUAWEI Mate 40', 'OCE-AN50', 'HUAWEI Mate 40E', 'OCE-AL50', 'HUAWEI Mate 40E', 'NOH-AN00', 'HUAWEI Mate 40 Pro', 'NOH-AN01', 'HUAWEI Mate 40 Pro', 'NOH-AL00', 'HUAWEI Mate 40 Pro', 'NOH-AL10', 'HUAWEI Mate 40 Pro', 'NOH-AN50', 'HUAWEI Mate 40E Pro', 'NOP-AN00', 'HUAWEI Mate 40 Pro', 'CET-AL00', 'HUAWEI Mate 50', 'CET-AL60', 'HUAWEI Mate 50E', 'DCO-AL00', 'HUAWEI Mate 50 Pro', 'TAH-AN00', 'HUAWEI Mate X', 'TAH-AN00m', 'HUAWEI Mate Xs', 'TET-AN00', 'HUAWEI Mate X2', 'TET-AN10', 'HUAWEI Mate X2', 'TET-AN50', 'HUAWEI Mate X2', 'TET-AL00', 'HUAWEI Mate X2', 'PAL-AL00', 'HUAWEI Mate Xs 2', 'PAL-AL10', 'HUAWEI Mate Xs 2', 'EVA-AL00', 'HUAWEI P9', 'EVA-AL10', 'HUAWEI P9', 'EVA-TL00', 'HUAWEI P9', 'EVA-DL00', 'HUAWEI P9', 'EVA-CL00', 'HUAWEI P9', 'VIE-AL10', 'HUAWEI P9 Plus', 'VTR-AL00', 'HUAWEI P10', 'VTR-TL00', 'HUAWEI P10', 'VKY-AL00', 'HUAWEI P10 Plus', 'VKY-TL00', 'HUAWEI P10 Plus', 'EML-AL00', 'HUAWEI P20', 'EML-TL00', 'HUAWEI P20', 'CLT-AL00', 'HUAWEI P20 Pro', 'CLT-AL01', 'HUAWEI P20 Pro', 'CLT-AL00l', 'HUAWEI P20 Pro', 'CLT-TL00', 'HUAWEI P20 Pro', 'CLT-TL01', 'HUAWEI P20 Pro', 'ELE-AL00', 'HUAWEI P30', 'ELE-TL00', 'HUAWEI P30', 'VOG-AL00', 'HUAWEI P30 Pro', 'VOG-AL10', 'HUAWEI P30 Pro', 'VOG-TL00', 'HUAWEI P30 Pro', 'ANA-AL00', 'HUAWEI P40', 'ANA-AN00', 'HUAWEI P40', 'ANA-TN00', 'HUAWEI P40', 'ELS-AN00', 'HUAWEI P40 Pro', 'ELS-TN00', 'HUAWEI P40 Pro', 'ELS-AN10', 'HUAWEI P40 Pro', 'ELS-TN10', 'HUAWEI P40 Pro', 'ABR-AL00', 'HUAWEI P50', 'ABR-AL80', 'HUAWEI P50', 'ABR-AL60', 'HUAWEI P50E', 'ABR-AL90', 'HUAWEI P50E', 'JAD-AL00', 'HUAWEI P50 Pro', 'JAD-AL80', 'HUAWEI P50 Pro', 'JAD-AL50', 'HUAWEI P50 Pro', 'JAD-AL60', 'HUAWEI P50 Pro', 'BAL-AL00', 'HUAWEI P50 Pocket', 'BAL-AL60', 'HUAWEI Pocket S', 'PIC-AL00', 'HUAWEI nova 2', 'PIC-TL00', 'HUAWEI nova 2', 'BAC-AL00', 'HUAWEI nova 2 Plus', 'BAC-TL00', 'HUAWEI nova 2 Plus', 'HWI-AL00', 'HUAWEI nova 2s', 'HWI-TL00', 'HUAWEI nova 2s', 'ANE-AL00', 'HUAWEI nova 3e', 'ANE-TL00', 'HUAWEI nova 3e', 'PAR-AL00', 'HUAWEI nova 3', 'PAR-TL00', 'HUAWEI nova 3', 'INE-AL00', 'HUAWEI nova 3i', 'INE-TL00', 'HUAWEI nova 3i', 'VCE-AL00', 'HUAWEI nova 4', 'VCE-TL00', 'HUAWEI nova 4', 'MAR-AL00', 'HUAWEI nova 4e', 'MAR-TL00', 'HUAWEI nova 4e', 'SEA-AL00', 'HUAWEI nova 5', 'SEA-TL00', 'HUAWEI nova 5', 'SEA-AL10', 'HUAWEI nova 5 Pro', 'SEA-TL10', 'HUAWEI nova 5 Pro', 'GLK-AL00', 'HUAWEI nova 5i', 'GLK-TL00', 'HUAWEI nova 5i', 'GLK-LX1U', 'HUAWEI nova 5i', 'SPN-TL00', 'HUAWEI nova 5i Pro', 'SPN-AL00', 'HUAWEI nova 5z', 'WLZ-AL10', 'HUAWEI nova 6', 'WLZ-AN00', 'HUAWEI nova 6', 'JNY-AL10', 'HUAWEI nova 6 SE', 'JNY-TL10', 'HUAWEI nova 6 SE', 'JEF-AN00', 'HUAWEI nova 7', 'JEF-AN20', 'HUAWEI nova 7', 'JEF-TN00', 'HUAWEI nova 7', 'JEF-TN20', 'HUAWEI nova 7', 'JER-AN10', 'HUAWEI nova 7 Pro', 'JER-AN20', 'HUAWEI nova 7 Pro', 'JER-TN10', 'HUAWEI nova 7 Pro', 'JER-TN20', 'HUAWEI nova 7 Pro', 'CDY-AN00', 'HUAWEI nova 7 SE', 'CDY-AN20', 'HUAWEI nova 7 SE', 'CDY-TN00', 'HUAWEI nova 7 SE', 'CDY-TN20', 'HUAWEI nova 7 SE', 'ANG-AN00', 'HUAWEI nova 8', 'BRQ-AN00', 'HUAWEI nova 8 Pro', 'BRQ-AL00', 'HUAWEI nova 8 Pro', 'JSC-AN00', 'HUAWEI nova 8 SE', 'JSC-TN00', 'HUAWEI nova 8 SE', 'JSC-AL50', 'HUAWEI nova 8 SE', 'NAM-AL00', 'HUAWEI nova 9', 'RTE-AL00', 'HUAWEI nova 9 Pro', 'JLN-AL00', 'HUAWEI nova 9 SE', 'NCO-AL00', 'HUAWEI nova 10', 'GLA-AL00', 'HUAWEI nova 10 Pro', 'CHA-AL80', 'HUAWEI nova 10z'],
['M2001J2C', 'Xiaomi 10', 'M2001J2G', 'Xiaomi 10', 'M2001J2I', 'Xiaomi 10', 'M2011K2C', 'Xiaomi 11', 'M2011K2G', 'Xiaomi 11', '2201123C', 'Xiaomi 12', '2201123G', 'Xiaomi 12', '2112123AC', 'Xiaomi 12X', '2112123AG', 'Xiaomi 12X', '2201122C', 'Xiaomi 12 Pro', '2201122G', 'Xiaomi 12 Pro'],
];
export function randDevice() {
let brandIdx = rand(0, deviceBrands.length - 1);
let brand = deviceBrands[brandIdx];
let modelIdx = rand(0, deviceModels[brandIdx].length / 2 - 1);
let model = deviceModels[brandIdx][modelIdx * 2 + 1];
let release = rand(8, 13);
let buildId = randStr(3, false).toUpperCase() + rand(11, 99) + randStr(1, false).toUpperCase();
return {
brand: brand,
model: model,
release: release,
buildId: buildId,
};
}
export function randDeviceWithId(len) {
let device = randDevice();
device['id'] = randStr(len);
return device;
}
export const MOBILE_UA = 'Mozilla/5.0 (Linux; Android 11; M2007J3SC Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 MQQBrowser/6.2 TBS/045714 Mobile Safari/537.36';
export const PC_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36';
export const UA = 'Mozilla/5.0';
export const UC_UA = 'Mozilla/5.0 (Linux; U; Android 9; zh-CN; MI 9 Build/PKQ1.181121.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.5.1035 Mobile Safari/537.36';
export const IOS_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1';
export const MAC_UA = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X MetaSr 1.0';
export function formatPlayUrl(src, name) {
if (src.trim() == name.trim()) {
return name;
}
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
export function formatPlayUrl2(src, name) {
var idx = name.indexOf('$');
if (idx <= 0) {
return formatPlayUrl(src, name);
}
return formatPlayUrl(src, name.substring(0, idx)) + name.substring(idx);
}
export function stripHtmlTag(src) {
return src
.replace(/<\/?[^>]+(>|$)/g, '')
.replace(/&.{1,5};/g, '')
.replace(/\s{2,}/g, ' ');
}
export function fixUrl(base, src) {
try {
if (src.startsWith('//')) {
let parse = new URL(base);
let host = src.substring(2, src.indexOf('/', 2));
if (!host.includes('.')) {
src = parse.protocol + '://' + parse.host + src.substring(1);
} else {
src = parse.protocol + ':' + src;
}
} else if (!src.includes('://')) {
let parse = new URL(base);
src = parse.protocol + '://' + parse.host + src;
}
} catch (error) {}
return src;
}
export function jsonParse(input, json) {
try {
let url = json.url || '';
if (url.startsWith('//')) {
url = 'https:' + url;
}
if (!url.startsWith('http')) {
return {};
}
let headers = json['headers'] || {};
let ua = (json['user-agent'] || '').trim();
if (ua.length > 0) {
headers['User-Agent'] = ua;
}
let referer = (json['referer'] || '').trim();
if (referer.length > 0) {
headers['Referer'] = referer;
}
return {
header: headers,
url: url,
};
} catch (error) {
console.log(error);
}
return {};
}

View File

@ -0,0 +1,255 @@
/*
* @File : nivid_object.js
* @Author : jade
* @Date : 2023/12/20 9:50
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Crypto} from "./cat.js";
let DesKey = "diao.com"
class ChannelResponse {
// classes
constructor() {
this.channelMsg = ""
this.channelStatus = 0
this.channelList = []
this.channelFilters = {}
}
fromJsonString(json_str, remove18ChannelCode = 0) {
let json_dic = JSON.parse(json_str)
this.channelMsg = json_dic.msg
this.channelStatus = json_dic.status
let channel_list = []
for (const channel_info of json_dic.list) {
let new_channel_info = new ChannelInfo()
switch (remove18ChannelCode) {
case 0:
new_channel_info.fromJson(channel_info)
channel_list.push(new_channel_info)
break
case 1:
if (channel_info.channelName !== "午夜场" && channel_info.channelName !== "午夜直播") {
new_channel_info.fromJson(channel_info)
channel_list.push(new_channel_info)
}
break
case 2:
if (channel_info.channelName === "午夜场" || channel_info.channelName === "午夜直播") {
new_channel_info.fromJson(channel_info)
channel_list.push(new_channel_info)
}
break
}
}
this.channelList = channel_list
this.channelFilters = json_dic.filter
}
setChannelFilters(filter_str) {
this.channelFilters = JSON.parse(filter_str)
}
getValues(typeList, name_key, id_key) {
let values = []
values.push({"n": "全部", "v": "0"})
for (const obj of typeList) {
values.push({"n": obj[name_key], "v": obj[id_key].toString()})
}
return values
}
getFilters() {
let filters = {}
for (const channel_info of this.channelList) {
filters[channel_info.channelId] = []
let sortMapList = this.channelFilters["sortsMap"][parseInt(channel_info.channelId)]
let sortValues = this.getValues(sortMapList, "title", "id")
filters[channel_info.channelId].push({"key": "1", "name": "排序", "value": sortValues})
let typeMapList = this.channelFilters["typesMap"][parseInt(channel_info.channelId)]
let typeValues = this.getValues(typeMapList, "showTypeName", "showTypeId")
filters[channel_info.channelId].push({"key": "2", "name": "类型", "value": typeValues})
let areaValues = this.getValues(this.channelFilters["regions"], "regionName", "regionId")
filters[channel_info.channelId].push({"key": "3", "name": "地区", "value": areaValues})
let langValues = this.getValues(this.channelFilters["langs"], "langName", "langId")
filters[channel_info.channelId].push({"key": "4", "name": "语言", "value": langValues})
let yearValues = this.getValues(this.channelFilters["yearRanges"], "name", "code")
filters[channel_info.channelId].push({"key": "5", "name": "年份", "value": yearValues})
}
return filters
}
getChannelFilters() {
return this.channelFilters
}
getChannelMsg() {
return this.channelMsg
}
getChannelStatus() {
return this.channelStatus
}
getChannelList() {
return this.channelList
}
getClassList() {
let classes = []
for (const channel_info of this.channelList) {
classes.push({"type_id": channel_info.channelId, "type_name": channel_info.channelName})
}
return classes
}
async save() {
await local.set("niba", "niba_channel", this.toString());
return this;
}
clear() {
this.channelMsg = ""
this.channelStatus = 0
this.channelList = []
}
async clearCache() {
this.clear()
await local.set("niba", "niba_channel", "{}");
}
toString() {
const params = {
msg: this.getChannelMsg(),
status: this.getChannelStatus(),
list: this.getChannelList(),
filter: this.getChannelFilters()
};
return JSON.stringify(params);
}
}
async function getChannelCache() {
return await local.get("niba", "niba_channel");
}
class ChannelInfo {
constructor() {
this.channelId = 0
this.channelName = ""
}
fromJsonString(json_str) {
let json_dic = JSON.parse(json_str)
this.channelId = json_dic.channelId
this.channelName = json_dic.channelName
}
fromJson(json) {
this.channelId = json.channelId
this.channelName = json.channelName
}
getChannelName() {
return this.channelName
}
getChannelId() {
return this.channelId
}
}
function isNumeric(str) {
return !isNaN(parseInt(str));
}
function getVod(video_dic_list, play_foramt_list, showIdCode) {
let episode_list = [], episode_str_list = [];
for (const video_dic of video_dic_list) {
let video_name = ""
if (isNumeric((video_dic['episodeName']))) {
video_name = "第" + video_dic["episodeName"] + "集"
} else {
video_name = video_dic["episodeName"]
}
episode_list.push(video_name + "$" + video_dic["playIdCode"] + "@" + showIdCode);
}
for (let index = 0; index < play_foramt_list.length; index++) {
episode_str_list.push(episode_list.join("#"));
}
return {
vod_play_url: episode_str_list.join("$$$"),
vod_play_from: play_foramt_list.map(item => item).join("$$$"),
};
}
function getHeader() {
return {
"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",
"Referer": "https://m.nivod.tv/",
"Content-Type": "application/x-www-form-urlencoded"
}
}
function md5(text) {
return Crypto.MD5(text).toString()
}
//加密
async function createSign(body = null) {
let params = {
"_ts": Date.now(), "app_version": "1.0",
"platform": "3", "market_id": "web_nivod",
"device_code": "web", "versioncode": 1,
"oid": "8ca275aa5e12ba504b266d4c70d95d77a0c2eac5726198ea"
}
/**
* __QUERY::_ts=1702973558399&app_version=1.0&device_code=web&market_id=web_nivod&oid=8ca275aa5e12ba504b266d4c70d95d77a0c2eac5726198ea&platform=3&versioncode=1&__BODY::__KEY::2x_Give_it_a_shot
*/
let params_list = []
for (const key of Object.keys(params).sort()) {
params_list.push(`${key}=${params[key]}`)
}
let body_str = "&__BODY::"
if (body !== null) {
let body_list = []
for (const key of Object.keys(body).sort()) {
body_list.push(`${key}=${body[key]}`)
}
body_str = body_str + body_list.join("&") + "&"
}
let params_str = "__QUERY::" + params_list.join("&") + body_str + "__KEY::2x_Give_it_a_shot"
let sign_code = md5(params_str)
params_list.push(`sign=${sign_code}`)
return "?" + params_list.join("&")
}
//解密
function desDecrypt(content) {
// 定义密钥
const key = Crypto.enc.Utf8.parse(DesKey); // 密钥需要进行字节数转换
/*
const encrypted = Crypto.DES.encrypt(content, key, {
mode: Crypto.mode.ECB, // 使用ECB模式
padding: Crypto.pad.Pkcs7, // 使用Pkcs7填充
}).ciphertext.toString();
*/
return Crypto.DES.decrypt({ciphertext: Crypto.enc.Hex.parse(content)}, key, {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7,
}).toString(Crypto.enc.Utf8);
}
export {getChannelCache, desDecrypt, createSign, ChannelResponse, getHeader, getVod};

View File

@ -0,0 +1,146 @@
/*
* @File : pipiXiaObject.js
* @Author : jade
* @Date : 2024/2/4 14:33
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
const UID = "DCC147D11943AF75"
const chrsz = 8;
const hexcase = 0;
function hex_md5(s) {
return binl2hex(core_md5(str2binl(s), s.length * chrsz))
}
function str2binl(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
return bin
}
function core_md5(x, len) {
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd)
}
return Array(a, b, c, d)
}
function md5_gg(a, b, c, d, x, s, t) {
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)
}
function md5_ff(a, b, c, d, x, s, t) {
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)
}
function md5_hh(a, b, c, d, x, s, t) {
return md5_cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t)
}
function md5_cmn(q, a, b, x, s, t) {
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
}
function safe_add(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF)
}
function bit_rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
function binl2hex(binarray) {
let hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
let str = "";
for (let i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF)
}
return str
}
function pipixiaMd5(date_time) {
return hex_md5('DS' + date_time + UID)
}
export {pipixiaMd5}
// let key = pipixiaMd5(Math.floor(new Date() / 1000),"DCC147D11943AF75")
// let x = 0

63
JN/CATJS/lib/quark.js Normal file
View File

@ -0,0 +1,63 @@
/**
* File: h:\PycharmProjects\Github\TVSpider\lib\quark.js
* Project: h:\PycharmProjects\Github\TVSpider
* Created Date: Monday, May 20th 2024, 4:54:26 pm
* Author: jade
* -----
* Last Modified: Tue May 21 2024
* Modified By: jade
* -----
* Copyright (c) 2024 samples
* ------------------------------------
* Javascript will save your soul!
*/
import {JadeLogging} from "./log.js";
import {Quark} from "./quark_api.js"
const quarkName = "夸克云盘"
const JadeLog = new JadeLogging(quarkName)
const quarkPlayFormatList = ["普画"]
const quark = new Quark()
async function initQuark(cookie) {
quark.initQuark(cookie)
await JadeLog.info(`夸克云盘初始化完成,Cookie为:${cookie}`, true)
}
async function detailContentQuark(share_url_list, type_name = "电影") {
try {
let video_items = [], sub_items = []
for (let i=0;i<share_url_list.length;i++){
let share_url = share_url_list[i]
await quark.getFilesByShareUrl(i+1,share_url,video_items,sub_items)
}
if (video_items.length > 0) {
await JadeLog.info(`获取播放链接成功,分享链接为:${share_url_list.join("\t")}`)
} else {
await JadeLog.error(`获取播放链接失败,检查分享链接为:${share_url_list.join("\t")}`)
}
return {"video_items":video_items,"sub_items":sub_items}
} catch (e) {
await JadeLog.error('获取夸克视频失败,失败原因为:' + e.message + ' 行数为:' + e.lineNumber);
}
}
async function playContentQuark(flag, id, flags){
let id_list = id.split("++")
let shareId = id_list[2],stoken = id_list[3], fileId = id_list[0], fileToken = id_list[1]
let playUrl = ""
if (flag.indexOf("原画") > -1){
playUrl = (await quark.getDownload(shareId, stoken, fileId, fileToken,true)).download_url
}else if (flag.indexOf("普画") > -1){
playUrl = (await quark.getLiveTranscoding(shareId, stoken, fileId, fileToken,true)).slice(-1)[0]["video_info"].url
}
return playUrl
}
function getQuarkHeaders(){
let headers = quark.getHeaders()
delete headers["Host"]
return headers
}
export {initQuark,detailContentQuark,playContentQuark,quarkPlayFormatList,quarkName,getQuarkHeaders}

282
JN/CATJS/lib/quark_api.js Normal file
View File

@ -0,0 +1,282 @@
/**
* File: /workspaces/TVSpider/lib/quark_api.js
* Project: /workspaces/TVSpider
* Created Date: Monday, May 20th 2024, 6:38:12 am
* Author: jade
* -----
* Last Modified: Tue May 21 2024
* Modified By: jade
* -----
* Copyright (c) 2024 samples
* ------------------------------------
* Javascript will save your soul!
*/
import {_,Crypto} from "../lib/cat.js";
import * as Utils from "../lib/utils.js"
import {Item} from "../lib/quark_object.js"
class Quark{
constructor(){
this.apiUrl = "https://drive-pc.quark.cn/1/clouddrive/"
this.cookie = ""
this.ckey = ""
this.shareTokenCache = {}
this.pr = "pr=ucpro&fr=pc"
this.subtitleExts = ['.srt', '.ass', '.scc', '.stl', '.ttml'];
this.saveFileIdCaches = {}
this.saveDirId = null
this.saveDirName = 'TV';
}
async initQuark(cookie) {
this.ckey = Crypto.enc.Hex.stringify(Crypto.MD5(cookie)).toString();
let localCfg = await local.get("quark", "cookie");
if (!_.isEmpty(localCfg)){
this.cookie = JSON.parse(localCfg)[this.ckey]
}else{
this.cookie = cookie
}
}
getHeaders(){
return {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch',
'Referer': 'https://pan.quark.cn/',
"Content-Type":"application/json",
"Cookie":this.cookie,
"Host":"drive-pc.quark.cn"
};
}
async api(url,data,retry,method){
const leftRetry = retry || 3;
let resp = await req(this.apiUrl + url,{
method:method || "post",
data:data,
headers:this.getHeaders()
})
if (resp.headers['set-cookie']) {
const puus = [resp.headers['set-cookie']].join(';;;').match(/__puus=([^;]+)/);
if (puus) {
if (this.cookie.match(/__puus=([^;]+)/)[1] != puus[1]) {
this.cookie = this.cookie.replace(/__puus=[^;]+/, `__puus=${puus[1]}`);
let cookieDic = {}
cookieDic[this.ckey] = this.cookie
await local.set("quark",this.cookie, JSON.stringify(cookieDic));
}
}
}
if (resp.code !== 200 && leftRetry > 0) {
Utils.sleep(1)
return await this.api(url, data, leftRetry - 1);
}
return JSON.parse(resp.content) || {};
}
getShareData(url) {
let regex = /https:\/\/pan\.quark\.cn\/s\/([^\\|#/]+)/;
let matches = regex.exec(url);
if (matches) {
return {
shareId: matches[1],
folderId: '0',
};
}
return null;
}
async getShareToken(shareData) {
if (!this.shareTokenCache[shareData.shareId]) {
delete this.shareTokenCache[shareData.shareId];
const shareToken = await this.api(`share/sharepage/token?${this.pr}`, {
pwd_id: shareData.shareId,
passcode: shareData.sharePwd || '',
});
if (shareToken.data && shareToken.data.stoken) {
this.shareTokenCache[shareData.shareId] = shareToken.data;
}
}
}
async listFile (shareIndex,shareData,videos,subtitles,shareId, folderId, page) {
const prePage = 200;
page = page || 1;
const listData = await this.api(`share/sharepage/detail?${this.pr}&pwd_id=${shareId}&stoken=${encodeURIComponent(this.shareTokenCache[shareId].stoken)}&pdir_fid=${folderId}&force=0&_page=${page}&_size=${prePage}&_sort=file_type:asc,file_name:asc`, null,null, 'get');
if (!listData.data) return [];
const items = listData.data.list;
if (!items) return [];
const subDir = [];
for (const item of items) {
if (item.dir === true) {
subDir.push(item);
} else if (item.file === true && item.obj_category === 'video') {
if (item.size < 1024 * 1024 * 5) continue;
item.stoken = this.shareTokenCache[shareData.shareId].stoken;
videos.push(Item.objectFrom(item,shareData.shareId,shareIndex));
} else if (item.type === 'file' && this.subtitleExts.some((x) => item.file_name.endsWith(x))) {
subtitles.push(Item.objectFrom(item,shareData,shareIndex));
}
}
if (page < Math.ceil(listData.metadata._total / prePage)) {
const nextItems = await this.listFile(shareIndex,shareData.shareId,videos,subtitles,shareId, folderId, page + 1);
for (const item of nextItems) {
items.push(item);
}
}
for (const dir of subDir) {
const subItems = await this.listFile(shareIndex,shareData,videos,subtitles,shareId, dir.fid);
for (const item of subItems) {
items.push(item);
}
}
return items;
};
findBestLCS(mainItem, targetItems) {
const results = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetItems.length; i++) {
const currentLCS = Utils.lcs(mainItem.name, targetItems[i].name);
results.push({ target: targetItems[i], lcs: currentLCS });
if (currentLCS.length > results[bestMatchIndex].lcs.length) {
bestMatchIndex = i;
}
}
const bestMatch = results[bestMatchIndex];
return { allLCS: results, bestMatch: bestMatch, bestMatchIndex: bestMatchIndex };
}
async getFilesByShareUrl(shareIndex,shareInfo,videos,subtitles){
const shareData = typeof shareInfo === 'string' ? this.getShareData(shareInfo) : shareInfo;
if (!shareData) return [];
await this.getShareToken(shareData);
if (!this.shareTokenCache[shareData.shareId]) return [];
await this.listFile(shareIndex,shareData,videos,subtitles,shareData.shareId, shareData.folderId);
if (subtitles.length > 0) {
videos.forEach((item) => {
var matchSubtitle = this.findBestLCS(item, subtitles);
if (matchSubtitle.bestMatch) {
item.subtitle = matchSubtitle.bestMatch.target;
}
});
}
}
clean(){
const saves = Object.keys(this.saveFileIdCaches);
for (const save of saves) {
delete this.saveFileIdCaches[save];
}
}
async clearSaveDir() {
const listData = await this.api(`file/sort?${this.pr}&pdir_fid=${this.saveDirId}&_page=1&_size=200&_sort=file_type:asc,updated_at:desc`, {}, {}, 'get');
if (listData.data && listData.data.list && listData.data.list.length > 0) {
await this.api(`file/delete?${this.pr}`, {
action_type: 2,
filelist: listData.data.list.map((v) => v.fid),
exclude_fids: [],
});
}
}
async createSaveDir(clean) {
if (this.saveDirId) {
// 删除所有子文件
if (clean) await this.clearSaveDir();
return;
}
const listData = await this.api(`file/sort?${this.pr}&pdir_fid=0&_page=1&_size=200&_sort=file_type:asc,updated_at:desc`, {}, {}, 'get');
if (listData.data && listData.data.list)
for (const item of listData.data.list) {
if (item.file_name === this.saveDirName) {
this.saveDirId = item.fid;
await this.clearSaveDir();
break;
}
}
if (!this.saveDirId) {
const create = await this.api(`file?${this.pr}`, {
pdir_fid: '0',
file_name: this.saveDirName,
dir_path: '',
dir_init_lock: false,
});
if (create.data && create.data.fid) {
this.saveDirId = create.data.fid;
}
}
}
async save(shareId, stoken, fileId, fileToken, clean) {
await this.createSaveDir(clean);
if (clean) {
this.clean()
}
if (!this.saveDirId) return null;
if (!stoken) {
await this.getShareToken({
shareId: shareId,
});
if (!this.shareTokenCache[shareId]) return null;
}
const saveResult = await this.api(`share/sharepage/save?${this.pr}`, {
fid_list: [fileId],
fid_token_list: [fileToken],
to_pdir_fid: this.saveDirId,
pwd_id: shareId,
stoken: stoken || this.shareTokenCache[shareId].stoken,
pdir_fid: '0',
scene: 'link',
});
if (saveResult.data && saveResult.data.task_id) {
let retry = 0;
// wait task finish
while (true) {
const taskResult = await this.api(`task?${this.pr}&task_id=${saveResult.data.task_id}&retry_index=${retry}`, {}, {}, 'get');
if (taskResult.data && taskResult.data.save_as && taskResult.data.save_as.save_as_top_fids && taskResult.data.save_as.save_as_top_fids.length > 0) {
return taskResult.data.save_as.save_as_top_fids[0];
}
retry++;
if (retry > 2) break;
Utils.sleep(1);
}
}
return false;
}
async getLiveTranscoding(shareId, stoken, fileId, fileToken) {
if (!this.saveFileIdCaches[fileId]) {
const saveFileId = await this.save(shareId, stoken, fileId, fileToken, true);
if (!saveFileId) return null;
this.saveFileIdCaches[fileId] = saveFileId;
}
const transcoding = await this.api(`file/v2/play?${this.pr}`, {
fid: this.saveFileIdCaches[fileId],
resolutions: 'normal,low,high,super,2k,4k',
supports: 'fmp4',
});
if (transcoding.data && transcoding.data.video_list) {
return transcoding.data.video_list;
}
return null;
}
async getDownload(shareId, stoken, fileId, fileToken, clean) {
if (!this.saveFileIdCaches[fileId]) {
const saveFileId = await this.save(shareId, stoken, fileId, fileToken, clean);
if (!saveFileId) return null;
this.saveFileIdCaches[fileId] = saveFileId;
}
const down = await this.api(`file/download?${this.pr}&uc_param_str=`, {
fids: [this.saveFileIdCaches[fileId]],
});
if (down.data) {
return down.data[0];
}
return null;
}
}
export {Quark}

View File

@ -0,0 +1,98 @@
/**
* File: h:\PycharmProjects\Github\TVSpider\lib\quark_object.js
* Project: h:\PycharmProjects\Github\TVSpider
* Created Date: Monday, May 20th 2024, 5:26:45 pm
* Author: jade
* -----
* Last Modified: Tue May 21 2024
* Modified By: jade
* -----
* Copyright (c) 2024 samples
* ------------------------------------
* Javascript will save your soul!
*/
import {_} from "../lib/cat.js";
import * as Utils from "./utils.js";
class Item {
constructor() {
this.fileId = "";
this.shareId = ""
this.shareToken = "";
this.shareFileToken = ""
this.seriesId = ""
this.name = "";
this.type = "";
this.formatType = "";
this.size = "";
this.parent = "";
this.shareData = null;
this.shareIndex = 0;
this.lastUpdateAt = 0
}
static objectFrom(item_json, shareId,shareIndex) {
let item = new Item();
item.fileId = typeof item_json.fid == undefined ? "" : item_json.fid;
item.shareId = shareId
item.shareToken = typeof item_json.stoken == undefined ? "" : item_json.stoken;
item.shareFileToken = typeof item_json.share_fid_token == undefined ? "" : item_json.share_fid_token;
item.seriesId = typeof item_json.series_id == undefined? "":item_json.series_id
item.name = typeof item_json.file_name == undefined ? "" : item_json.file_name;
item.type = typeof item_json.obj_category == undefined ? "" : item_json.obj_category;
item.formatType = typeof item_json.format_type == undefined? "" : item_json.format_type;
item.size = typeof item_json.size == undefined ? "" : item_json.size;
item.parent = typeof item_json.pdir_fid == undefined ? "" : item_json.pdir_fid;
item.lastUpdateAt = typeof item_json.last_update_at == undefined ? "" : item_json.last_update_at
item.shareIndex = shareIndex
return item;
}
getFileExtension(){
return this.name.split(".").slice(-1)[0]
}
getFileId() {
return _.isEmpty(this.fileId) ? "" : this.fileId
}
getName() {
return _.isEmpty(this.name) ? "" : this.name;
}
getParent() {
return _.isEmpty(this.parent) ? "" : "[" + this.parent + "]";
}
getSize() {
return this.size === 0 ? "" : "[" + Utils.getSize(this.size) + "]";
}
getShareIndex(){
return this.shareIndex
}
getDisplayName(type_name) {
let name = this.getName();
if (type_name === "电视剧") {
let replaceNameList = ["4k", "4K"]
name = name.replaceAll("." + this.getFileExtension(), "")
name = name.replaceAll(" ", "").replaceAll(" ", "")
for (const replaceName of replaceNameList) {
name = name.replaceAll(replaceName, "")
}
name = Utils.getStrByRegexDefault(/\.S01E(.*?)\./, name)
const numbers = name.match(/\d+/g);
if (!_.isEmpty(numbers) && numbers.length > 0) {
name = numbers[0]
}
}
return name + " " + this.getSize();
}
getEpisodeUrl(type_name){
return this.getDisplayName(type_name) + "$" + this.getFileId() + "++" + this.shareFileToken + "++" + this.shareId + "++" + this.shareToken
}
}
export {Item}

170
JN/CATJS/lib/shift-jis.js Normal file
View File

@ -0,0 +1,170 @@
import { inRange, decoderError, encoderError, floor, isASCIICodePoint, isASCIIByte,
end_of_stream, finished } from './text_decoder_utils.js'
import index, { indexCodePointFor, indexShiftJISPointerFor } from './text_decoder_indexes.js'
// 13.3 Shift_JIS
// 13.3.1 Shift_JIS decoder
/**
* @constructor
* @implements {Decoder}
* @param {{fatal: boolean}} options
*/
export class ShiftJISDecoder {
constructor(options) {
const { fatal } = options
this.fatal = fatal
// Shift_JIS's decoder has an associated Shift_JIS lead (initially
// 0x00).
this.Shift_JIS_lead = 0x00
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream and Shift_JIS lead is not 0x00,
// set Shift_JIS lead to 0x00 and return error.
if (bite === end_of_stream && this.Shift_JIS_lead !== 0x00) {
this.Shift_JIS_lead = 0x00
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and Shift_JIS lead is 0x00,
// return finished.
if (bite === end_of_stream && this.Shift_JIS_lead === 0x00)
return finished
// 3. If Shift_JIS lead is not 0x00, let lead be Shift_JIS lead,
// let pointer be null, set Shift_JIS lead to 0x00, and then run
// these substeps:
if (this.Shift_JIS_lead !== 0x00) {
var lead = this.Shift_JIS_lead
var pointer = null
this.Shift_JIS_lead = 0x00
// 1. Let offset be 0x40, if byte is less than 0x7F, and 0x41
// otherwise.
var offset = (bite < 0x7F) ? 0x40 : 0x41
// 2. Let lead offset be 0x81, if lead is less than 0xA0, and
// 0xC1 otherwise.
var lead_offset = (lead < 0xA0) ? 0x81 : 0xC1
// 3. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
// to 0xFC, inclusive, set pointer to (lead lead offset) ×
// 188 + byte offset.
if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFC))
pointer = (lead - lead_offset) * 188 + bite - offset
// 4. If pointer is in the range 8836 to 10715, inclusive,
// return a code point whose value is 0xE000 8836 + pointer.
if (inRange(pointer, 8836, 10715))
return 0xE000 - 8836 + pointer
// 5. Let code point be null, if pointer is null, and the
// index code point for pointer in index jis0208 otherwise.
var code_point = (pointer === null) ? null :
indexCodePointFor(pointer, index('jis0208'))
// 6. If code point is null and byte is an ASCII byte, prepend
// byte to stream.
if (code_point === null && isASCIIByte(bite))
stream.prepend(bite)
// 7. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 8. Return a code point whose value is code point.
return code_point
}
// 4. If byte is an ASCII byte or 0x80, return a code point
// whose value is byte.
if (isASCIIByte(bite) || bite === 0x80)
return bite
// 5. If byte is in the range 0xA1 to 0xDF, inclusive, return a
// code point whose value is 0xFF61 0xA1 + byte.
if (inRange(bite, 0xA1, 0xDF))
return 0xFF61 - 0xA1 + bite
// 6. If byte is in the range 0x81 to 0x9F, inclusive, or 0xE0
// to 0xFC, inclusive, set Shift_JIS lead to byte and return
// continue.
if (inRange(bite, 0x81, 0x9F) || inRange(bite, 0xE0, 0xFC)) {
this.Shift_JIS_lead = bite
return null
}
// 7. Return error.
return decoderError(this.fatal)
}
}
// 13.3.2 Shift_JIS encoder
/**
* @constructor
* @implements {Encoder}
* @param {{fatal: boolean}} options
*/
export class ShiftJISEncoder {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point or U+0080, return a
// byte whose value is code point.
if (isASCIICodePoint(code_point) || code_point === 0x0080)
return code_point
// 3. If code point is U+00A5, return byte 0x5C.
if (code_point === 0x00A5)
return 0x5C
// 4. If code point is U+203E, return byte 0x7E.
if (code_point === 0x203E)
return 0x7E
// 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
// return a byte whose value is code point 0xFF61 + 0xA1.
if (inRange(code_point, 0xFF61, 0xFF9F))
return code_point - 0xFF61 + 0xA1
// 6. If code point is U+2212, set it to U+FF0D.
if (code_point === 0x2212)
code_point = 0xFF0D
// 7. Let pointer be the index Shift_JIS pointer for code point.
var pointer = indexShiftJISPointerFor(code_point)
// 8. If pointer is null, return error with code point.
if (pointer === null)
return encoderError(code_point)
// 9. Let lead be floor(pointer / 188).
var lead = floor(pointer / 188)
// 10. Let lead offset be 0x81, if lead is less than 0x1F, and
// 0xC1 otherwise.
var lead_offset = (lead < 0x1F) ? 0x81 : 0xC1
// 11. Let trail be pointer % 188.
var trail = pointer % 188
// 12. Let offset be 0x40, if trail is less than 0x3F, and 0x41
// otherwise.
var offset = (trail < 0x3F) ? 0x40 : 0x41
// 13. Return two bytes whose values are lead + lead offset and
// trail + offset.
return [lead + lead_offset, trail + offset]
}
}

View File

@ -0,0 +1,53 @@
function compareTwoStrings(first, second) {
if ((first = first.replace(/\s+/g, "")) === (second = second.replace(/\s+/g, ""))) return 1;
if (first.length < 2 || second.length < 2) return 0;
var firstBigrams = new Map;
for (let i = 0; i < first.length - 1; i++) {
var bigram = first.substring(i, i + 2), count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) + 1 : 1;
firstBigrams.set(bigram, count)
}
let intersectionSize = 0;
for (let i = 0; i < second.length - 1; i++) {
const bigram = second.substring(i, i + 2), count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) : 0;
0 < count && (firstBigrams.set(bigram, count - 1), intersectionSize++)
}
return 2 * intersectionSize / (first.length + second.length - 2)
}
function findBestMatch(mainString, targetStrings) {
var ratings = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetStrings.length; i++) {
var currentTargetString = targetStrings[i], currentRating = compareTwoStrings(mainString, currentTargetString);
ratings.push({
target: currentTargetString,
rating: currentRating
}), currentRating > ratings[bestMatchIndex].rating && (bestMatchIndex = i)
}
return {ratings: ratings, bestMatch: ratings[bestMatchIndex], bestMatchIndex: bestMatchIndex}
}
function lcs(str1, str2) {
if (!str1 || !str2) return {length: 0, sequence: "", offset: 0};
for (var sequence = "", str1Length = str1.length, str2Length = str2.length, num = new Array(str1Length), maxlen = 0, lastSubsBegin = 0, i = 0; i < str1Length; i++) {
for (var subArray = new Array(str2Length), j = 0; j < str2Length; j++) subArray[j] = 0;
num[i] = subArray
}
for (var thisSubsBegin = null, i = 0; i < str1Length; i++) for (j = 0; j < str2Length; j++) str1[i] !== str2[j] ? num[i][j] = 0 : (num[i][j] = 0 === i || 0 === j ? 1 : 1 + num[i - 1][j - 1], num[i][j] > maxlen && (maxlen = num[i][j], lastSubsBegin === (thisSubsBegin = i - num[i][j] + 1) ? sequence += str1[i] : (lastSubsBegin = thisSubsBegin, sequence = "", sequence += str1.substr(lastSubsBegin, i + 1 - lastSubsBegin))));
return {length: maxlen, sequence: sequence, offset: thisSubsBegin}
}
function findBestLCS(mainString, targetStrings) {
var results = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetStrings.length; i++) {
var currentTargetString = targetStrings[i], currentLCS = lcs(mainString, currentTargetString);
results.push({
target: currentTargetString,
lcs: currentLCS
}), currentLCS.length > results[bestMatchIndex].lcs.length && (bestMatchIndex = i)
}
return {allLCS: results, bestMatch: results[bestMatchIndex], bestMatchIndex: bestMatchIndex}
}
export {compareTwoStrings, findBestMatch, findBestLCS};

View File

@ -0,0 +1,86 @@
import { end_of_stream, finished, isASCIIByte, decoderError, encoderError, isASCIICodePoint } from './text_decoder_utils.js'
import { indexPointerFor } from './text_decoder_indexes.js'
//
// 10. Legacy single-byte encodings
//
// 10.1 single-byte decoder
/**
* @implements {Decoder}
*/
export class SingleByteDecoder {
/**
* @param {!Array.<number>} index The encoding index.
* @param {{fatal: boolean}} options
*/
constructor(index, options) {
const { fatal } = options
this.fatal = fatal
this.index = index
}
/**
* @param {Stream} stream The stream of bytes being decoded.
* @param {number} bite The next byte read from the stream.
*/
handler(stream, bite) {
// 1. If byte is end-of-stream, return finished.
if (bite === end_of_stream)
return finished
// 2. If byte is an ASCII byte, return a code point whose value
// is byte.
if (isASCIIByte(bite))
return bite
// 3. Let code point be the index code point for byte 0x80 in
// index single-byte.
var code_point = this.index[bite - 0x80]
// 4. If code point is null, return error.
if (code_point === null)
return decoderError(this.fatal)
// 5. Return a code point whose value is code point.
return code_point
}
}
// 10.2 single-byte encoder
/**
* @implements {Encoder}
*/
export class SingleByteEncoder {
/**
* @param {!Array.<?number>} index The encoding index.
*/
constructor(index) {
this.index = index
}
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return {(number|!Array.<number>)} Byte(s) to emit.
*/
handler(stream, code_point) {
// 1. If code point is end-of-stream, return finished.
if (code_point === end_of_stream)
return finished
// 2. If code point is an ASCII code point, return a byte whose
// value is code point.
if (isASCIICodePoint(code_point))
return code_point
// 3. Let pointer be the index pointer for code point in index
// single-byte.
const pointer = indexPointerFor(code_point, this.index)
// 4. If pointer is null, return error with code point.
if (pointer === null)
encoderError(code_point)
// 5. Return a byte whose value is pointer + 0x80.
return pointer + 0x80
}
}

119
JN/CATJS/lib/table.js Normal file
View File

@ -0,0 +1,119 @@
import Encodings from './encodings.js'
import { UTF8Decoder, UTF8Encoder } from './utf8.js'
import { UTF16Decoder, UTF16Encoder } from './utf16.js'
import { GB18030Decoder, GB18030Encoder } from './gb18030.js'
import { Big5Decoder, Big5Encoder } from './big5.js'
import { EUCJPDecoder, EUCJPEncoder } from './euc-jp.js'
import { EUCKRDecoder, EUCKREncoder } from './euc-kr.js'
import { ISO2022JPDecoder, ISO2022JPEncoder } from './iso-2022-jp.js'
import { XUserDefinedDecoder, XUserDefinedEncoder } from './x-user-defined.js'
import { ShiftJISDecoder, ShiftJISEncoder } from './shift-jis.js'
import { SingleByteDecoder, SingleByteEncoder } from './single-byte.js'
import index from './text_decoder_indexes.js';
// 5.2 Names and labels
// TODO: Define @typedef for Encoding: {name:string,labels:Array.<string>}
// https://github.com/google/closure-compiler/issues/247
// Label to encoding registry.
/** @type {Object.<string,{name:string,labels:Array.<string>}>} */
export const label_to_encoding = {}
Encodings.forEach(({ encodings }) => {
encodings.forEach((encoding) => {
encoding.labels.forEach((label) => {
label_to_encoding[label] = encoding
})
})
})
// Registry of of encoder/decoder factories, by encoding name.
export const encoders = {
'UTF-8'() { // 9.1 utf-8
return new UTF8Encoder()
},
'GBK'(options) { // 11.1.2 gbk encoder;
// gbk's encoder is gb18030's encoder with its gbk flag set.
return new GB18030Encoder(options, true)
},
'gb18030'() {
return new GB18030Encoder()
},
'Big5'() {
return new Big5Encoder()
},
'EUC-JP'() {
return new EUCJPEncoder()
},
'EUC-KR'() {
return new EUCKREncoder()
},
'ISO-2022-JP'() {
return new ISO2022JPEncoder()
},
'UTF-16BE'() { // 15.3 utf-16be
return new UTF16Encoder(true)
},
'UTF-16LE'() { // 15.4 utf-16le
return new UTF16Encoder()
},
'x-user-defined'() {
return new XUserDefinedEncoder()
},
'Shift_JIS'() {
return new ShiftJISEncoder()
},
}
/** @type {Object.<string, function({fatal:boolean}): Decoder>} */
export const decoders = {
'UTF-8'(options) { // 9.1.1 utf-8 decoder
return new UTF8Decoder(options)
},
'GBK'(options) { // 11.1.1 gbk decoder; gbk's decoder is gb18030's decoder.
return new GB18030Decoder(options)
},
'gb18030'(options) {
return new GB18030Decoder(options)
},
'Big5'(options) {
return new Big5Decoder(options)
},
'EUC-JP'(options) {
return new EUCJPDecoder(options)
},
'EUC-KR'(options) {
return new EUCKRDecoder(options)
},
'ISO-2022-JP'(options) {
return new ISO2022JPDecoder(options)
},
'UTF-16BE'(options) { // 15.3.1 utf-16be decoder
return new UTF16Decoder(true, options)
},
'UTF-16LE'(options) { // 15.4.1 utf-16le decoder
return new UTF16Decoder(false, options)
},
'x-user-defined'() {
return new XUserDefinedDecoder()
},
'Shift_JIS'(options) {
return new ShiftJISDecoder(options)
},
}
Encodings.forEach(({ heading, encodings }) => {
if (heading != 'Legacy single-byte encodings')
return
encodings.forEach((encoding) => {
const name = encoding.name
const idx = index(name.toLowerCase())
decoders[name] = (options) => {
return new SingleByteDecoder(idx, options)
}
encoders[name] = (options) => {
return new SingleByteEncoder(idx, options)
}
})
})

View File

@ -0,0 +1,84 @@
/*
* @File : tencentDanmu.js
* @Author : jade
* @Date : 2024/3/13 13:17
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {DammuSpider} from "./danmuSpider.js";
import {VodDetail} from "./vod.js";
import * as Utils from "./utils.js";
class TencentDammuSpider extends DammuSpider {
constructor() {
super()
this.siteUrl = "https://v.qq.com"
this.reconnectTimes = 0
this.maxReconnectTimes = 5
}
getAppName() {
return "腾讯视频"
}
async parseVodShortListFromDoc($) {
let vodElements = $("[class=\"_infos\"]")
let vod_list = []
for (const vodElement of vodElements) {
let vodDetail = new VodDetail()
let titleElement = $(vodElement).find("[class=\"result_title\"]")
let infoItemEvenElenet = $(vodElement).find("[class=\"info_item info_item_even\"]")
let infoItemOddElement = $(vodElement).find("[class=\"info_item info_item_odd\"]")
let descElement = $(vodElement).find("[class=\"info_item info_item_desc\"]")
vodDetail.vod_name = $($(titleElement).find("[class=\"hl\"]")).text()
vodDetail.vod_year = $($(titleElement).find("[class=\"sub\"]")).text().replaceAll("\n","").replaceAll("(","").replaceAll(")","").replaceAll("\t","").split("/").slice(-1)[0]
vodDetail.type_name = $($(titleElement).find("[class=\"type\"]")).text()
vodDetail.vod_director = $($($(infoItemEvenElenet).find("[class=\"content\"]")).find("span")).text()
let actorList = $( $(infoItemOddElement.slice(-1)[0]).find("[class=\"content\"]")).find("a")
let vodActorList = []
for (const actorElement of actorList){
vodActorList.push($(actorElement).text())
}
vodDetail.vod_actor = vodActorList.join(" * ")
vodDetail.vod_content = $($(descElement).find("[class=\"desc_text\"]")[0]).text()
let url = $(vodElement).find("a")[0].attribs.href
if (url.indexOf("cover") > -1){
let detail$ = await this.getHtml(url)
let video_ids = JSON.parse(Utils.getStrByRegex(/"video_ids":(.*?),/,detail$.html()))
vodDetail.vod_id = video_ids[0]
vod_list.push(vodDetail)
}
}
return vod_list
}
async search(wd) {
await this.jadeLog.debug(`正在搜索:${wd}`, true)
let searchUrl = this.siteUrl + `/x/search/?q=${wd}`
let $ = await this.getHtml(searchUrl)
return this.parseVodShortListFromDoc($)
}
parseDammu(id){
}
async getDammu(voddetail, episodeId) {
let vod_list = await this.search(voddetail.vod_name)
for (const searchVodDetail of vod_list){
if (voddetail.vod_director === searchVodDetail.vod_director){
await this.jadeLog.debug("搜索匹配成功",true)
return
}
}
await this.jadeLog.warning(`搜索匹配失败,原:${JSON.stringify(voddetail)},搜索:${JSON.stringify(vod_list)}`)
return ""
}
}
export {TencentDammuSpider}

View File

@ -0,0 +1,118 @@
import { end_of_stream } from './text_decoder_utils.js'
import { label_to_encoding } from './table.js'
export default class Stream {
/**
* A stream represents an ordered sequence of tokens.
* @param {!(Array.<number>|Uint8Array)} tokens Array of tokens that provide
* the stream.
*/
constructor(tokens) {
this.tokens = [...tokens]
// Reversed as push/pop is more efficient than shift/unshift.
this.tokens.reverse()
}
/**
* @returns True if end-of-stream has been hit.
*/
endOfStream() {
return !this.tokens.length
}
/**
* When a token is read from a stream, the first token in the
* stream must be returned and subsequently removed, and
* end-of-stream must be returned otherwise.
*
* @return Get the next token from the stream, or end_of_stream.
*/
read() {
if (!this.tokens.length)
return end_of_stream
return this.tokens.pop()
}
/**
* When one or more tokens are prepended to a stream, those tokens
* must be inserted, in given order, before the first token in the
* stream.
*
* @param {(number|!Array.<number>)} token The token(s) to prepend to the
* stream.
*/
prepend(token) {
if (Array.isArray(token)) {
var tokens = /**@type {!Array.<number>}*/(token)
while (tokens.length)
this.tokens.push(tokens.pop())
} else {
this.tokens.push(token)
}
}
/**
* When one or more tokens are pushed to a stream, those tokens
* must be inserted, in given order, after the last token in the
* stream.
*
* @param {(number|!Array.<number>)} token The tokens(s) to push to the
* stream.
*/
push(token) {
if (Array.isArray(token)) {
const tokens = /**@type {!Array.<number>}*/(token)
while (tokens.length)
this.tokens.unshift(tokens.shift())
} else {
this.tokens.unshift(token)
}
}
}
export const DEFAULT_ENCODING = 'utf-8'
/**
* Returns the encoding for the label.
* @param {string} label The encoding label.
*/
export function getEncoding(label) {
// 1. Remove any leading and trailing ASCII whitespace from label.
label = String(label).trim().toLowerCase()
// 2. If label is an ASCII case-insensitive match for any of the
// labels listed in the table below, return the corresponding
// encoding, and failure otherwise.
if (Object.prototype.hasOwnProperty.call(label_to_encoding, label)) {
return label_to_encoding[label]
}
return null
}
//
// 5. Encodings
//
// 5.1 Encoders and decoders
// /** @interface */
// function Decoder() {}
// Decoder.prototype = {
// /**
// * @param {Stream} stream The stream of bytes being decoded.
// * @param {number} bite The next byte read from the stream.
// * @return {?(number|!Array.<number>)} The next code point(s)
// * decoded, or null if not enough data exists in the input
// * stream to decode a complete code point, or |finished|.
// */
// handler: function(stream, bite) {},
// }
// /** @interface */
// function Encoder() {}
// Encoder.prototype = {
// /**
// * @param {Stream} stream The stream of code points being encoded.
// * @param {number} code_point Next code point read from the stream.
// * @return {(number|!Array.<number>)} Byte(s) to emit, or |finished|.
// */
// handler: function(stream, code_point) {},
// }

Some files were not shown because too many files have changed in this diff Show More