rollup 编译文件

This commit is contained in:
lushunming 2024-08-19 14:06:21 +08:00
parent cce23dc2d7
commit a178c1bc62
102 changed files with 26 additions and 73035 deletions

View File

@ -1,238 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,183 +0,0 @@
/*
* @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}

View File

@ -1,258 +0,0 @@
/*
* @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

@ -1,85 +0,0 @@
/*
* @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,
};
}

File diff suppressed because one or more lines are too long

View File

@ -1,152 +0,0 @@
/*
* @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}

View File

@ -1,268 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

View File

@ -1,191 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,233 +0,0 @@
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

@ -1,215 +0,0 @@
/*
* @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}

View File

@ -1,246 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,214 +0,0 @@
/*
* @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}

View File

@ -1,96 +0,0 @@
/*
* @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}

View File

@ -1,96 +0,0 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc : 非凡资源18+(已失效)
*/
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}

View File

@ -1,333 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,625 +0,0 @@
/*
* @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}

View File

@ -1,273 +0,0 @@
/*
* @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}

View File

@ -1,153 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

View File

@ -1,319 +0,0 @@
/*
* @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}

View File

@ -1,317 +0,0 @@
/*
* @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}

View File

@ -1,295 +0,0 @@
/*
* @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}

View File

@ -1,174 +0,0 @@
/*
* @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.x9s8x.icu" // https://www.cs1369.com
}
getName() {
return "🔞┃九九六影视┃🔞"
}
getAppName() {
return "九九六影视"
}
getJSName() {
return "jiujiuliu"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $('[class="content-item"]')
for (const vodElement of vodElements) {
let vodShort = new VodShort()
let videoElement = $(vodElement).find("a")[0]
vodShort.vod_id = videoElement.attribs["href"]
vodShort.vod_name = videoElement.attribs["title"]
vodShort.vod_pic = $(videoElement).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(vodElement).find('[class="note text-bg-r"]')).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let detailElement = $('[class="row film_info clearfix"]')
vodDetail.vod_pic = $(detailElement).find("img")[0].attribs["data-original"]
vodDetail.vod_name = $($(detailElement).find('[class="c_pink text-ellipsis"]')).text()
let content = $( $(detailElement).find('[class="row"]')).text()
vodDetail.type_name = Utils.getStrByRegex(/视频类型(.*?)\n/,content).replaceAll("","")
vodDetail.vod_area = Utils.getStrByRegex(/更新时间(.*?)\n/,content).replaceAll("","")
let playVod = {}
let playElement = $('[class="btn btn-m btn-default"]')[0]
let vodItems = []
const epName = vodDetail.vod_name;
const playUrl = playElement.attribs.href
vodItems.push(epName + '$' + playUrl)
playVod[playElement.attribs.title] = vodItems.join('#')
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl,true);
let menuElements = $('[class="row-item-title bg_red"]').find("a")
for (const menuElement of menuElements) {
let type_name = $(menuElement).text()
let type_id = menuElement.attribs["href"]
if (type_name.indexOf("小说") === -1){
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($,index) {
let html = $.html()
let extend_list = []
let extendElement = $($($($('[class="row-item-content"]')[index])).find('[class="item"]')).find("a")
let extend_dic = {"name":"排序","key":"sort","value":[]}
for (const element of extendElement){
let type_name = $(element).text()
let type_id = element.attribs["href"]
extend_dic["value"].push(this.getFliterDic(type_name,type_id))
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
let index = 0
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if ( type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl,true)
this.filterObj[type_id] = await this.getFilter($,index)
index = index + 1
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl,true)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + tid.replaceAll(".html",`/page/${pg}.html`),true)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id,true)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl+id,true)
let playerConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/,$.html()))
this.playUrl = playerConfig["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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,93 +0,0 @@
/*
* @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}

View File

@ -1,93 +0,0 @@
/*
* @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}

View File

@ -1,260 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

View File

@ -1,133 +0,0 @@
/*
* @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}

View File

@ -1,181 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,242 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

View File

@ -1,459 +0,0 @@
/*
* @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}

View File

@ -1,115 +0,0 @@
/*
* @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}

View File

@ -1,251 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

View File

@ -1,901 +0,0 @@
/*
* @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, response,proxy)
}
}
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}

File diff suppressed because one or more lines are too long

View File

@ -1,128 +0,0 @@
import {__jsEvalReturn} from './wogg.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 = 'wogg';
let siteType = 3;
await spider.init({
skey: siteKey, stype: siteType, ext: {
"aliToken": "a0debd28d10e4aa5a431e7de586e6e42",
"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":"__puus=4315f3066f599ce7233f88d8c313a030AAQ/jijbnct663MvWewmjAye1IUH1d9WVf3hcrcIIOEZvWcl4jsz4IUe4nBqByH9+Oc6JSgdx08r93auaJcX5OHH3X8MozlbCX3f7EQ0/UmJwlZiQsz4UKCA++VixQLNd71zoRJ+VvHmYFkJxfnnveJ3nWSWt3HVbUJbAjsWhKR0UrI72TA33ocAbXvyF0XXFVe8lJI4j4DMK6HixNIf1CX2; CwsSessionId=4ebf55ce-02e3-469c-b7fc-59eb327be82c; kkpcwpea=a=a&uc_param_str=einibicppfmivefrlantcunwsssvjbktchnnsnddds&instance=kkpcwp&pf=145&self_service=true&wxUid=AAR33S5CGi7X5FDtOxbk2juf&plain_utdid=Zk29NiM5i2QDAKrmAFKxjrco&system_ver=Darwin_13.6.6&channel_no=pckk%40clouddrive_share_ch&ve=3.2.7&sv=release; _UP_D_=pc; __kp=872521a0-1743-11ef-8758-49b470509a34; __kps=AAR33S5CGi7X5FDtOxbk2juf; __ktd=v/InsJyWIBLv++dfPEXCtA==; __pus=46820c01a28fc1296d407f0bf5cff035AASGf9nOKeDv5D/U50Qsjq6L5IUllrXEQOlPdpQ2S6JymmRlRK1fmlpdAQRkZ4zTHX3i0LGLYxuSwxai4pJtx/pU; __uid=AAR33S5CGi7X5FDtOxbk2juf; _UP_A4A_11_=wb964143699847c8862df3296d502423"
}
});
let classes = JSON.parse(await spider.home(true));
console.debug(JSON.stringify(classes))
// 测试详情
let detail1 = JSON.parse(await spider.detail("/index.php/voddetail/84022.html"))
await testPlay(detail1)
//测试首页列表
let homeVod = JSON.parse(await spider.homeVod())
console.debug(JSON.stringify(homeVod));
// 测试搜索
let search_page = JSON.parse(await spider.search("庆余年", false, 1))
console.debug(JSON.stringify(search_page))
// 测试详情
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};

File diff suppressed because one or more lines are too long

View File

@ -1,343 +0,0 @@
/*
* @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}

View File

@ -1,192 +0,0 @@
/*
* @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}

View File

@ -1,322 +0,0 @@
/*
* @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}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,268 +0,0 @@
/*
* @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}

View File

@ -1,190 +0,0 @@
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}

View File

@ -1,107 +0,0 @@
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}

View File

@ -1,86 +0,0 @@
/*
* @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,
};

View File

@ -1,677 +0,0 @@
/*
* @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("user not allowed access drive") > -1){
return {code: 404, 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}
}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 || response.code === 404)) {
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 === 404) {
await JadeLog.error("阿里授权失败,失败原因为:用户没有权限" + response.content)
return await oauthFunc(url, params, true)
}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
};

View File

@ -1,516 +0,0 @@
/*
* @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
};

View File

@ -1,154 +0,0 @@
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

@ -1,31 +0,0 @@
/*
* @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}

View File

@ -1,76 +0,0 @@
/*
* @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
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,107 +0,0 @@
/**
* 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,getQuarkPlayFormatList,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)
let quarkPlayFormatList = getQuarkPlayFormatList();
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}

View File

@ -1,188 +0,0 @@
/*
* @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

View File

@ -1,460 +0,0 @@
/**
* 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

View File

@ -1,166 +0,0 @@
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]
}
}

View File

@ -1,124 +0,0 @@
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]
}
}

View File

@ -1,480 +0,0 @@
/*
* @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}

View File

@ -1,251 +0,0 @@
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
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,940 +0,0 @@
/*
* @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};

View File

@ -1,441 +0,0 @@
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]
}
}

View File

@ -1,86 +0,0 @@
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}

View File

@ -1,129 +0,0 @@
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

@ -1,255 +0,0 @@
/*
* @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

@ -1,146 +0,0 @@
/*
* @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

View File

@ -1,66 +0,0 @@
/**
* 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 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);
}
}
function getQuarkPlayFormatList(){
return quark.getPlayFormatList()
}
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{
playUrl = await quark.getLiveTranscoding(shareId, stoken, fileId, fileToken,flag)
}
return playUrl
}
function getQuarkHeaders(){
let headers = quark.getHeaders()
delete headers["Host"]
return headers
}
export {initQuark,detailContentQuark,playContentQuark,getQuarkPlayFormatList,quarkName,getQuarkHeaders}

View File

@ -1,313 +0,0 @@
/**
* 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';
this.isVip = false;
}
async initQuark(cookie) {
this.ckey = Crypto.enc.Hex.stringify(Crypto.MD5(cookie)).toString();
this.cookie = cookie
this.isVip = await this.getVip()
}
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]}`);
}
}
}
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 getVip(){
const listData = await this.api(`member?pr=ucpro&fr=pc&uc_param_str=&fetch_subscribe=true&_ch=home&fetch_identity=true`, null,null, 'get');
if (listData.data.member_type==="EXP_SVIP"){
return true
}else{
return false
}
}
getPlayFormatList(){
if(this.isVip){
return ["4K","超清","高清","普画"]
}else{
return ["普画"]
}
}
getPlayFormtQuarkList(){
if(this.isVip){
return ["4k","2k","super","high","normal","low"]
}{
return ["low"]
}
}
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,flag) {
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) {
let flag_id = flag.split("-").slice(-1)[0]
let index = Utils.findAllIndexes(this.getPlayFormatList(),flag_id);
let quarkFormat = this.getPlayFormtQuarkList()[index]
for (const video of transcoding.data.video_list){
if (video.resolution === quarkFormat){
return video.video_info.url
}
}
return transcoding.data.video_list[index].video_info.url
}
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

@ -1,98 +0,0 @@
/**
* 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}

View File

@ -1,170 +0,0 @@
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

@ -1,53 +0,0 @@
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

@ -1,86 +0,0 @@
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
}
}

View File

@ -1,119 +0,0 @@
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

@ -1,84 +0,0 @@
/*
* @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

@ -1,118 +0,0 @@
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) {},
// }

View File

@ -1,153 +0,0 @@
import { inRange } from './text_decoder_utils.js'
import {Indexes} from './encoding-indexes.js'
//
// 6. Indexes
//
/**
* @param {number} pointer The |pointer| to search for.
* @param {(!Array.<?number>|undefined)} index The |index| to search within.
* @return {?number} The code point corresponding to |pointer| in |index|,
* or null if |code point| is not in |index|.
*/
export function indexCodePointFor(pointer, i) {
if (!i) return null
return i[pointer] || null
}
/**
* @param {number} code_point The |code point| to search for.
* @param {!Array.<?number>} i The |index| to search within.
* @return {?number} The first pointer corresponding to |code point| in
* |index|, or null if |code point| is not in |index|.
*/
export function indexPointerFor(code_point, i) {
var pointer = i.indexOf(code_point)
return pointer === -1 ? null : pointer
}
/**
* @param {string} name Name of the index.
*/
export default function index(name) {
return Indexes[name]
}
/**
* @param {number} pointer The |pointer| to search for in the gb18030 index.
* @return The code point corresponding to |pointer| in |index|,
* or null if |code point| is not in the gb18030 index.
*/
export function indexGB18030RangesCodePointFor(pointer) {
// 1. If pointer is greater than 39419 and less than 189000, or
// pointer is greater than 1237575, return null.
if ((pointer > 39419 && pointer < 189000) || (pointer > 1237575))
return null
// 2. If pointer is 7457, return code point U+E7C7.
if (pointer === 7457) return 0xE7C7
// 3. Let offset be the last pointer in index gb18030 ranges that
// is equal to or less than pointer and let code point offset be
// its corresponding code point.
var offset = 0
var code_point_offset = 0
var idx = index('gb18030-ranges')
var i
for (i = 0; i < idx.length; ++i) {
/** @type {!Array.<number>} */
var entry = idx[i]
if (entry[0] <= pointer) {
offset = entry[0]
code_point_offset = entry[1]
} else {
break
}
}
// 4. Return a code point whose value is code point offset +
// pointer offset.
return code_point_offset + pointer - offset
}
/**
* @param {number} code_point The |code point| to locate in the gb18030 index.
* @return {number} The first pointer corresponding to |code point| in the
* gb18030 index.
*/
export function indexGB18030RangesPointerFor(code_point) {
// 1. If code point is U+E7C7, return pointer 7457.
if (code_point === 0xE7C7) return 7457
// 2. Let offset be the last code point in index gb18030 ranges
// that is equal to or less than code point and let pointer offset
// be its corresponding pointer.
var offset = 0
var pointer_offset = 0
var idx = index('gb18030-ranges')
var i
for (i = 0; i < idx.length; ++i) {
/** @type {!Array.<number>} */
var entry = idx[i]
if (entry[1] <= code_point) {
offset = entry[1]
pointer_offset = entry[0]
} else {
break
}
}
// 3. Return a pointer whose value is pointer offset + code point
// offset.
return pointer_offset + code_point - offset
}
/**
* @param {number} code_point The |code_point| to search for in the Shift_JIS
* index.
* @return {?number} The code point corresponding to |pointer| in |index|,
* or null if |code point| is not in the Shift_JIS index.
*/
export function indexShiftJISPointerFor(code_point) {
// 1. Let index be index jis0208 excluding all entries whose
// pointer is in the range 8272 to 8835, inclusive.
shift_jis_index = shift_jis_index ||
index('jis0208').map((cp, pointer) => {
return inRange(pointer, 8272, 8835) ? null : cp
})
const index_ = shift_jis_index
// 2. Return the index pointer for code point in index.
return index_.indexOf(code_point)
}
var shift_jis_index
/**
* @param {number} code_point The |code_point| to search for in the big5
* index.
* @return {?number} The code point corresponding to |pointer| in |index|,
* or null if |code point| is not in the big5 index.
*/
export function indexBig5PointerFor(code_point) {
// 1. Let index be index Big5 excluding all entries whose pointer
big5_index_no_hkscs = big5_index_no_hkscs ||
index('big5').map((cp, pointer) => {
return (pointer < (0xA1 - 0x81) * 157) ? null : cp
})
var index_ = big5_index_no_hkscs
// 2. If code point is U+2550, U+255E, U+2561, U+256A, U+5341, or
// U+5345, return the last pointer corresponding to code point in
// index.
if (code_point === 0x2550 || code_point === 0x255E ||
code_point === 0x2561 || code_point === 0x256A ||
code_point === 0x5341 || code_point === 0x5345) {
return index_.lastIndexOf(code_point)
}
// 3. Return the index pointer for code point in index.
return indexPointerFor(code_point, index_)
}
var big5_index_no_hkscs

View File

@ -1,180 +0,0 @@
//
// Utilities
//
/**
* @param {number} a The number to test.
* @param {number} min The minimum value in the range, inclusive.
* @param {number} max The maximum value in the range, inclusive.
* @return {boolean} True if a >= min and a <= max.
*/
export function inRange(a, min, max) {
return min <= a && a <= max
}
export const floor = Math.floor
/**
* @param {string} string Input string of UTF-16 code units.
* @return {!Array.<number>} Code points.
*/
export function stringToCodePoints(string) {
// https://heycam.github.io/webidl/#dfn-obtain-unicode
// 1. Let S be the DOMString value.
var s = String(string)
// 2. Let n be the length of S.
var n = s.length
// 3. Initialize i to 0.
var i = 0
// 4. Initialize U to be an empty sequence of Unicode characters.
var u = []
// 5. While i < n:
while (i < n) {
// 1. Let c be the code unit in S at index i.
var c = s.charCodeAt(i)
// 2. Depending on the value of c:
// c < 0xD800 or c > 0xDFFF
if (c < 0xD800 || c > 0xDFFF) {
// Append to U the Unicode character with code point c.
u.push(c)
}
// 0xDC00 ≤ c ≤ 0xDFFF
else if (0xDC00 <= c && c <= 0xDFFF) {
// Append to U a U+FFFD REPLACEMENT CHARACTER.
u.push(0xFFFD)
}
// 0xD800 ≤ c ≤ 0xDBFF
else if (0xD800 <= c && c <= 0xDBFF) {
// 1. If i = n1, then append to U a U+FFFD REPLACEMENT
// CHARACTER.
if (i === n - 1) {
u.push(0xFFFD)
}
// 2. Otherwise, i < n1:
else {
// 1. Let d be the code unit in S at index i+1.
var d = s.charCodeAt(i + 1)
// 2. If 0xDC00 ≤ d ≤ 0xDFFF, then:
if (0xDC00 <= d && d <= 0xDFFF) {
// 1. Let a be c & 0x3FF.
var a = c & 0x3FF
// 2. Let b be d & 0x3FF.
var b = d & 0x3FF
// 3. Append to U the Unicode character with code point
// 2^16+2^10*a+b.
u.push(0x10000 + (a << 10) + b)
// 4. Set i to i+1.
i += 1
}
// 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a
// U+FFFD REPLACEMENT CHARACTER.
else {
u.push(0xFFFD)
}
}
}
// 3. Set i to i+1.
i += 1
}
// 6. Return U.
return u
}
/**
* @param {!Array.<number>} code_points Array of code points.
* @return {string} string String of UTF-16 code units.
*/
export function codePointsToString(code_points) {
var s = ''
for (var i = 0; i < code_points.length; ++i) {
var cp = code_points[i]
if (cp <= 0xFFFF) {
s += String.fromCharCode(cp)
} else {
cp -= 0x10000
s += String.fromCharCode((cp >> 10) + 0xD800,
(cp & 0x3FF) + 0xDC00)
}
}
return s
}
/**
* @param {boolean} fatal If true, decoding errors raise an exception.
* @param {number=} opt_code_point Override the standard fallback code point.
* @return The code point to insert on a decoding error.
*/
export function decoderError(fatal, opt_code_point) {
if (fatal)
throw TypeError('Decoder error')
return opt_code_point || 0xFFFD
}
/**
* @param {number} code_point The code point that could not be encoded.
* @return {number} Always throws, no value is actually returned.
*/
export function encoderError(code_point) {
throw TypeError('The code point ' + code_point + ' could not be encoded.')
}
/**
* @param {number} code_unit
* @param {boolean} utf16be
*/
export function convertCodeUnitToBytes(code_unit, utf16be) {
// 1. Let byte1 be code unit >> 8.
const byte1 = code_unit >> 8
// 2. Let byte2 be code unit & 0x00FF.
const byte2 = code_unit & 0x00FF
// 3. Then return the bytes in order:
// utf-16be flag is set: byte1, then byte2.
if (utf16be)
return [byte1, byte2]
// utf-16be flag is unset: byte2, then byte1.
return [byte2, byte1]
}
//
// 4. Terminology
//
/**
* An ASCII byte is a byte in the range 0x00 to 0x7F, inclusive.
* @param {number} a The number to test.
* @return {boolean} True if a is in the range 0x00 to 0x7F, inclusive.
*/
export function isASCIIByte(a) {
return 0x00 <= a && a <= 0x7F
}
/**
* An ASCII code point is a code point in the range U+0000 to
* U+007F, inclusive.
*/
export const isASCIICodePoint = isASCIIByte
/**
* End-of-stream is a special token that signifies no more tokens are in the stream.
*/
export const end_of_stream = -1
export const finished = -1

View File

@ -1,139 +0,0 @@
import { inRange, decoderError, end_of_stream, finished, convertCodeUnitToBytes } from './text_decoder_utils.js'
// 15.2.1 shared utf-16 decoder
/**
* @implements {Decoder}
*/
export class UTF16Decoder {
/**
* @param {boolean} utf16_be True if big-endian, false if little-endian.
* @param {{fatal: boolean}} options
*/
constructor(utf16_be, options) {
const { fatal } = options
this.utf16_be = utf16_be
this.fatal = fatal
this.utf16_lead_byte = null
this.utf16_lead_surrogate = null
}
/**
* @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 either utf-16 lead byte or
// utf-16 lead surrogate is not null, set utf-16 lead byte and
// utf-16 lead surrogate to null, and return error.
if (bite === end_of_stream && (this.utf16_lead_byte !== null ||
this.utf16_lead_surrogate !== null)) {
return decoderError(this.fatal)
}
// 2. If byte is end-of-stream and utf-16 lead byte and utf-16
// lead surrogate are null, return finished.
if (bite === end_of_stream && this.utf16_lead_byte === null &&
this.utf16_lead_surrogate === null) {
return finished
}
// 3. If utf-16 lead byte is null, set utf-16 lead byte to byte
// and return continue.
if (this.utf16_lead_byte === null) {
this.utf16_lead_byte = bite
return null
}
// 4. Let code unit be the result of:
let code_unit
if (this.utf16_be) {
// utf-16be decoder flag is set
// (utf-16 lead byte << 8) + byte.
code_unit = (this.utf16_lead_byte << 8) + bite
} else {
// utf-16be decoder flag is unset
// (byte << 8) + utf-16 lead byte.
code_unit = (bite << 8) + this.utf16_lead_byte
}
// Then set utf-16 lead byte to null.
this.utf16_lead_byte = null
// 5. If utf-16 lead surrogate is not null, let lead surrogate
// be utf-16 lead surrogate, set utf-16 lead surrogate to null,
// and then run these substeps:
if (this.utf16_lead_surrogate !== null) {
const lead_surrogate = this.utf16_lead_surrogate
this.utf16_lead_surrogate = null
// 1. If code unit is in the range U+DC00 to U+DFFF,
// inclusive, return a code point whose value is 0x10000 +
// ((lead surrogate 0xD800) << 10) + (code unit 0xDC00).
if (inRange(code_unit, 0xDC00, 0xDFFF)) {
return 0x10000 + (lead_surrogate - 0xD800) * 0x400 +
(code_unit - 0xDC00)
}
// 2. Prepend the sequence resulting of converting code unit
// to bytes using utf-16be decoder flag to stream and return
// error.
stream.prepend(convertCodeUnitToBytes(code_unit, this.utf16_be))
return decoderError(this.fatal)
}
// 6. If code unit is in the range U+D800 to U+DBFF, inclusive,
// set utf-16 lead surrogate to code unit and return continue.
if (inRange(code_unit, 0xD800, 0xDBFF)) {
this.utf16_lead_surrogate = code_unit
return null
}
// 7. If code unit is in the range U+DC00 to U+DFFF, inclusive,
// return error.
if (inRange(code_unit, 0xDC00, 0xDFFF))
return decoderError(this.fatal)
// 8. Return code point code unit.
return code_unit
}
}
// 15.2.2 shared utf-16 encoder
/**
* @implements {Encoder}
*/
export class UTF16Encoder {
/**
* @param {boolean} [utf16_be] True if big-endian, false if little-endian.
*/
constructor(utf16_be = false) {
this.utf16_be = utf16_be
}
/**
* @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 in the range U+0000 to U+FFFF, inclusive,
// return the sequence resulting of converting code point to
// bytes using utf-16be encoder flag.
if (inRange(code_point, 0x0000, 0xFFFF))
return convertCodeUnitToBytes(code_point, this.utf16_be)
// 3. Let lead be ((code point 0x10000) >> 10) + 0xD800,
// converted to bytes using utf-16be encoder flag.
const lead = convertCodeUnitToBytes(
((code_point - 0x10000) >> 10) + 0xD800, this.utf16_be)
// 4. Let trail be ((code point 0x10000) & 0x3FF) + 0xDC00,
// converted to bytes using utf-16be encoder flag.
const trail = convertCodeUnitToBytes(
((code_point - 0x10000) & 0x3FF) + 0xDC00, this.utf16_be)
// 5. Return a byte sequence of lead followed by trail.
return lead.concat(trail)
}
}

View File

@ -1,208 +0,0 @@
import { inRange, decoderError, isASCIICodePoint,
end_of_stream, finished } from './text_decoder_utils.js'
/**
* @implements {Decoder}
*/
export class UTF8Decoder {
/**
* @param {{fatal: boolean}} options
*/
constructor(options) {
const { fatal } = options
// utf-8's decoder's has an associated utf-8 code point, utf-8
// bytes seen, and utf-8 bytes needed (all initially 0), a utf-8
// lower boundary (initially 0x80), and a utf-8 upper boundary
// (initially 0xBF).
let /** @type {number} */ utf8_code_point = 0,
/** @type {number} */ utf8_bytes_seen = 0,
/** @type {number} */ utf8_bytes_needed = 0,
/** @type {number} */ utf8_lower_boundary = 0x80,
/** @type {number} */ utf8_upper_boundary = 0xBF
/**
* @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.
*/
this.handler = function(stream, bite) {
// 1. If byte is end-of-stream and utf-8 bytes needed is not 0,
// set utf-8 bytes needed to 0 and return error.
if (bite === end_of_stream && utf8_bytes_needed !== 0) {
utf8_bytes_needed = 0
return decoderError(fatal)
}
// 2. If byte is end-of-stream, return finished.
if (bite === end_of_stream)
return finished
// 3. If utf-8 bytes needed is 0, based on byte:
if (utf8_bytes_needed === 0) {
// 0x00 to 0x7F
if (inRange(bite, 0x00, 0x7F)) {
// Return a code point whose value is byte.
return bite
}
// 0xC2 to 0xDF
else if (inRange(bite, 0xC2, 0xDF)) {
// 1. Set utf-8 bytes needed to 1.
utf8_bytes_needed = 1
// 2. Set UTF-8 code point to byte & 0x1F.
utf8_code_point = bite & 0x1F
}
// 0xE0 to 0xEF
else if (inRange(bite, 0xE0, 0xEF)) {
// 1. If byte is 0xE0, set utf-8 lower boundary to 0xA0.
if (bite === 0xE0)
utf8_lower_boundary = 0xA0
// 2. If byte is 0xED, set utf-8 upper boundary to 0x9F.
if (bite === 0xED)
utf8_upper_boundary = 0x9F
// 3. Set utf-8 bytes needed to 2.
utf8_bytes_needed = 2
// 4. Set UTF-8 code point to byte & 0xF.
utf8_code_point = bite & 0xF
}
// 0xF0 to 0xF4
else if (inRange(bite, 0xF0, 0xF4)) {
// 1. If byte is 0xF0, set utf-8 lower boundary to 0x90.
if (bite === 0xF0)
utf8_lower_boundary = 0x90
// 2. If byte is 0xF4, set utf-8 upper boundary to 0x8F.
if (bite === 0xF4)
utf8_upper_boundary = 0x8F
// 3. Set utf-8 bytes needed to 3.
utf8_bytes_needed = 3
// 4. Set UTF-8 code point to byte & 0x7.
utf8_code_point = bite & 0x7
}
// Otherwise
else {
// Return error.
return decoderError(fatal)
}
// Return continue.
return null
}
// 4. If byte is not in the range utf-8 lower boundary to utf-8
// upper boundary, inclusive, run these substeps:
if (!inRange(bite, utf8_lower_boundary, utf8_upper_boundary)) {
// 1. Set utf-8 code point, utf-8 bytes needed, and utf-8
// bytes seen to 0, set utf-8 lower boundary to 0x80, and set
// utf-8 upper boundary to 0xBF.
utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0
utf8_lower_boundary = 0x80
utf8_upper_boundary = 0xBF
// 2. Prepend byte to stream.
stream.prepend(bite)
// 3. Return error.
return decoderError(fatal)
}
// 5. Set utf-8 lower boundary to 0x80 and utf-8 upper boundary
// to 0xBF.
utf8_lower_boundary = 0x80
utf8_upper_boundary = 0xBF
// 6. Set UTF-8 code point to (UTF-8 code point << 6) | (byte &
// 0x3F)
utf8_code_point = (utf8_code_point << 6) | (bite & 0x3F)
// 7. Increase utf-8 bytes seen by one.
utf8_bytes_seen += 1
// 8. If utf-8 bytes seen is not equal to utf-8 bytes needed,
// continue.
if (utf8_bytes_seen !== utf8_bytes_needed)
return null
// 9. Let code point be utf-8 code point.
var code_point = utf8_code_point
// 10. Set utf-8 code point, utf-8 bytes needed, and utf-8 bytes
// seen to 0.
utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0
// 11. Return a code point whose value is code point.
return code_point
}
}
}
// 9.1.2 utf-8 encoder
/**
* @implements {Encoder}
*/
export class UTF8Encoder {
constructor() {
/**
* @param {Stream} stream Input stream.
* @param {number} code_point Next code point read from the stream.
* @return {(number|!Array.<number>)} Byte(s) to emit.
*/
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. Set count and offset based on the range code point is in:
var count, offset
// U+0080 to U+07FF, inclusive:
if (inRange(code_point, 0x0080, 0x07FF)) {
// 1 and 0xC0
count = 1
offset = 0xC0
}
// U+0800 to U+FFFF, inclusive:
else if (inRange(code_point, 0x0800, 0xFFFF)) {
// 2 and 0xE0
count = 2
offset = 0xE0
}
// U+10000 to U+10FFFF, inclusive:
else if (inRange(code_point, 0x10000, 0x10FFFF)) {
// 3 and 0xF0
count = 3
offset = 0xF0
}
// 4. Let bytes be a byte sequence whose first byte is (code
// point >> (6 × count)) + offset.
var bytes = [(code_point >> (6 * count)) + offset]
// 5. Run these substeps while count is greater than 0:
while (count > 0) {
// 1. Set temp to code point >> (6 × (count 1)).
var temp = code_point >> (6 * (count - 1))
// 2. Append to bytes 0x80 | (temp & 0x3F).
bytes.push(0x80 | (temp & 0x3F))
// 3. Decrease count by one.
count -= 1
}
// 6. Return bytes bytes, in order.
return bytes
}
}
}

View File

@ -1,385 +0,0 @@
/*
* @File : utils.js
* @Author : jade
* @Date : 2024/1/25 15:01
* @Email : jadehh@1ive.com
* @Software : Samples
* @Desc :
*/
import {Crypto} from "./cat.js";
import {TextDecoder} from "./TextDecoder.js";
import {TextEncoder} from "./TextEncoder.js";
// import {TextDecoder} from "text-decoding";
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'],
];
var charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
let CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36";
const MOBILEUA = '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';
let RESOURCEURL = "https://gh.con.sh/https://raw.githubusercontent.com/jadehh/TV/js"
function isSub(ext) {
return ext === "srt" || ext === "ass" || ext === "ssa";
}
function isNumeric(str) {
return !isNaN(parseInt(str));
}
function getSize(size) {
if (size <= 0) return "";
if (size > 1024 * 1024 * 1024 * 1024.0) {
size /= (1024 * 1024 * 1024 * 1024.0);
return size.toFixed(2) + "TB";
} else if (size > 1024 * 1024 * 1024.0) {
size /= (1024 * 1024 * 1024.0);
return size.toFixed(2) + "GB";
} else if (size > 1024 * 1024.0) {
size /= (1024 * 1024.0);
return size.toFixed(2) + "MB";
} else {
size /= 1024.0;
return size.toFixed(2) + "KB";
}
}
function removeExt(text) {
return text.indexOf('.') > -1 ? text.substring(0, text.lastIndexOf(".")) : text;
}
async function log(str) {
console.debug(str);
}
function isVideoFormat(url) {
var RULE = /http((?!http).){12,}?\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)\?.*|http((?!http).){12,}\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)|http((?!http).)*?video\/tos*/;
if (url.indexOf("url=http") > -1 || url.indexOf(".js") > -1 || url.indexOf(".css") > -1 || url.indexOf(".html") > -1) {
return false;
}
return RULE.test(url);
}
function jsonParse(input, json) {
var jsonPlayData = JSON.parse(json);
var url = jsonPlayData.url;
if (url.startsWith("//")) {
url = "https:" + url;
}
if (!url.startsWith("http")) {
return null;
}
if (url === input) {
if (!isVideoFormat(url)) {
return null;
}
}
var headers = {};
var ua = jsonPlayData["user-agent"] || "";
if (ua.trim().length > 0) {
headers["User-Agent"] = " " + ua;
}
var referer = jsonPlayData.referer || "";
if (referer.trim().length > 0) {
headers["Referer"] = " " + referer;
}
var taskResult = {
header: headers, url: url
};
return taskResult;
}
function debug(obj) {
for (var a in obj) {
if (typeof (obj[a]) == "object") {
debug(obj[a]); //递归遍历
} else {
console.debug(a + "=" + obj[a]);
}
}
}
function objectToStr(params = null, isBase64Encode = false) {
let params_str_list = []
if (params !== null) {
for (const key of Object.keys(params)) {
if (isBase64Encode) {
params_str_list.push(`${key}=${encodeURIComponent(params[key])}`)
} else {
params_str_list.push(`${key}=${params[key]}`)
}
}
}
return params_str_list.join("&")
}
function sleep(delay) {
const start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay * 1000) {
continue;
}
}
function getStrByRegex(pattern, str) {
let matcher = pattern.exec(str);
if (matcher !== null) {
if (matcher.length >= 1) {
if (matcher.length >= 1) return matcher[1]
}
}
return "";
}
function getStrByRegexDefault(pattern, str) {
let matcher = pattern.exec(str);
if (matcher !== null) {
if (matcher.length >= 1) {
if (matcher.length >= 1) return matcher[1]
}
}
return str;
}
function base64Encode(text) {
return Crypto.enc.Base64.stringify(Crypto.enc.Utf8.parse(text));
}
function base64Decode(text) {
return Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(text));
}
function unescape(code) {
return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
}
function decode(buffer, encode_type) {
let decoder = new TextDecoder(encode_type)
return decoder.decode(buffer)
}
function encode(buffer, encode_type) {
let encoder = new TextEncoder(encode_type)
return encoder.encode(buffer)
}
function getHost(url) {
let url_list = url.split("/")
return url_list[0] + "//" + url_list[2]
}
function unquote(str) {
return str.replace(/^"(.*)"$/, '$1');
}
function md5Encode(text) {
return Crypto.MD5(Crypto.enc.Utf8.parse(text)).toString();
}
function getUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
}) + "-" + new Date().getTime().toString(16)
}
function objToList(list, key, split_value = "*") {
let value_list = []
for (const dic of list) {
value_list.push(dic[key])
}
return value_list.join(split_value)
}
function getPropertiesAndMethods(obj) {
let str = ""
for (let key in obj) {
if (typeof obj[key] === 'function') {
str = str + "方法名:" + key + '()' + "\n";
} else {
str = str + "属性名:" + (key + ': ' + obj[key]) + "\n";
}
}
return str
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
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,
};
}
function randStr(len, withNum, onlyNum) {
let _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (let 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;
}
function randDeviceWithId(len) {
let device = randDevice();
device['id'] = randStr(len);
return device;
}
function randUUID() {
return randStr(8).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(4).toLowerCase() + '-' + randStr(12).toLowerCase();
}
function formatUrl(url) {
if (url.indexOf("https:////") > -1) {
url = "https://" + url.replaceAll("https:////", "")
}
if (url.indexOf("http:////") > -1) {
url = "http://" + url.replaceAll("http:////", "")
}
return url
}
function formatContent(content) {
return content.replaceAll('&amp;', '&')
.replaceAll('&lt;', '<')
.replaceAll('&gt;', '>')
.replaceAll('&quot;', '\"')
.replaceAll(/<\/?[^>]+>/g, '');
}
/**
* 字符串相似度匹配
* @returns
*/
function lcs(str1, str2) {
if (!str1 || !str2) {
return {
length: 0,
sequence: '',
offset: 0,
};
}
var sequence = '';
var str1Length = str1.length;
var str2Length = str2.length;
var num = new Array(str1Length);
var maxlen = 0;
var lastSubsBegin = 0;
for (var i = 0; i < str1Length; i++) {
var subArray = new Array(str2Length);
for (var j = 0; j < str2Length; j++) {
subArray[j] = 0;
}
num[i] = subArray;
}
var thisSubsBegin = null;
for (i = 0; i < str1Length; i++) {
for (j = 0; j < str2Length; j++) {
if (str1[i] !== str2[j]) {
num[i][j] = 0;
} else {
if (i === 0 || j === 0) {
num[i][j] = 1;
} else {
num[i][j] = 1 + num[i - 1][j - 1];
}
if (num[i][j] > maxlen) {
maxlen = num[i][j];
thisSubsBegin = i - num[i][j] + 1;
if (lastSubsBegin === thisSubsBegin) {
// if the current LCS is the same as the last time this block ran
sequence += str1[i];
} else {
// this block resets the string builder if a different LCS is found
lastSubsBegin = thisSubsBegin;
sequence = ''; // clear it
sequence += str1.substr(lastSubsBegin, i + 1 - lastSubsBegin);
}
}
}
}
}
return {
length: maxlen,
sequence: sequence,
offset: thisSubsBegin,
};
}
function findAllIndexes(arr, value) {
const indexes = arr.map((item, index) => index).filter(index => arr[index] === value);
return indexes;
}
let patternAli = /(https:\/\/www\.aliyundrive\.com\/s\/[^"]+|https:\/\/www\.alipan\.com\/s\/[^"]+)/
let patternQuark = /(https:\/\/pan\.quark\.cn\/s\/[^"]+)/
export {
isSub,
getSize,
removeExt,
log,
isVideoFormat,
jsonParse,
debug,
CHROME,
objectToStr,
sleep,
getStrByRegex,
RESOURCEURL,
base64Encode,
base64Decode,
patternAli,
patternQuark,
unescape,
decode,
MOBILEUA,
isNumeric,
getHost,
unquote,
md5Encode,
getStrByRegexDefault,
getUUID,
objToList,
getPropertiesAndMethods,
formatPlayUrl,
randDeviceWithId,
randStr,
randUUID,
formatContent,
formatUrl,
encode,
lcs,
findAllIndexes
};

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