Add files via upload

This commit is contained in:
newrecha
2024-08-25 20:53:29 +08:00
committed by GitHub
parent 638638505a
commit 544bdfae66
64 changed files with 18489 additions and 0 deletions
+238
View File
@@ -0,0 +1,238 @@
/*
* @File : 4kysxz.js.js
* @Author : jade
* @Date : 2024/1/24 16:47
* @Email : [email protected]
* @Software : Samples
* @Desc : 4k高清网 (已失效)
*/
import {_} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class YSXZSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://4kysxz.top"
}
getAppName() {
return `4K高清网`
}
getName() {
return `🚄┃4K高清网┃🚄`
}
getJSName() {
return "4kysxz"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
}
async parseVodShortListFromDoc($) {
const cards = $('div.row.posts-wrapper >div > article > div.entry-media > div > a')
return _.map(cards, (n) => {
let id = n.attribs['href'];
let name = $($(n).find('img')[0]).attr('alt').replaceAll('<strong>', '').replaceAll('</strong>', '').split(' ')[0];
let pic = $($(n).find('img')[0]).attr('data-src');
return {
vod_id: id, vod_name: name, vod_pic: pic, vod_remarks: '',
};
});
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodElement = $("[class=\"entry-content u-text-format u-clearfix\"]")
let text = "";
for (const vodEle of vodElement) {
text = text + $(vodEle).text().replaceAll("", ":") + "\n"
}
vodDetail.vod_name = $($("[class=\"article-title\"]")).text()
vodDetail.vod_pic = $($("[class=\"entry-content u-text-format u-clearfix\"]")).find("img")[0].attribs["src"]
vodDetail.vod_area = Utils.getStrByRegex(/上映地区(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_director = Utils.getStrByRegex(/导演(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_actor = Utils.getStrByRegex(/主演(.*?)\n/, text).replaceAll(":", "")
vodDetail.vod_content = Utils.getStrByRegex(/剧情简介(.*?)\n/, text).replaceAll(":", "").replaceAll("·", "")
let actors = _.map($('div.entry-content.u-text-format.u-clearfix > div:nth-child(10) > div > span > span'), (n) => {
return $(n).text().split(' ')[0];
});
vodDetail.vod_actor = actors.join('/');
let directors = _.map($('div.entry-content.u-text-format.u-clearfix > div:nth-child(6) > div > span'), (n) => {
return $(n).text().split(' ')[0];
});
vodDetail.vod_director = directors.join('/');
vodDetail.vod_name = $('div.site-content > section > div > header > h1').text().trim();
let playUrlStr = '';
let playFromStr = '';
//高清直播
const cards = $('div.entry-content.u-text-format.u-clearfix > custag > ul > li > a');
if (cards.length > 0) {
let playUrls = _.map(cards, (n) => {
let playUrl = n.attribs['href'];
if (playUrl.indexOf('url=') > 0) {
playUrl = playUrl.split('url=')[1].split('&name')[0];
}
return $(n).text() + '$' + playUrl;
});
playUrlStr = playUrls.join('#');
playFromStr = '高清直播';
}
if (!this.catOpenStatus) {
//磁力链接
const tbs = $('loginshow > table');
let playFrom = '';
let nameUrls = [];
for (let i = 0; i < tbs.length; i++) {
if (i % 2 == 0) {
playFrom = $(tbs[i]).find('tbody > tr >td').text().replaceAll('WEB', '磁力');
} else if (i % 2 == 1) {
const tds = $(tbs[i]).find('tbody > tr >td');
let nameUrl = '';
for (let j = 0; j < tds.length; j++) {
if (j % 2 == 0) {
nameUrl = $(tds[j]).text().split('.')[0].split(' ')[0];
} else if (j % 2 == 1) {
nameUrl = nameUrl + '$' + $(tds[j]).text().split('【')[0];
nameUrls.push(nameUrl);
}
}
if (playFromStr.length > 0) {
playFromStr += '$$$';
playUrlStr += '$$$';
}
playFromStr += playFrom;
playUrlStr += nameUrls.join('#');
}
}
}
vodDetail.vod_play_from = playFromStr
vodDetail.vod_play_url = playUrlStr
return vodDetail
}
async setClasses() {
this.classes = []
this.classes.push(this.getTypeDic("首页", "/#"))
}
async getFilter(typeElements) {
let value_list = []
value_list.push({
"n": "全部", "v": "全部",
})
for (const typeElement of typeElements) {
value_list.push({
"n": typeElement.attribs["title"],
"v": typeElement.attribs["href"].split("/").slice(-1)[0].split(".")[0],
})
}
return [{"key": "1", "name": "类型", "value": value_list}]
}
async setFilterObj() {
let $ = await this.getHtml()
let navElements = $("[class=\"navbar-item menu-item-has-children\"]")
let extent_list = []
for (const navElement of navElements) {
let type_name = $($(navElement).find("a")[0]).text()
if (type_name.indexOf("影视") > -1) {
let extend_dic = {"key": "1", "name": type_name, "value": []}
let type_elements = $($(navElement).find("ul")).find("a")
for (const type_element of type_elements) {
extend_dic["value"].push({"n": $(type_element).text(), "v": type_element.attribs["href"]})
}
extent_list.push(extend_dic)
}
}
this.filterObj["/#"] = extent_list
}
async setCategory(tid, pg, filter, extend) {
let url;
if (extend["1"] === undefined) {
url = this.siteUrl + tid
} else {
if (extend["1"].indexOf("category") > -1) {
url = this.siteUrl + extend["1"].split(".")[0] + "_" + pg + ".html"
} else {
url = this.siteUrl + extend["1"]
}
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
const $ = await this.getHtml(id);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + '/search.php?q=' + wd)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
let spider = new YSXZSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+299
View File
@@ -0,0 +1,299 @@
/*
* @Author: samples [email protected]
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples [email protected]
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/aiyingshi.js
* @Description: 爱影视爬虫类
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class AiYingShiSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://aiyingshis.com';
}
getName() {
return "🚀‍┃爱影视┃🚀"
}
getAppName() {
return "爱影视"
}
getJSName() {
return "aiyingshi"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
let pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src')
if (pic.indexOf("img.php?url=") > 0) {
pic = pic.split("img.php?url=")[1]
}else if (pic.indexOf("https:") === -1 && pic.indexOf("http:") === -1){
pic = "https:" + pic
}
vodShort.vod_pic = pic
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
if (vodShort.vod_name !== undefined){
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($("[class=\"video-cover\"]")).find(".lazyload")[0].attribs["data-src"]
let video_info_list = $($(".video-info-aux")).text().replaceAll("\t","").split("\n")
let type_list = []
for (const video_info of video_info_list){
if (!_.isEmpty(video_info.replaceAll(" ","").replaceAll("/",""))){
type_list.push(video_info.replaceAll(" ","").replaceAll("/",""))
}
}
vodDetail.type_name = type_list.slice(0,2).join("*")
let video_items = $("[class=\"video-info-items\"]")
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const vidoe_info_actor of vidoe_info_actor_list) {
actor_list.push(vidoe_info_actor.children[0].data)
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = type_list[2]
vodDetail.vod_remarks = $($(video_items[3]).find(".video-info-item")).text()
vodDetail.vod_content = $($(video_items[5]).find(".video-info-item")).text()
vodDetail.vod_area = type_list[3]
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "").replaceAll("\t","").replaceAll("\n","")
let playElements = $($("[class=\"module-tab-content\"]")[0]).find("span")
let urlElements = $("[class=\"module-list module-player-list tab-list sort-list \"]")
let form_list = []
for (const playerElement of playElements){
form_list.push($(playerElement).text())
}
let play_url_list = []
for (const urlElement of urlElements){
let playUrlElements = $($(urlElement).find("[class=\"sort-item\"]")).find("a")
let vodItems = []
for (const playUrlElement of playUrlElements){
let name = $(playUrlElement).text()
let url = playUrlElement.attribs["href"]
let play_url = name + "$" + url
vodItems.push(play_url)
}
play_url_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = form_list.join('$$$');
vodDetail.vod_play_url = _.values(play_url_list).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src']
vodShort.vod_remarks = $($(item).find(".video-serial")[0]).text();
vod_list.push(vodShort);
}
return vod_list
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $($("[class=\"nav-menu-items\"]")[0]).find("li")
for (const element of elements.slice(0,6)) {
let type_name = $($(element).find("span")).text()
if (type_name !== "首页"){
let type_id = $(element).find("a")[0].attribs["href"].split("/").slice(-1)[0].split(".")[0]
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
}
async getFilter($) {
let elements = $("[class=\"scroll-content\"]").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
if ($($(elements[i]).find("a")[0]).text() === "全部类型"){
extend_dic["value"].push({"n": $(ele).text(), "v":ele.attribs["href"].split("/").slice(-1)[0].split(".")[0]})
}else{
extend_dic["value"].push({"n": $(ele).text(), "v":$(ele).text()})
}
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/vodshow/id/${type_id}.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
getExtend(value,defaultvalue,key = ""){
if (value !== undefined && value !== "0"){
return key + value
}else{
return defaultvalue
}
}
async getCateUrl(tid,pg,extend){
tid = this.getExtend(extend["1"],tid)
let area = this.getExtend(extend["2"],"","/area/")
let lanuage = this.getExtend(extend["3"],"","/lang/")
let year = this.getExtend(extend["4"],"","/year/")
let letter = this.getExtend(extend["5"],"","/letter/")
let time = this.getExtend(extend['6'],"","/by/")
return this.siteUrl + `/vodshow${time}${area}/id/${tid}${lanuage}${letter}${year}/page/${pg}.html`
}
async setCategory(tid, pg, filter, extend) {
let reqUrl = await this.getCateUrl(tid,pg,extend)
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
let html = await this.fetch(this.siteUrl + id,null,this.getHeader())
if (!_.isEmpty(html)){
let player_str = Utils.getStrByRegex(/<script type="text\/javascript">var player_aaaa=(.*?)<\/script>/,html)
let play_dic = JSON.parse(player_str)
this.playUrl = play_dic["url"]
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/vodsearch/wd/${wd}.html`
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new AiYingShiSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,proxy:proxy
};
}
export {spider}
+229
View File
@@ -0,0 +1,229 @@
/*
* @File : alipansou.js
* @Author : jade
* @Date : 2024/1/18 13:20
* @Email : [email protected]
* @Software : Samples
* @Desc : 猫狸盘搜
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import { detailContent,initCloud,playContent,getHeaders } from "../lib/cloud.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class GitCafeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.alipansou.com"
}
getHeaders(id) {
let headers = this.getHeader()
headers["Referer"] = this.siteUrl + id
headers["_bid"] = "6d14a5dd6c07980d9dc089a693805ad8"
headers["Cookie"] = "_egg=70463dec0ec843b682ce18c36ec9ce91e"
return headers
}
getName() {
return "😸┃阿里猫狸┃😸"
}
getAppName() {
return "阿里猫狸"
}
getJSName() {
return "alipansou"
}
getType() {
return 3
}
getHeader() {
return {
"User-Agent":Utils.CHROME,
"Connection": "keep-alive"
}
}
async getContentHtml() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
return load(html)
}
}
async spiderInit() {
this.content_html = await this.getContentHtml()
}
async init(cfg) {
await this.spiderInit()
await super.init(cfg);
await initCloud(this.cfgObj);
}
async parseClassFromDoc($) {
let tap_elemets = $($("[id=\"app\"]")[0]).find("van-tab")
let index = 0
for (const tap_element of tap_elemets) {
let type_name = tap_element.attribs["title"]
if (type_name.indexOf("热搜") === -1 && type_name !== "游戏" && type_name !== "小说") {
this.classes.push({"type_name": type_name, "type_id": index})
}
index = index + 1
}
}
async parseVodShortListFromDoc(doc) {
let vod_list = []
let elements = this.content_html(doc).find("a")
for (const element of elements) {
let vodShort = new VodShort()
vodShort.vod_id = element.attribs["href"]
vodShort.vod_name = this.content_html(element).text().split(".").slice(-1)[0]
vod_list.push(vodShort)
}
return vod_list
}
async getAliUrl(id) {
let url = this.siteUrl + id.replace("/s/", "/cv/")
let headers = this.getHeaders(id)
let content = await req(url,{postType:"get",headers:headers,redirect:2})
await this.jadeLog.debug(`回复内容为:${JSON.stringify(content)}`)
// let url = await this.fetch(this.siteUrl + id.replace("/s/", "/cv/"), null, headers, true)
return content.headers.location
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail();
vodDetail.vod_name = obj["name"]
vodDetail.vod_remarks = obj["remarks"]
let ali_url = await this.getAliUrl(obj["id"])
await this.jadeLog.debug(`阿里分享链接为:${ali_url}`)
if (!_.isEmpty(ali_url)) {
let playVod = await detailContent([ali_url],vodDetail.type_name)
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let elements = $($($("[id=\"app\"]")[0]).find("van-row")).find("a")
let vod_list = []
for (const element of elements) {
let id = element.attribs["href"]
let matches = id.match(/(\/s\/[^"])/);
if (!_.isEmpty(matches) && id.indexOf("https") === -1) {
let text = $(element).text().replaceAll("\n", "").replaceAll(" ", "")
if (text.indexOf("时间") > -1 && text.indexOf("文件夹") > -1) {
let textList = text.split("时间")
let vodShort = new VodShort()
vodShort.vod_name = textList[0]
vodShort.vod_remarks = textList[1].split("格式")[0].replaceAll(":", "").replaceAll(" ", "").replaceAll("", "").replaceAll(" ", "")
vodShort.vod_id = JSON.stringify({
"name": vodShort.vod_name, "remarks": vodShort.vod_remarks, "id": id
})
vod_list.push(vodShort)
}
}
}
return vod_list
}
async setClasses() {
await this.parseClassFromDoc(this.content_html)
}
async setHomeVod() {
let tap_elemets = this.content_html(this.content_html("[id=\"app\"]")[0]).find("van-tab")
this.homeVodList = await this.parseVodShortListFromDoc(tap_elemets[0])
}
async setDetail(id) {
if (id.indexOf("search") > -1) {
let url = this.siteUrl + "/search"
let params = {"k":decodeURIComponent(id.split("search?k=").slice(-1)[0]) }
let html = await this.fetch(url, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let vod_list = await this.parseVodShortListFromDocBySearch($)
if (vod_list.length > 0) {
id = vod_list[0]["vod_id"]
} else {
id = ""
}
}
}
if (!_.isEmpty(id)) {
let json_content = JSON.parse(id)
this.vodDetail = await this.parseVodDetailfromJson(json_content)
}
}
async setCategory(tid, pg, filter, extend) {
let tap_elemets = this.content_html(this.content_html("[id=\"app\"]")[0]).find("van-tab")
this.vodList = await this.parseVodShortListFromDoc(tap_elemets[parseInt(tid)])
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search"
let params = {"k": wd}
let html = await this.fetch(url, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
let spider = new GitCafeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+227
View File
@@ -0,0 +1,227 @@
/*
* @File : aliyunpanshare.js
* @Author : jade
* @Date : 2024/1/26 13:06
* @Email : [email protected]
* @Software : Samples
* @Desc : 阿里云盘分享
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import { detailContent,initCloud,playContent,getHeaders} from "../lib/cloud.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
let remark_list = ["4k", "4K"]
class AliyunpanShare extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.alypw.com';
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj);
}
getName() {
return "🥏‍┃阿里云盘分享┃🥏‍"
}
getAppName() {
return "阿里云盘分享"
}
getJSName() {
return "aliyunpanshare"
}
getType() {
return 3
}
getRemarks(name, title) {
if (_.isEmpty(name)) {
for (const remark of remark_list) {
if (title.indexOf(remark) > -1) {
return remark
}
}
} else {
return name
}
}
parseVodName(name) {
let vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?) /, name)
if (name.indexOf("合集") > -1) {
return ""
}
if (_.isEmpty(vod_name)) {
vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?)/, name)
}
if (vod_name.indexOf("[") > -1) {
vod_name = vod_name.split("[")[0]
}
if (vod_name.indexOf("【") > -1) {
vod_name = vod_name.split("【")[0]
}
if (vod_name === "4K") {
return ""
}
return vod_name
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"hometab\"]").find("[class=\"box\"]")).find("li")
for (const vodElement of vodElements) {
let ele = $(vodElement).find("[class=\"imgr\"]")[0]
let vodShort = new VodShort();
vodShort.vod_id = $(ele).find("a")[0].attribs["href"]
let name = $(ele).find("a")[0].attribs["title"]
vodShort.vod_name = this.parseVodName(name)
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["src"]
vodShort.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let mainElement = $("[class=\"main container\"]")
let vodElements = $($(mainElement).find("[class=\"list\"]")).find("li")
if (vodElements.length === 0) {
vodElements = $(mainElement).find("li")
}
for (const vodElement of vodElements) {
let name = $(vodElement).find("img")[0].attribs["alt"].replaceAll("<strong>", "").replaceAll("</strong>", "")
let vodShort = new VodShort();
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
vodShort.vod_name = this.parseVodName(name)
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["src"]
vodShort.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
if (!_.isEmpty(vodShort.vod_name)) {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let mainElements = $("[class=\"mainl\"]")
let name = $($(mainElements).find("[class=\"title\"]")[0]).text()
let vodDetail = new VodDetail();
vodDetail.vod_name = Utils.getStrByRegex(/\[阿里云盘](.*?) /, name)
vodDetail.vod_remarks = this.getRemarks(Utils.getStrByRegex(/【(.*?)】/, name), name)
let articleElement = $(mainElements).find("[class=\"article_content\"]")
vodDetail.vod_pic = $(articleElement).find("p>img")[0].attribs["src"]
let articleElements = $(articleElement).find("p")
let articleContent = ""
for (const articleEle of articleElements) {
articleContent = articleContent + $(articleEle).text() + "\n"
}
let share_ali_url_list = []
let share_url_list = Utils.getStrByRegex(Utils.patternAli, articleContent).split("\n")
for (const share_url of share_url_list) {
let matches = share_url.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_ali_url_list.push(matches[1])
let quarkMatches = share_url.match(Utils.patternQuark);
if (!_.isEmpty(quarkMatches)) share_ali_url_list.push(quarkMatches[1])
}
let playVod = await detailContent([share_ali_url_list])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
vodDetail.type_name = Utils.getStrByRegex(/标签(.*?)\n/, articleContent).replaceAll("", "")
vodDetail.vod_content = Utils.getStrByRegex(/描述(.*?)\n/, articleContent).replaceAll("", "")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let typeElements = $("[id^='navbar-category']").find("a")
let key_list = ["影", "剧", "4K", "视", "音", "演", "动漫"]
for (const typeElement of typeElements) {
let type_name = $(typeElement).text()
let type_id = typeElement.attribs["href"]
let is_show = false
for (const key of key_list) {
if (type_name.indexOf(key) > -1) {
is_show = true
}
}
if (is_show) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let cateUrl = tid.split(".html")[0] + "_" + pg + ".html"
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
async setSearch(wd, quick) {
let url = this.siteUrl + `/search.php?q=${wd}`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new AliyunpanShare()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+183
View File
@@ -0,0 +1,183 @@
/*
* @Author: samples [email protected]
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples [email protected]
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/asianx.js
* @Description: asianx
*/
import {Spider} from "./spider.js";
import {Crypto, _, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class AsianXSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://cn.asianx.tube/"
}
getName() {
return "🔞┃海外宅┃🔞"
}
getAppName() {
return "海外宅"
}
getJSName() {
return "asianx"
}
getType() {
return 3
}
async getFilter($) {
let navElements = $($("[class=\"menu m-0 mb-2 mb-lg-0\"]")).find("a").slice(6)
let extend_dic = {"key": "1", "name": "分类", "value": [{"n": "全部", "v": "全部"}]}
for (const navElement of navElements) {
let type_name = $($(navElement).find("span")).text()
let type_id = navElement.attribs["href"]
extend_dic["value"].push({"n": type_name, "v": type_id})
}
return [extend_dic]
}
async parseVodShortListFromDoc($,is_home=false) {
let vod_list = []
let vodShortElements;
if (is_home){
vodShortElements = $($("[class=\"gal-box\"]")).slice(12)
}else{
vodShortElements = $($("[class=\"gal-box\"]"))
}
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElements = $(vodShortElement).find("a")
vodShort.vod_id = vodElements[0].attribs["href"]
vodShort.vod_pic = $(vodElements[0]).find("img")[0].attribs["data-src"]
vodShort.vod_name = vodElements[1].attribs["title"]
vodShort.vod_remarks = $($(vodShortElement).find("[class=\"meta text-muted text-truncate\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc(html) {
let vodDetail = new VodDetail();
let content = Utils.getStrByRegex(/<script type="application\/ld\+json">(.*?)<\/script>/,html)
let content_json = JSON.parse(content)
let textList = content_json["name"].split(" ")
vodDetail.vod_name = textList[0]
vodDetail.vod_play_from = ["未加密线路","加密线路"].join("$$$")
let playUrl1 = content_json["contentUrl"]
let playUrl2 = content_json["embedUrl"]
vodDetail.vod_play_url = [`${textList[0]}$${playUrl1}`,`${textList[0]}$${playUrl2}`].join("$$$")
vodDetail.vod_remarks = content_json["uploadDate"]
vodDetail.vod_content = content_json["description"]
return vodDetail
}
async setClasses() {
this.classes = []
this.classes.push({"type_name": "首页", "type_id": "/"})
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let navElements = $($("[class=\"menu m-0 mb-2 mb-lg-0\"]")).find("a").slice(0, 5)
for (const navElement of navElements) {
let type_name = $($(navElement).find("span")).text()
let type_id = navElement.attribs["href"]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
this.filterObj[this.classes[0].type_id] = await this.getFilter($)
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($,true)
}
}
getExtend(pg,extend){
if (extend["1"] !== undefined){
if (extend["1"] === "全部"){
return this.siteUrl
}else{
return this.siteUrl + extend["1"] + "/" + pg
}
}else{
return this.siteUrl
}
}
async setDetail(id) {
let html = await this.fetch(id,null,this.getHeader())
if (!_.isEmpty(html)){
this.vodDetail = await this.parseVodDetailFromDoc(html)
}
}
async setCategory(tid, pg, filter, extend) {
let url;
if (tid === "/") {
url = this.getExtend(pg,extend)
} else {
url = this.siteUrl + tid + "/" + pg
}
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($,false)
}
}
}
let spider = new AsianXSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}
+258
View File
@@ -0,0 +1,258 @@
/*
* @File : audiomack.js
* @Author : jade
* @Date : 2024/1/31 15:56
* @Email : [email protected]
* @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}
+85
View File
@@ -0,0 +1,85 @@
/*
* @File : base_spider.js.js
* @Author : jade
* @Date : 2024/1/4 14:13
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {JadeLogging} from "../lib/log.js";
import {Result, SpiderInit} from "../lib/spider_object.js";
const JadeLog = new JadeLogging(getAppName(), "DEBUG")
let result = new Result()
let CatOpenStatus = false
function getName() {
return `🍥┃基础┃🍥`
}
function getAppName() {
return `基础`
}
async function init(cfg) {
let obj = await SpiderInit(cfg)
CatOpenStatus = obj.CatOpenStatus
// 读取缓存
}
async function home(filter) {
await JadeLog.info("正在解析首页类别", true)
try{
await JadeLog.debug(`首页类别内容为:${result.home()}`)
await JadeLog.info("首页类别解析完成", true)
return result.homeVod()
}catch (e){
await this.jadeLog.error(`首页内容解析失败,失败原因为:{e}`)
}
}
async function homeVod() {
let vod_list = []
if (!CatOpenStatus) {
await JadeLog.info("正在解析首页内容")
}
await JadeLog.debug(`首页内容为:${JSON.stringify({"list": vod_list})}`)
return JSON.stringify({"list": vod_list})
}
async function category(tid, pg, filter, extend) {
let url = ""
await JadeLog.info(`正在解析分类页面,tid = ${tid},pg = ${pg},filter = ${filter},extend = ${JSON.stringify(extend)},url = ${url}`)
}
async function detail(id) {
return JSON.stringify({})
}
async function play(flag, id, flags) {
return JSON.stringify({});
}
async function search(wd, quick) {
let url = ""
await JadeLog.info(`正在解析搜索页面,关键词为 = ${wd},quick = ${quick},url = ${url}`)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
+571
View File
@@ -0,0 +1,571 @@
/*
* @File : bilibili.js
* @Author : jade
* @Date : 2024/4/3 9:27
* @Email : [email protected]
* @Software : Samples
* @Desc : 哔哩哔哩
*/
import {Spider} from "./spider.js";
import * as Utils from "../lib/utils.js";
import {Crypto, _, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class BilibiliSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.bilibili.com"
this.apiUrl = "https://api.bilibili.com"
this.cookie = ""
this.bili_jct = '';
this.is_login = false
this.is_vip = false
this.vod_audio_id = {
30280: 192000,
30232: 132000,
30216: 64000,
};
this.vod_codec = {
// 13: 'AV1',
12: 'HEVC',
7: 'AVC',
};
this.play_url_obj = {
80: "1080P 高清",
64: "720P 高清",
32: "420P 清晰",
16: "360P 流畅"
}
}
getHeader() {
const headers = super.getHeader();
if (!_.isEmpty(this.cookie)) {
headers["cookie"] = this.cookie;
}
return headers;
}
initCookie(cookie) {
this.cookie = cookie
if (cookie.includes('bili_jct')) {
this.bili_jct = cookie.split('bili_jct=')[1].split(";")[0];
}
}
async spiderInit(Req) {
this.is_login = await this.checkLogin()
if (this.is_login) {
await this.jadeLog.info("哔哩哔哩登录成功", true)
} else {
await this.jadeLog.error("哔哩哔哩登录失败", true)
}
if (Req === null) {
// dash mpd 代理
this.js2Base = await js2Proxy(true, this.siteType, this.siteKey, 'dash/', this.getHeader());
} else {
this.js2Base = await js2Proxy(Req, "dash", this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.initCookie(this.cfgObj["cookie"])
await this.spiderInit(null)
this.danmuStaus = true
}
getName() {
return "🏰┃哔哩哔哩┃🏰"
}
getAppName() {
return "哔哩哔哩"
}
getJSName() {
return "bilibili"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"channel-items__left\"]").find("a")
for (const navElement of navElements) {
this.classes.push(this.getTypeDic($(navElement).text(), $(navElement).text()))
}
if (!_.isEmpty(this.bili_jct) && this.is_login) {
this.classes.push(this.getTypeDic("历史记录", "历史记录"))
}
}
async getFilter($) {
return [
{
key: 'order',
name: '排序',
value: [
{n: '综合排序', v: '0'},
{n: '最多点击', v: 'click'},
{n: '最新发布', v: 'pubdate'},
{n: '最多弹幕', v: 'dm'},
{n: '最多收藏', v: 'stow'},
],
},
{
key: 'duration',
name: '时长',
value: [
{n: '全部时长', v: '0'},
{n: '60分钟以上', v: '4'},
{n: '30~60分钟', v: '3'},
{n: '10~30分钟', v: '2'},
{n: '10分钟以下', v: '1'},
],
},
];
}
async setFilterObj() {
for (const typeDic of this.classes) {
let type_id = typeDic["type_name"]
if (type_id !== "最近更新" && type_id !== "历史记录") {
this.filterObj[type_id] = await this.getFilter()
}
}
}
getFullTime(numberSec) {
let totalSeconds = '';
try {
let timeParts = numberSec.split(":");
let min = parseInt(timeParts[0]);
let sec = parseInt(timeParts[1]);
totalSeconds = min * 60 + sec;
} catch (e) {
totalSeconds = parseInt(numberSec);
}
if (isNaN(totalSeconds)) {
return '无效输入';
}
if (totalSeconds >= 3600) {
const hours = Math.floor(totalSeconds / 3600);
const remainingSecondsAfterHours = totalSeconds % 3600;
const minutes = Math.floor(remainingSecondsAfterHours / 60);
const seconds = remainingSecondsAfterHours % 60;
return `${hours}小时 ${minutes}分钟 ${seconds}`;
} else {
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}分钟 ${seconds}`;
}
}
removeTags(input) {
return input.replace(/<[^>]*>/g, '');
}
async parseVodShortListFromJson(objList) {
let vod_list = []
for (const vodData of objList) {
let vodShort = new VodShort()
vodShort.vod_id = vodData["bvid"]
if (vodData.hasOwnProperty("rcmd_reason")) {
vodShort.vod_remarks = vodData["rcmd_reason"]["content"]
} else {
vodShort.vod_remarks = this.getFullTime(vodData["duration"])
}
vodShort.vod_name = this.removeTags(vodData["title"])
let imageUrl = vodData["pic"];
if (imageUrl.startsWith('//')) {
imageUrl = 'https:' + imageUrl;
}
vodShort.vod_pic = imageUrl
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj, bvid) {
let cd = this.getFullTime(obj["duration"]);
const aid = obj.aid;
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["title"]
vodDetail.vod_pic = obj["pic"]
vodDetail.type_name = obj["tname"]
vodDetail.vod_remarks = cd
vodDetail.vod_content = obj["desc"]
let params = {"avid": aid, "cid": obj["cid"], "qn": "127", "fnval": 4048, "fourk": 1}
let playUrlDatas = JSON.parse(await this.fetch(this.apiUrl + "/x/player/playurl", params, this.getHeader()));
let playUrldDataList = playUrlDatas["data"];
const accept_quality = playUrldDataList["accept_quality"];
const accept_description = playUrldDataList["accept_description"];
const qualityList = [];
const descriptionList = [];
for (let i = 0; i < accept_quality.length; i++) {
if (!this.is_vip) {
if (this.is_login) {
if (accept_quality[i] > 80) continue;
} else {
if (accept_quality[i] > 32) continue;
}
}
descriptionList.push(Utils.base64Encode(accept_description[i]));
qualityList.push(accept_quality[i]);
}
let treeMap = {};
const jSONArray = obj["pages"];
let playList = [];
for (let j = 0; j < jSONArray.length; j++) {
const jSONObject6 = jSONArray[j];
const cid = jSONObject6.cid;
const playUrl = j + '$' + aid + '+' + cid + '+' + qualityList.join(':') + '+' + descriptionList.join(':');
playList.push(playUrl);
}
if (this.catOpenStatus) {
for (let quality of qualityList) {
treeMap[`dash - ${this.play_url_obj[quality]}`] = playList.join("#")
}
} else {
await this.jadeLog.warning("TV暂不支持Dash播放")
}
for (let quality of qualityList) {
treeMap[`mp4 - ${this.play_url_obj[quality]}`] = playList.join("#")
}
let relatedParams = {"bvid": bvid}
const relatedData = JSON.parse(await this.fetch(this.apiUrl + "/x/web-interface/archive/related", relatedParams, this.getHeader())).data;
playList = [];
for (let j = 0; j < relatedData.length; j++) {
const jSONObject6 = relatedData[j];
const cid = jSONObject6.cid;
const title = jSONObject6.title;
const aaid = jSONObject6.aid;
const playUrl = title + '$' + aaid + '+' + cid + '+' + qualityList.join(':') + '+' + descriptionList.join(':');
playList.push(playUrl);
}
if (this.catOpenStatus) {
for (let quality of qualityList) {
treeMap["相关" + ` - ${this.play_url_obj[quality]}`] = playList.join("#")
}
} else {
await this.jadeLog.warning("TV暂不支持相关播放")
}
vodDetail.vod_play_from = Object.keys(treeMap).join("$$$");
vodDetail.vod_play_url = Object.values(treeMap).join("$$$");
return vodDetail
}
async setHomeVod() {
let params = {"ps": 20}
let content = await this.fetch(this.apiUrl + "/x/web-interface/popular", params, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content)["data"]["list"])
}
async setDetail(id) {
const detailUrl = this.apiUrl + "/x/web-interface/view";
let params = {"bvid": id}
const detailData = JSON.parse(await this.fetch(detailUrl, params, this.getHeader())).data
// 记录历史
if (!_.isEmpty(this.bili_jct)) {
const historyReport = this.apiUrl + '/x/v2/history/report';
let dataPost = {
aid: detailData.aid,
cid: detailData.cid,
csrf: this.bili_jct,
}
await this.post(historyReport, dataPost, this.getHeader(), "form");
}
this.vodDetail = await this.parseVodDetailfromJson(detailData, id)
}
findKeyByValue(obj, value) {
for (const key in obj) {
if (obj[key] === value) {
return key;
}
}
return null;
}
async setPlay(flag, id, flags) {
const ids = id.split('+');
const aid = ids[0];
const cid = ids[1];
let quality_name = flag.split(" - ")[1]
let quality_id = this.findKeyByValue(this.play_url_obj, quality_name)
this.danmuUrl = this.apiUrl + '/x/v1/dm/list.so?oid=' + cid;
this.result.header = this.getHeader()
if (flag.indexOf("dash") > -1 || flag.indexOf('相关') > -1) {
// dash mpd 代理
if (this.catOpenStatus) {
this.playUrl = this.js2Base + Utils.base64Encode(aid + '+' + cid + '+' + quality_id)
}
} else if (flag.indexOf('mp4') > -1) {
// 直链
const url = this.apiUrl + `/x/player/playurl`;
let params = {"avid": aid, "cid": cid, "qn": parseInt(quality_id), "fourk": "1"}
const resp = JSON.parse(await this.fetch(url, params, this.getHeader()));
const data = resp.data;
this.playUrl = data["durl"][0].url;
} else {
// 音频外挂
let urls = [];
let audios = [];
const url = this.siteUrl + "/x/player/playurl"
let params = {"avid": aid, "cid": cid, "qn": quality_id, "fnval": 4048, "fourk": 1};
let resp = JSON.parse(await this.fetch(url, params, this.getHeader()));
const dash = resp.data.dash;
const video = dash.video;
const audio = dash.audio;
for (let j = 0; j < video.length; j++) {
const dashjson = video[j];
if (dashjson.id === quality_id) {
for (const key in this.vod_codec) {
if (dashjson["codecid"] === key) {
urls.push(Utils.base64Decode(quality_id) + ' ' + this.vod_codec[key], dashjson["baseUrl"]);
}
}
}
}
if (audios.length === 0) {
for (let j = 0; j < audio.length; j++) {
const dashjson = audio[j];
for (const key in this.vod_audio_id) {
if (dashjson.id === key) {
audios.push({
title: _.floor(parseInt(this.vod_audio_id[key]) / 1024) + 'Kbps',
bit: this.vod_audio_id[key],
url: dashjson["baseUrl"],
});
}
}
}
audios = _.sortBy(audios, 'bit');
}
this.playUrl = urls
this.extra = {"audio": audios}
}
}
async checkLogin() {
let result = JSON.parse(await this.fetch('https://api.bilibili.com/x/web-interface/nav', null, this.getHeader()));
this.is_vip = result["data"]["vipStatus"]
return result["data"]["isLogin"]
}
async setCategory(tid, pg, filter, extend) {
let page;
if (parseInt(pg) < 1) {
page = 1;
} else {
page = parseInt(pg)
}
if (Object.keys(extend).length > 0 && extend.hasOwnProperty('tid') && extend['tid'].length > 0) {
tid = extend['tid'];
}
let url = '';
url = this.apiUrl + `/x/web-interface/search/type?search_type=video&keyword=${encodeURIComponent(tid)}`;
if (Object.keys(extend).length > 0) {
for (const k in extend) {
if (k === 'tid') {
continue;
}
url += `&${encodeURIComponent(k)}=${encodeURIComponent(extend[k])}`;
}
}
url += `&page=${encodeURIComponent(page)}`;
if (tid === "历史记录") {
url = this.apiUrl + "/x/v2/history?pn=" + page;
}
const data = JSON.parse(await this.fetch(url, null, this.getHeader())).data;
let items = data.result;
if (tid === "历史记录") {
items = data;
}
this.vodList = await this.parseVodShortListFromJson(items)
}
async setSearch(wd, quick, pg) {
const ext = {
duration: '0',
};
let page = parseInt(pg)
const limit = 20
let resp = JSON.parse(await this.category(wd, page, true, ext));
this.vodList = resp["list"]
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
getDashMedia(dash) {
try {
let qnid = dash.id;
const codecid = dash["codecid"];
const media_codecs = dash["codecs"];
const media_bandwidth = dash["bandwidth"];
const media_startWithSAP = dash["startWithSap"];
const media_mimeType = dash.mimeType;
const media_BaseURL = dash["baseUrl"].replace(/&/g, '&amp;');
const media_SegmentBase_indexRange = dash["SegmentBase"]["indexRange"];
const media_SegmentBase_Initialization = dash["SegmentBase"]["Initialization"];
const mediaType = media_mimeType.split('/')[0];
let media_type_params = '';
if (mediaType === 'video') {
const media_frameRate = dash.frameRate;
const media_sar = dash["sar"];
const media_width = dash.width;
const media_height = dash.height;
media_type_params = `height='${media_height}' width='${media_width}' frameRate='${media_frameRate}' sar='${media_sar}'`;
} else if (mediaType === 'audio') {
for (const key in this.vod_audio_id) {
if (qnid === key) {
const audioSamplingRate = this.vod_audio_id[key];
media_type_params = `numChannels='2' sampleRate='${audioSamplingRate}'`;
}
}
}
qnid += '_' + codecid;
return `<AdaptationSet lang="chi">
<ContentComponent contentType="${mediaType}"/>
<Representation id="${qnid}" bandwidth="${media_bandwidth}" codecs="${media_codecs}" mimeType="${media_mimeType}" ${media_type_params} startWithSAP="${media_startWithSAP}">
<BaseURL>${media_BaseURL}</BaseURL>
<SegmentBase indexRange="${media_SegmentBase_indexRange}">
<Initialization range="${media_SegmentBase_Initialization}"/>
</SegmentBase>
</Representation>
</AdaptationSet>`;
} catch (e) {
// Handle exceptions here
}
}
getDash(ja, videoList, audioList) {
const duration = ja.data.dash["duration"];
const minBufferTime = ja.data.dash["minBufferTime"];
return `<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" type="static" mediaPresentationDuration="PT${duration}S" minBufferTime="PT${minBufferTime}S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
<Period duration="PT${duration}S" start="PT0S">
${videoList}
${audioList}
</Period>
</MPD>`;
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'dash') {
const ids = url.split('+');
const aid = ids[0];
const cid = ids[1];
const str5 = ids[2];
const urls = this.apiUrl + `/x/player/playurl?avid=${aid}&cid=${cid}&qn=${str5}&fnval=4048&fourk=1`;
let videoList = '';
let audioList = '';
let content = await this.fetch(urls, null, headers);
let resp = JSON.parse(content)
const dash = resp.data.dash;
const video = dash.video;
const audio = dash.audio;
for (let i = 0; i < video.length; i++) {
// if (i > 0) continue; // 只取一个
const dashjson = video[i];
if (dashjson.id.toString() === str5) {
videoList += this.getDashMedia(dashjson);
}
}
for (let i = 0; i < audio.length; i++) {
// if (i > 0) continue;
const ajson = audio[i];
for (const key in this.vod_audio_id) {
if (ajson.id.toString() === key) {
audioList += this.getDashMedia(ajson);
}
}
}
let mpd = this.getDash(resp, videoList, audioList);
return JSON.stringify({
code: 200,
content: mpd,
headers: {
'Content-Type': 'application/dash+xml',
},
});
}
return JSON.stringify({
code: 500,
content: '',
});
}
}
let spider = new BilibiliSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+152
View File
@@ -0,0 +1,152 @@
/*
* @File : bookan.js
* @Author : jade
* @Date : 2024/1/31 13:44
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import {Spider} from "./spider.js";
function formatPlayUrl(name) {
return name
.trim()
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
class BooKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.bookan.com.cn";
}
getName() {
return "🎵┃看书┃🎵"
}
getAppName() {
return "看书"
}
getJSName() {
return "bookan"
}
getType() {
return 10
}
async parseVodShortListFromJson(obj) {
let books = [];
for (const book of obj.list) {
books.push({
book_id: book.id, book_name: book.name, book_pic: book.cover, book_remarks: book.extra.author,
});
}
return books
}
async setClasses() {
{
this.classes = [{type_id: '1305', type_name: '少年读物'}, {
type_id: '1304', type_name: '儿童文学'
}, {type_id: '1320', type_name: '国学经典'}, {type_id: '1306', type_name: '文艺少年'}, {
type_id: '1309', type_name: '育儿心经'
}, {type_id: '1310', type_name: '心理哲学'}, {type_id: '1307', type_name: '青春励志'}, {
type_id: '1312', type_name: '历史小说'
}, {type_id: '1303', type_name: '故事会'}, {type_id: '1317', type_name: '音乐戏剧'}, {
type_id: '1319', type_name: '相声评书'
},]
}
}
async setCategory(tid, pg, filter, extend) {
let content = await this.fetch(`${this.siteUrl}/voice/book/list?instance_id=25304&page=${pg}&category_id=${tid}&num=24`, null, this.getHeader());
let data = JSON.parse(content).data;
this.vodList = await this.parseVodShortListFromJson(data)
}
async parseVodDetailfromJson(obj) {
let book = {
audio: 1,
type_name: '',
book_year: '',
book_area: '',
book_remarks: '',
book_actor: '',
book_director: '',
book_content: '',
};
let us = _.map(obj.list, function (b) {
return formatPlayUrl(b.title) + '$' + b.file;
}).join('#');
book.volumes = '书卷';
book.urls = us;
return book
}
async setDetail(id) {
let content = await this.fetch(`${this.siteUrl}/voice/album/units?album_id=${id}&page=1&num=200&order=1`, null, this.getHeader());
let data = JSON.parse(content).data;
this.vodDetail = await this.parseVodDetailfromJson(data)
this.vodDetail.book_id = id
}
async play(flag, id, flags) {
return JSON.stringify({
parse: 0, url: id,
});
}
async setSearch(wd, quick) {
let content = await this.fetch(`https://es.bookan.com.cn/api/v3/voice/book?instanceId=25304&keyword=${wd}&pageNum=1&limitNum=20`,null,this.getHeader());
let data = JSON.parse(content).data;
this.vodList = await this.parseVodShortListFromJson(data)
}
}
let spider = new BooKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}
+268
View File
@@ -0,0 +1,268 @@
/*
* @File : bqg_open.js.js
* @Author : jade
* @Date : 2024/1/30 15:38
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class BQQSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://m.13bqg.com"
}
getAppName() {
return "笔趣阁"
}
getJSName() {
return "bqg_open"
}
getType() {
return 10
}
getName() {
return "📚︎┃笔趣阁┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $("[class=\"block\"]")
for (const bookElement of $(bookElements[0]).find("li")) {
let bookShort = new BookShort()
let bookShortElements = $(bookElement).find("span")
bookShort.book_remarks = $(bookShortElements[0]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = $(bookShortElements[1]).find("a")[0].attribs.href
bookShort.book_pic = this.jsBase + Utils.base64Encode(bookShort.book_id)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let books = [];
for (const item of $('div.item')) {
let bookShort = new BookShort()
bookShort.book_id = $(item).find('a:first')[0].attribs.href;
const img = $(item).find('img:first')[0];
bookShort.book_name = img.attribs.alt
bookShort.book_pic = img.attribs.src
bookShort.book_remarks = $(item).find('span:first')[0].children[0].data.trim();
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let bookDetail = new BookDetail()
bookDetail.book_name = $('[property$=book_name]')[0].attribs.content
bookDetail.book_year = $('[property$=update_time]')[0].attribs.content
bookDetail.book_director = $('[property$=author]')[0].attribs.content
bookDetail.book_content = $('[property$=description]')[0].attribs.content
bookDetail.book_pic = $($("[class=\"cover\"]")).find("img")[0].attribs.src
bookDetail.book_id = id
let playBook = {}
if (id !== undefined) {
$ = await this.getHtml(this.siteUrl + id + `list.html`);
let urls = [];
const links = $('dl>dd>a[href*="/html/"]');
for (const l of links) {
const name = $(l).text().trim();
const link = l.attribs.href;
urls.push(name + '$' + link);
}
playBook["最新章节"] = urls.slice(-10).join('#');
playBook["目录"] = urls.join('#');
}
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
for (const a of $('div.nav > ul > li > a[href!="/"]')) {
this.classes.push({
type_id: a.attribs.href.replace(/\//g, ''), type_name: a.children[0].data.trim(), tline: 2,
});
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + `/${tid}/${pg}.html`);
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
try {
let content = '';
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += $('#chaptercontent')
.html()
.replace(/<br>|请收藏.*?<\/p>/g, '\n')
.trim();
id = $('a.Readpage_down')[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content":content + '\n\n'}
} catch (e) {
this.playUrl = {"content":""}
}
}
async search(wd, quick) {
const cook = await req(`${this.siteUrl}/user/hm.html?q=${encodeURIComponent(wd)}`, {
headers: {
accept: 'application/json',
'User-Agent': Utils.MOBILEUA,
Referer: `${this.siteUrl}/s?q=${encodeURIComponent(wd)}`,
},
});
const set_cookie = _.isArray(cook.headers['set-cookie']) ? cook.headers['set-cookie'].join(';;;') : cook.headers['set-cookie'];
const cks = set_cookie.split(';;;');
const cookie = {};
for (const c of cks) {
const tmp = c.trim();
const idx = tmp.indexOf('=');
const k = tmp.substr(0, idx);
cookie[k] = tmp.substr(idx + 1, tmp.indexOf(';') - idx - 1);
}
const resp = await req(`${this.siteUrl}/user/search.html?q=${encodeURIComponent(wd)}&so=undefined`, {
headers: {
accept: 'application/json',
'User-Agent': Utils.MOBILEUA,
cookie: 'hm=' + cookie['hm'],
Referer: `${this.siteUrl}/s?q=${encodeURIComponent(wd)}`,
},
});
let data = JSON.parse(resp.content);
let books = [];
for (const book of data) {
books.push({
book_id: book["url_list"],
book_name: book["articlename"],
book_pic: book["url_img"],
book_remarks: book["author"],
});
}
return {
tline: 2, list: books,
};
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'img') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + url)
let bookDetail = await this.parseVodDetailFromDoc($)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new BQQSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+333
View File
@@ -0,0 +1,333 @@
/*
* @File : changzhang.js
* @Author : jade
* @Date : 2024/2/2 16:02
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import { aliName, detailContent,initCloud,playContent, quarkName } from "../lib/cloud.js";
function cryptJs(text, key, iv, type) {
let key_value = Crypto.enc.Utf8.parse(key || 'PBfAUnTdMjNDe6pL');
let iv_value = Crypto.enc.Utf8.parse(iv || 'sENS6bVbwSfvnXrj');
let content
if (type) {
content = Crypto.AES.encrypt(text, key_value, {
iv: iv_value, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7
})
} else {
content = Crypto.AES.decrypt(text, key_value, {
iv: iv_value, padding: Crypto.pad.Pkcs7
}).toString(Crypto.enc.Utf8)
}
return content
}
class ChangZhangSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.czys.pro"
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj);
}
getName() {
return "🏭️┃厂长直连┃🏭️"
}
getAppName() {
return "厂长直连"
}
getJSName() {
return "changzhang"
}
getType() {
return 3
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
let response = await this.fetch(url, null, headers,false,true);
let html = response["content"]
if (!_.isEmpty(html) && html.indexOf("人机验证")===-1) {
return load(html)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
getSearchHeader() {
return {
"Cookie": "cf_clearance=otYZbHg1safCIxkCtZfy9DPKbf1Gs_zUskkVDc0MVKM-1707026063-1-ATOpKnTLv9+pv171YE/rzxN/nmvGN9Mucx7vpwp0kW2vZb/cbtz5e2md2/ym7EE+9dT7pPBV+kQOg9vJx2v8cks=;myannoun=1;PHPSESSID=73386nobqugs7r3pb2ljcsp5q4",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/100.0.4896.77 Mobile/15E148 Safari/604.1",
"Connection":"keep-alive",
"Host":"www.czzy55.com"
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort()
let imgElement = $($(element).find("a")).find("img")[0]
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_pic = imgElement.attribs["data-original"]
vodShort.vod_remarks = $($($(element).find("[class='hdinfo']")).find("span")).text()
vodShort.vod_id = $(element).find("a")[0].attribs.href
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let aList = $($("[class=\"mi_cont\"]").find("ul")).find("li")
for (const a of aList) {
vod_list.push(this.parseVodShortFromElement($, a))
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let aList = $($("[class=\"mi_cont \"]").find("ul")).find("li")
for (const a of aList) {
vod_list.push(this.parseVodShortFromElement($, a))
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let nodeElement = $("[class='dyxingq']")
vodDetail.vod_pic = $(nodeElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(nodeElement).find("h1")[0]).text()
vodDetail.vod_content = $($($("[class='yp_context']")).find("p")).text()
let infoArray = $(nodeElement).find("[class='moviedteail_list']").find("li")
let x = $(infoArray).text()
for (const info of infoArray) {
let content = $(info).text()
if (content.indexOf("类型") > -1) {
vodDetail.type_name = content.replaceAll("类型", "").replaceAll("", "")
} else if (content.indexOf("年份") > -1) {
vodDetail.vod_year = content.replaceAll("年份", "").replaceAll("", "")
} else if (content.indexOf("地区") > -1) {
vodDetail.vod_area = content.replaceAll("地区", "").replaceAll("", "")
} else if (content.indexOf("豆瓣") > -1) {
vodDetail.vod_remarks = content.replaceAll("豆瓣", "").replaceAll("", "")
} else if (content.indexOf("主演") > -1) {
vodDetail.vod_actor = content.replaceAll("主演", "").replaceAll("", "")
} else if (content.indexOf("导演") > -1) {
vodDetail.vod_director = content.replaceAll("导演", "").replaceAll("", "")
} else if (content.indexOf("剧情") > -1) {
vodDetail.vod_content = content.replaceAll("剧情", "").replaceAll("", "")
}
}
let vod_play_from_list = ["厂长资源"]
let vodPlayList = $("[class='paly_list_btn']")
let vod_play_list = []
for (const v1 of vodPlayList) {
let vodItems = []
let aList = $(v1).find("a")
for (const tA of aList) {
let episodeUrl = tA.attribs.href
let episodeName = $(tA).text().replaceAll("立即播放  (", "").replaceAll(")", "")
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
let valify_formt_list = ["磁力链接", aliName]
let otherPlayList = $("[class=\"ypbt_down_list\"]").find("li")
let playVod = {}
for (const otherPlay of otherPlayList) {
let form_name = $(otherPlay).text()
let is_valify = false
for (const valify_format_name of valify_formt_list) {
if (form_name.indexOf(valify_format_name) > -1) {
is_valify = true
if (form_name.indexOf(aliName) === -1) {
vod_play_from_list.push(valify_format_name)
}
}
}
if (is_valify) {
let vodItems = []
for (const ciliPlayUrl of $(otherPlay).find("a")) {
let episodeUrl = ciliPlayUrl.attribs.href
if ($(otherPlay).text().indexOf(aliName)) {
playVod = await detailContent([episodeUrl])
} else {
let episodeName = Utils.getStrByRegex(/\[(.*?)]/, $(ciliPlayUrl).text())
vodItems.push(episodeName + "$" + episodeUrl)
playVod["磁力链接"] = (vodItems.join("#"))
}
}
}
}
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
const items = $('div.search_list > ul > li');
return _.map(items, (item) => {
const img = $(item).find('img:first')[0];
const a = $(item).find('a:first')[0];
const hdinfo = $($(item).find('div.hdinfo')[0]).text().trim();
const jidi = $($(item).find('div.jidi')[0]).text().trim();
return {
vod_id: a.attribs.href,
vod_name: img.attribs.alt,
vod_pic: img.attribs['data-original'],
vod_remarks: jidi || hdinfo || '',
};
})
}
async setClasses() {
const $ = await this.getHtml(this.siteUrl + '/movie_bt');
const series = $('div#beautiful-taxonomy-filters-tax-movie_bt_series > a[cat-url*=movie_bt_series]');
const tags = $('div#beautiful-taxonomy-filters-tax-movie_bt_tags > a');
let tag = {
key: 'tag', name: '类型', value: _.map(tags, (n) => {
let v = n.attribs['cat-url'] || '';
v = v.substring(v.lastIndexOf('/') + 1);
return {n: n.children[0].data, v: v};
}),
};
tag['init'] = tag.value[0].v;
let classes = _.map(series, (s) => {
let typeId = s.attribs['cat-url'];
typeId = typeId.substring(typeId.lastIndexOf('/') + 1);
this.filterObj[typeId] = [tag];
return {
type_id: typeId, type_name: s.children[0].data,
};
});
const sortName = ['电影', '电视剧', '国产剧', '美剧', '韩剧', '日剧', '海外剧(其他)', '华语电影', '印度电影', '日本电影', '欧美电影', '韩国电影', '动画', '俄罗斯电影', '加拿大电影'];
let sort_classes = _.sortBy(classes, (c) => {
const index = sortName.indexOf(c.type_name);
return index === -1 ? sortName.length : index;
});
for (const sort_class of sort_classes){
let type_name = sort_class["type_name"]
if (type_name!=="会员专区" && type_name !== "站长推荐"){
this.classes.push(sort_class)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0) pg = 1;
const tag = extend.tag || '';
const link = this.siteUrl + '/movie_bt' + (tag.length > 0 ? `/movie_bt_tags/${tag}` : '') + '/movie_bt_series/' + tid + (pg > 1 ? `/page/${pg}` : '');
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
const $ = await this.getHtml(this.siteUrl + '/xssearch?q=' + wd,this.getSearchHeader());
let html = $.html()
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf(aliName) > -1 || flag.indexOf(quarkName) > -1) {
this.playUrl = await playContent(flag, id, flags)
this.result.setHeader(getHeaders(flag))
} else {
if (id.indexOf("magnet") > -1) {
this.playUrl = id
} else {
let $ = await this.getHtml(id)
const iframe = $('body iframe[src*=https]');
if (iframe.length > 0) {
const iframeHtml = (await req(iframe[0].attribs.src, {
headers: {
Referer: id, 'User-Agent': Utils.CHROME,
},
})).content;
let player = Utils.getStrByRegex(/var player = "(.*?)"/, iframeHtml)
let rand = Utils.getStrByRegex(/var rand = "(.*?)"/, iframeHtml)
let content = JSON.parse(cryptJs(player, "VFBTzdujpR9FWBhe", rand))
this.playUrl = content["url"]
} else {
const js = $('script:contains(window.wp_nonce)').html();
const group = js.match(/(var.*)eval\((\w*\(\w*\))\)/);
const md5 = Crypto;
const result = eval(group[1] + group[2]);
this.playUrl = result.match(/url:.*?['"](.*?)['"]/)[1];
}
}
}
}
}
let spider = new ChangZhangSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+191
View File
@@ -0,0 +1,191 @@
/*
* @File : ciliduo.js
* @Author : jade
* @Date : 2024/3/1 13:26
* @Email : [email protected]
* @Software : Samples
* @Desc : 磁力多
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class CiliDuoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://of.cilido.top"
this.apiUrl = ""
this.vodShortObj = {}
}
getName() {
return "🔞┃磁力多BT┃🔞"
}
getAppName() {
return "磁力多BT"
}
getJSName() {
return "ciliduo"
}
getType() {
return 3
}
getProxy(src) {
return Utils.base64Decode(src)
}
async home(filter) {
try {
await this.jadeLog.info("正在解析首页类别", true)
let $ = await this.getHtml()
let proxy_src = Utils.getStrByRegex(/var proxy = atob\('(.*?)'\)/, $.html())
this.apiUrl = this.getProxy(proxy_src)
let params = `/?host=${Utils.getHost(this.siteUrl).split("://").slice(-1)[0]}&v=1`
let homeContent = await this.fetch(this.apiUrl, params, this.getHeader())
return await this.parseVodShortListFromDoc(load(homeContent))
} catch (e) {
await this.jadeLog.error(`首页解析失败,失败原因为:${e}`)
}
}
async parseVodShortListFromDoc($) {
let rootElemet = $("[class=\"htab\"]")
let navElements = rootElemet.find("a")
let vodElements = $("[class=\"hotwords\"]").find("ul")
for (let i = 0; i < navElements.length; i++) {
let navElement = navElements[i]
if (i !== navElements.length - 1) {
let type_name = $(navElement).text()
if (type_name === "热门") {
type_name = "最近更新"
}
this.classes.push(this.getTypeDic(type_name, type_name))
let vodElement = vodElements[i]
let vod_list = []
for (const vodShorElement of $(vodElement).find("a")) {
let vodShort = new VodShort()
vodShort.vod_id = vodShorElement.attribs.href
vodShort.vod_name = $(vodShorElement).html()
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vod_list.push(vodShort)
}
this.vodShortObj[type_name] = vod_list
}
}
return this.result.home(this.classes, [], this.filterObj)
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"ssbox\"]")
for (const vodElement of vodElements.slice(0, -1)) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = $($(vodElement).find("a")[0]).text()
vodShort.vod_remarks = $($(vodElement).find("span")[0]).text()
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let html = $.html()
let vodDetail = new VodDetail()
vodDetail.vod_name = $($("[class=\"bt_title\"]")).text()
vodDetail.vod_pic = Utils.RESOURCEURL + "/resources/cili.jpg"
vodDetail.vod_remarks = Utils.getStrByRegex(/<br>收录时间:<span>(.*?)<\/span>/, $.html())
vodDetail.vod_content = "下载速度:" + Utils.getStrByRegex(/下载速度:<span>(.*?)<\/span>/, $.html())
vodDetail.vod_play_from = ["磁力连接"].join("$$$")
let vodItems = []
let contentElement = $("[class=\"content\"]").find("span")[0]
let episodeUrl = contentElement.attribs.href;
let episodeName = contentElement.attribs.title;
vodItems.push(episodeName + "$" + episodeUrl);
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setHomeVod() {
this.homeVodList = this.vodShortObj["最近更新"]
}
async setCategory(tid, pg, filter, extend) {
this.vodList = this.vodShortObj[tid]
}
async setDetail(id) {
if (id.indexOf("search") > -1) {
let content = await this.fetch(this.apiUrl + id, null, this.getHeader())
let vod_list = await this.parseVodShortListFromDocBySearch(load(content))
id = vod_list[0].vod_id
}
await this.jadeLog.debug(id)
let detailUrl = this.apiUrl + id
let detailContent = await this.fetch(detailUrl, null, this.getHeader())
this.vodDetail = await this.parseVodDetailFromDoc(load(detailContent))
}
async setSearch(wd, quick) {
let searchUrl = this.apiUrl + `search?word=${wd}`
let content = await this.fetch(searchUrl, null, this.getHeader())
this.vodList = await this.parseVodShortListFromDocBySearch(load(content))
}
}
let spider = new CiliDuoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+253
View File
@@ -0,0 +1,253 @@
/*
* @File : cilixiong.js
* @Author : jade
* @Date : 2024/4/13 14:52
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js"
class CiliXiongSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.cilixiong.com"
this.cateObj = {"/movie/": "1", "/drama/": "2"}
}
getAppName() {
return "磁力熊"
}
getName() {
return "🐻┃磁力熊┃🐻"
}
getJSName() {
return "cilixiong"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0\"]").find("li")
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
if (type_name !== "首页" && type_name !== "榜单" && type_name !== "留言") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let extend_list = []
let filerElements = $("[class=\"nav small\"]")
let i = 1
for (const filetElement of filerElements) {
let extend_name = $($(filetElement).find("li")[0]).text().replaceAll("", "")
let extend_dic = {"key": (i).toString(), "name": extend_name, "value": []}
for (const typeElement of $(filetElement).find("li").slice(1)) {
let element = $(typeElement).find("a")[0]
let type_id = element.attribs.href.split("-")[i]
extend_dic["value"].push({"n": $(element).text(), "v": type_id})
}
i = i + 1
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"col\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_pic = Utils.getStrByRegex(/background-image: url\('(.*?)'\)/, $(vodElement).find("[class=\"card-img\"]")[0].attribs["style"])
vodShort.vod_name = $($(vodElement).find("h2")).text()
let remarks = $($(vodElement).find("[class=\"rank bg-success p-1\"]")).text()
vodShort.vod_remarks = "评分:" + remarks
if (remarks !== "AD") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"card card-cover h-100 overflow-hidden text-bg-dark rounded-4 shadow-lg position-relative\"]")
for (const vodElement of vodElements){
let vodShort= new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = $($(vodElement).find("[class=\"pt-5 lh-1 pb-2 h4\"]")).text()
vodShort.vod_pic = Utils.getStrByRegex(/background-image: url\('(.*?)'\)/,$(vodElement).find("[class=\"card-img\"]")[0].attribs.style)
vodShort.vod_remarks = "评分:" + $($(vodElement).find("[class=\"rank bg-success p-1\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodDetailElement = $("[class=\"row row-cols-1 row-cols-lg-3 align-items-stretch g-4 p-5 text-white\"]")
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(vodDetailElement).find("h1")).text()
let vodContentElements = $(vodDetailElement).find("[class=\"mb-2\"]").slice(1)
for (const contentElement of vodContentElements) {
let name = $(contentElement).text()
if (name.indexOf("豆瓣评分") > -1) {
vodDetail.vod_remarks = name
}
if (name.indexOf("类型") > -1) {
vodDetail.type_name = name.replaceAll("", "").replace("类型", "").replaceAll(":", "")
}
if (name.indexOf("上映地区") > -1) {
vodDetail.vod_area = name.replaceAll("", "").replace("上映地区", "").replaceAll(":", "")
}
if (name.indexOf("主演") > -1) {
vodDetail.vod_actor = name.replaceAll("", "").replace("主演", "").replaceAll(":", "")
}
if (name.indexOf("上映日期") > -1){
vodDetail.vod_year = name.replaceAll("", "").replace("上映日期", "").replaceAll(":", "")
}
}
vodDetail.vod_content = $($(vodDetailElement).find("[class=\"mv_card_box\"]")).text()
let playerMap = {}
let emebedVideoElements = $("[class=\"row col-md-12 embed_video\"]")
let index = 1
for (const emebedVideoElement of emebedVideoElements){
let vodItems = []
let playUrl = $($(emebedVideoElement).find("iframe"))[0].attribs["src"]
vodItems.push("播放" + "$" + playUrl);
playerMap["在线播放" + index.toString()+ "第一集在线播放预览"] = vodItems.join("#")
index = index + 1
}
let mangetIndex = 1
let mangetElements = $("[class=\"row col-md-12 text-white p-3 pt-1\"]").find("[class=\"container\"]")
for (const mangenment of mangetElements){
let vodItems = []
let playElement = $($(mangenment).find("a"))[0]
let playUrl = playElement.attribs.href
let playName = $(playElement).text()
if (playUrl.startsWith("magnet")){
vodItems.push(playName + "$" + playUrl);
}
if (vodItems.length > 0){
playerMap["磁力链接" + "-" + mangetIndex] = vodItems.join("#")
mangetIndex = mangetIndex + 1
}
}
vodDetail.vod_play_from = Object.keys(playerMap).join("$$$");
vodDetail.vod_play_url = Object.values(playerMap).join("$$$");
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let type = extend["1"] ?? "0"
let area = extend["2"] ?? "0"
let page = parseInt(pg) - 1
let url = this.siteUrl + "/" + this.cateObj[tid] + `-${type}-${area}-${page}.html`
await this.jadeLog.debug(`分类URL:${url}`)
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("在线播放") > -1){
let $ = await this.getHtml(this.siteUrl + id)
this.playUrl = Utils.getStrByRegex(/const source = '(.*?)'/,$.html())
}else{
this.playUrl = id
}
}
async setSearch(wd, quick) {
let params = {"classid":"1,2","show":"title","tempid":"1","keyboard":wd}
let response = await this.post(this.siteUrl + "/e/search/index.php",params,this.getHeader())
let $ = load(response)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new CiliXiongSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+364
View File
@@ -0,0 +1,364 @@
/*
* @File : cntv.js
* @Author : jade
* @Date : 2024/4/25 10:26
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class CNTVSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://tv.cctv.com/m/index.shtml"
this.apiUrl = "https://api.app.cctv.com"
this.liveJsonUrl = "https://gh.con.sh/https://github.com/jadehh/LiveSpider/blob/main/json/live.json"
}
getName() {
return "🤵‍♂️┃中央影视┃🤵‍♂️"
}
getAppName() {
return "中央影视"
}
getJSName() {
return "cntv"
}
getType() {
return 3
}
async spiderInit() {
await super.spiderInit();
this.liveJson = JSON.parse(await this.fetch(this.liveJsonUrl, null, null))
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit()
}
async getFilterByLive(dataList) {
let extend_list = []
let extend_dic = {"key": "live", "name": "直播", "value": []}
for (const data of dataList) {
if (data["appBarTitle"] !== "最近常看") {
extend_dic["value"].push({"n": data["appBarTitle"], "v": data["pageId"]})
}
}
extend_list.push(extend_dic)
return extend_list
}
arrayIsinclude(str, items) {
let isInclude = false
for (const data of items) {
if (str === data["title"]) {
return true
}
}
return isInclude
}
async getFilterByTv(dataList) {
let extend_list = []
for (const data of dataList) {
let add_year_status = false
let extend_dic = {"key": data["classname"], "name": data["title"], "value": []}
for (const extendData of data["items"]) {
if (data["classname"] === "nianfen") {
if (!this.arrayIsinclude("2024", data["items"]) && extendData["title"] !== "全部" && !add_year_status) {
extend_dic["value"].push({"n": "2024", "v": "2024"})
add_year_status = true
}
}
extend_dic["value"].push({"n": extendData["title"], "v": extendData["title"]})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let liveTypeId = "cctvlive"
let liveApi = this.apiUrl + `/api/navigation/iphone/AppStore/7.9.4/${liveTypeId}`
let liveJson = JSON.parse(await this.fetch(liveApi, null, this.getHeader()))
let extend_list = await this.getFilterByLive(liveJson["data"]["templates"])
let defaultLiveId = extend_list[0]["value"][0]["v"]
this.classes.push(this.getTypeDic("直播", defaultLiveId))
this.filterObj[defaultLiveId] = extend_list
let tvApi = "https://cbox.cctv.com/cboxpcvip/online2022/yxg/data1.jsonp?=pk"
let tvContent = await this.fetch(tvApi, null, this.getHeader())
let tvJSon = JSON.parse(tvContent.replaceAll("pk(", "").replaceAll(")", ""))
for (const data of tvJSon["data"]) {
let typeName = data["title"]
this.classes.push(this.getTypeDic(typeName, typeName))
this.filterObj[typeName] = await this.getFilterByTv(data["templates"])
}
}
parseVodShortByJson(items) {
let vod_list = []
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_pic = item["img1"]
if (_.isEmpty(vodShort.vod_pic)) {
vodShort.vod_pic = item["epgHorizontalPic"]
vodShort.vod_id = "live-" + item["epgChnlChar"] + "-" + vodShort.vod_pic
} else {
vodShort.vod_id = "play-" + item["playid"] + "-" + vodShort.vod_pic
vodShort.vod_pic = item["img1"]
}
vodShort.vod_name = item["title"]
vod_list.push(vodShort)
}
return vod_list
}
parseVodShortByTvJson(items) {
let vod_list = []
for (const item of items) {
let vodShort = new VodShort()
//关键是如何获取GUID 2d3224585904496ea837f682da0c4aa6
vodShort.vod_id = "url-" + item["vsetid"]
vodShort.vod_name = item["title"]
vodShort.vod_pic = item["image"]
vodShort.vod_remarks = item["sc"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(objList) {
let vod_list = []
let top_status = false
for (const data of objList) {
if (data["title"] === "今日热点") {
top_status = true
} else if (!_.isEmpty(data["title"])) {
if (top_status) {
break
}
}
if (top_status) {
vod_list = [...vod_list, ...this.parseVodShortByJson(data["items"])]
}
}
return vod_list
}
async getLiveUrl(channel_id, obj) {
let liveApiUrl = `https://vdn.live.cntv.cn/api2/live.do?channel=pd://cctv_p2p_hd${channel_id}&client=iosapp`
let liveResponse = await req(liveApiUrl, {"headers": this.getHeader()})
let liveJson = JSON.parse(liveResponse["content"])
let playList = {}
let channelName = obj["channelName"].split(" ")[0].replaceAll("-", "").toLowerCase()
let liveUrl = this.liveJson[channelName] ?? liveJson["hls_url"]["hls2"]
playList["直播"] = ["点击播放$" + liveUrl]
await this.jadeLog.info(`liveJson:${JSON.stringify(liveJson)}`)
let vod_items = []
if (this.liveJson[channelName] !== undefined) {
} else {
for (const data of obj["program"]) {
let episodeName = data["showTime"] + "-" + data["t"]
let episodeUrl = liveUrl + `?begintimeabs=${data["st"] * 1000}&endtimeabs=${data["et"] * 1000}`
vod_items.push(episodeName + "$" + episodeUrl)
}
}
if (vod_items.length > 0){
playList["点播"] = vod_items.join("#")
}
return playList
}
async getVideoUrl(guid) {
return {"中央影视": ['点击播放' + '$' + guid].join("#")}
}
async parseVodDetailfromJson(id, obj, pic) {
let vodDetail = new VodDetail()
let $;
let guid;
if (obj["url"] !== undefined) {
vodDetail.vod_name = obj["title"]
vodDetail.vod_pic = obj["img"]
vodDetail.type_name = obj["tags"]
vodDetail.vod_year = obj["time"]
vodDetail.vod_content = obj["vset_brief"]
vodDetail.vod_director = obj["vset_title"]
$ = await this.getHtml(obj["url"])
} else {
if (_.isEmpty(obj["lvUrl"])) {
vodDetail.vod_name = obj["channelName"]
vodDetail.vod_pic = pic
} else {
$ = await this.getHtml(obj["lvUrl"])
vodDetail.vod_name = $('[property$=title]')[0].attribs.content
vodDetail.vod_content = $('[property$=description]')[0].attribs.content
let pic = $('[property$=image]')[0].attribs.content
if (!pic.startsWith("http")) {
pic = "https:" + pic
}
vodDetail.vod_pic = pic
}
}
if (!_.isEmpty($)) {
guid = Utils.getStrByRegex(/var guid = "(.*?)"/, $.html())
}
let playlist
if (_.isEmpty(guid) && obj["url"] === undefined) {
playlist = await this.getLiveUrl(id, obj)
} else {
playlist = await this.getVideoUrl(guid)
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async parseVodDetailFromJsonByTv(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["videoSetInfo"]["title"]
vodDetail.type_name = obj["videoSetInfo"]["sc"]
vodDetail.vod_pic = obj["videoSetInfo"]["image"]
vodDetail.vod_content = obj["videoSetInfo"]["brief"]
vodDetail.vod_area = obj["videoSetInfo"]["area"]
let playlist = {}
let vodItems = []
for (const data of obj["videoRoughCut"]) {
let title = data["title"].split("》").slice(-1)[0]
vodItems.push(title + "$" + data["guid"])
}
playlist["中央影视"] = vodItems.join("#")
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setHomeVod() {
let resJson = JSON.parse(await this.fetch(this.apiUrl + "/api/page/iphone/HandheldApplicationSink/7.0.0/158", null, this.getHeader()))
this.homeVodList = await this.parseVodShortListFromJson(resJson["data"]["templates"])
}
getExtendValue(extend, key) {
if (extend[key] !== undefined && extend[key] !== "全部") {
return extend[key]
}
return ""
}
async setCategory(tid, pg, filter, extend) {
if (Utils.isNumeric(tid)) {
tid = extend["live"] ?? tid
let url = this.apiUrl + `/api/page/iphone/HandheldApplicationSink/7.0.0/${tid}`
let response = JSON.parse(await this.fetch(url, null, this.getHeader()))
this.vodList = this.parseVodShortByJson(response["data"]["templates"][0]["items"])
} else {
let letter = this.getExtendValue(extend, "zimu")
let area = this.getExtendValue(extend, "diqu")
let type = this.getExtendValue(extend, "leixing")
let year = this.getExtendValue(extend, "nianfen")
const limit = 12
let url = "https://api.cntv.cn" + `/newVideoset/getCboxVideoAlbumList`
let params = {
"channelid": "",
"sc": type,
"fc": tid,
"p": pg,
"n": limit,
"fl": letter,
"area": area,
"year": year,
"serviceId": "cbox"
}
let resJson = JSON.parse(await this.fetch(url, params, this.getHeader()))
this.vodList = this.parseVodShortByTvJson(resJson["data"]["list"])
}
}
async setDetail(id) {
//区分直播还是点播
let aList = id.split("-")
let playType = aList[0]
let pic = aList[2]
id = aList[1]
if (playType === "play") {
let resJson = JSON.parse(await this.fetch(`https://api.cntv.cn/video/videoinfoByGuid?serviceId=cbox&guid=${id}`, null, this.getHeader()))
this.vodDetail = await this.parseVodDetailfromJson(id, resJson, pic)
} else if (playType === "url") {
let url = `https://api.app.cctv.com/api/getVideoPageDetail?videoSetContentId=${id}`
let resJson = JSON.parse(await this.fetch(url, null, this.getHeader()))
this.vodDetail = await this.parseVodDetailFromJsonByTv(resJson["data"])
} else {
let content = (await this.fetch(`https://api.cntv.cn/epg/epginfo3?serviceId=shiyi&c=${id}&cb=LiveTileShow.prototype.getEpg`, null, this.getHeader())).replaceAll("LiveTileShow.prototype.getEpg(", "").replaceAll(");", "")
this.vodDetail = await this.parseVodDetailfromJson(id, JSON.parse(content)[id], pic)
}
}
async setSearch(wd, quick, pg) {
}
async setPlay(flag, id, flags) {
if (id.startsWith("http")) {
this.playUrl = id
let headers = this.getHeader()
headers["Referer"] = "https://tv.cctv.com/"
this.result.header = headers
} else {
this.playUrl = 'https://hls.cntv.myhwcdn.cn/asp/hls/2000/0303000a/3/default/' + id + '/2000.m3u8'
}
}
}
let spider = new CNTVSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, CNTVSpider}
+233
View File
@@ -0,0 +1,233 @@
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
import {Crypto} from "../lib/cat.js";
class CopyManhuaSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.copymanga.tv';
}
getName() {
return "🧑‍🎨|拷贝漫画|🧑‍🎨"
}
getAppName() {
return "拷贝漫画"
}
getJSName() {
return "copymanga"
}
getType() {
return 20
}
async setClasses() {
this.classes.push(this.getTypeDic("全部", "c1"))
}
async getFilter($) {
let region = {
key: 'region', name: '地區', init: '',
};
let regionValues = [];
regionValues.push({n: '全部', v: ''});
regionValues.push({n: '日漫', v: '0'});
regionValues.push({n: '韓漫', v: '1'});
regionValues.push({n: '美漫', v: '2'});
region['value'] = regionValues;
let ordering = {
key: 'ordering', name: '排序', init: '-datetime_updated',
};
let orderingValues = [];
orderingValues.push({n: '更新時間↓', v: '-datetime_updated'});
orderingValues.push({n: '更新時間↑', v: 'datetime_updated'});
orderingValues.push({n: '熱門↓', v: '-popular'});
orderingValues.push({n: '熱門↑', v: 'popular'});
ordering['value'] = orderingValues;
let status = {
key: 'sort', name: '狀態', init: '',
};
let statusValues = [];
statusValues.push({n: '全部', v: ''});
statusValues.push({n: '連載中', v: '0'});
statusValues.push({n: '已完結', v: '1'});
statusValues.push({n: '短篇', v: '2'});
status['value'] = statusValues;
let extend_list = []
let themeValues = [{n: '全部', v: ''}];
for (const a of $('div.classify-right>a[href*="theme="]')) {
themeValues.push({
n: $(a).text().trim(), v: a.attribs.href.match(/.*?theme=(.*)&/)[1],
});
}
extend_list.push({
key: 'theme', name: '', init: '', wrap: 1, value: themeValues,
});
extend_list.push(region);
extend_list.push(status);
extend_list.push(ordering);
return extend_list
}
async setFilterObj() {
let $ = await this.getHtml(this.siteUrl + '/comics');
this.filterObj['c1'] = await this.getFilter($);
}
parseVodShortFromJson(obj) {
let bookShort = new BookShort()
bookShort.book_id = obj["path_word"]
bookShort.book_name = obj["name"]
bookShort.book_pic = obj["cover"]
bookShort.book_remarks = obj.author ? obj.author[0].name : '';
return bookShort
}
async parseVodShortListFromDocByCategory($) {
const list = eval($('div[class="row exemptComic-box"]')[0].attribs.list);
let books = [];
for (const book of list) {
let bookShort = this.parseVodShortFromJson(book)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDoc($) {
let vodElements = $("[class=\"container edit\"]").find("[class=\"col-auto\"]")
let books = []
for (const vodElement of vodElements) {
let bookShort = new BookShort()
bookShort.book_id = $(vodElement).find("a")[0].attribs.href.split("/comic/")[1]
bookShort.book_pic = $(vodElement).find("img")[0].attribs["data-src"]
bookShort.book_name = $($(vodElement).find("p")).text()
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let bookDetail = new BookDetail()
bookDetail.book_pic = $("[class=\"comicParticulars-left-img loadingIcon\"]").find("img")[0].attribs["data-src"]
bookDetail.book_name = $('h6').text().trim()
bookDetail.book_director = $('span.comicParticulars-right-txt>a[href*="/author/"]')
.map((_, a) => $(a).text().trim())
.get()
.join('/')
bookDetail.book_content = $('p.intro').text().trim()
let data = JSON.parse(await this.fetch(this.siteUrl + `/comicdetail/${id}/chapters`, null, this.getHeader()))["results"]
let key = Crypto.enc.Utf8.parse('xxxmanga.woo.key');
let iv = Crypto.enc.Utf8.parse(data.substr(0, 16));
let src = Crypto.enc.Hex.parse(data.substr(16));
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
const groups = JSON.parse(dst).groups;
let urls = groups.default["chapters"]
.map((c) => {
return c.name + '$' + id + '|' + c.id;
})
.join('#');
bookDetail.volumes = '默認';
bookDetail.urls = urls;
bookDetail.book_id = id
return bookDetail
}
async parseVodShortListFromJson(obj) {
const books = [];
for (const book of obj) {
books.push(this.parseVodShortFromJson(book))
}
return books
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let page = pg || 1;
if (page === 0) page = 1;
let link = this.siteUrl + `/comics?theme=${extend.theme || ''}&region=${extend.region || ''}&status=${extend.status || ''}&ordering=${extend.ordering || '-datetime_updated'}`;
if (page > 1) {
link += '&offset=' + (page - 1) * 50 + '&limit=50';
}
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `/comic/${id}`)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setPlay(flag, id, flags) {
let info = id.split('|');
let $ = await this.getHtml(this.siteUrl + `/comic/${info[0]}/chapter/${info[1]}`);
const data = $('div.imageData')[0].attribs["contentkey"];
let key = Crypto.enc.Utf8.parse('xxxmanga.woo.key');
let iv = Crypto.enc.Utf8.parse(data.substr(0, 16));
let src = Crypto.enc.Hex.parse(data.substr(16));
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
const list = JSON.parse(dst);
let content = [];
for (let index = 0; index < list.length; index++) {
const element = list[index];
content[index] = element.url;
}
this.playUrl = {
"content": content,
}
}
async setSearch(wd, quick) {
let page = 1
const link = `${this.siteUrl}/api/kb/web/searcha/comics?offset=${page > 1 ? ((page - 1) * 12).toString() : ''}&platform=2&limit=12&q=${wd}&q_type=`;
let list = JSON.parse(await this.fetch(link, null, this.getHeader()))["results"]["list"]
this.vodList = await this.parseVodShortListFromJson(list)
}
}
let spider = new CopyManhuaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+215
View File
@@ -0,0 +1,215 @@
/*
* @File : dj0898_book_open.js.js
* @Author : jade
* @Date : 2023/12/22 17:00
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_} from '../lib/cat.js';
import {Spider} from "./spider.js";
import {BookShort} from "../lib/book.js";
class DJ0898Spider extends Spider {
constructor() {
super();
this.siteUrl = "http://m.dj0898.com";
}
getName() {
return "🎵┃世纪DJ音乐网┃🎵"
}
getAppName() {
return "世纪DJ音乐网"
}
getJSName() {
return "dj0898_book_open"
}
getType() {
return 10
}
async parseVodShortListFromDoc($) {
let books = []
const list = $("ul.djddv_djList > li");
for (const it of list) {
let bookShort = new BookShort();
const a = $(it).find("a")[1];
bookShort.book_id = a.attribs.href
bookShort.book_pic = $(it).find("img:first")[0].attribs.src;
const tt = $(it).find("strong:first")[0];
bookShort.book_name = tt.children[0].data
bookShort.book_remarks = "🎵" + $(it).find("font")[5].children[0].data || ""
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
const list = $("ul.djddv_djList > li");
let videos = _.map(list, (it) => {
const a = $(it).find("a")[1];
const img = $(it).find("img:first")[0];
const tt = $(it).find("strong:first")[0];
const remarks = $(it).find("font")[5];
return {
book_id: a.attribs.href,
book_name: tt.children[0].data,
book_pic: img.attribs["src"],
book_remarks: "🎵" + remarks.children[0].data || "",
};
});
const hasMore = $("ul.page_link > li > a:contains(\u00a0)").length > 0;
this.page = hasMore ? parseInt(this.page) + 1 : parseInt(this.page);
return videos
}
async parseVodShortListFromDocBySearch($) {
const list = $("ul.djddv_djList > li");
return _.map(list, (it) => {
const a = $(it).find("a")[1];
const img = $(it).find("img:first")[0];
const tt = $(it).find("strong:first")[0];
const remarks = $(it).find("font:first")[0];
return {
book_id: a.attribs.href,
book_name: tt.children[0].data,
book_pic: img.attribs["src"],
book_remarks: "🎵" + remarks.children[0].data || "",
};
})
}
async parseVodDetailFromDoc(id) {
const vod = {
book_id: id,
audio: 1,
type_name: '',
book_year: '',
book_area: '',
book_remarks: '',
book_actor: '',
book_director: '',
book_content: '',
};
const playlist = ["点击播放" + "$" + vod.book_id];
vod.volumes = "世纪DJ音乐网";
vod.urls = playlist.join("#");
return vod
}
async setClasses() {
this.classes = [{type_id: 1, type_name: "🎧串烧舞曲"}, {type_id: 2, type_name: "🎧外文舞曲"}, {
type_id: 3,
type_name: "🎧早场暖场"
}, {type_id: 4, type_name: "🎧中文舞曲"}, {type_id: 5, type_name: "🎧其他舞曲"}, {
type_id: 6,
type_name: "🎧国外电音"
}, {type_id: 8, type_name: "🎧慢歌连版"}, {type_id: 9, type_name: "🎧酒吧潮歌"}, {
type_id: 10,
type_name: "🎧中文串烧"
}, {type_id: 11, type_name: "🎧外文串烧"}, {type_id: 12, type_name: "🎧中外串烧"}, {
type_id: 13,
type_name: "🎧车载串烧"
}, {type_id: 14, type_name: "🎧越鼓串烧"}, {type_id: 40, type_name: "🎧3D/环绕"}, {
type_id: 45,
type_name: "🎧口水旋律"
}, {type_id: 46, type_name: "🎧精品收藏"}, {type_id: 47, type_name: "🎧开场舞曲"}, {
type_id: 48,
type_name: "🎧印度舞曲"
}, {type_id: 49, type_name: "🎧编排套曲"}, {type_id: 20, type_name: "🎧DuTch"}, {
type_id: 21,
type_name: "🎧Mash up"
}, {type_id: 22, type_name: "🎧ClubHouse"}, {type_id: 23, type_name: "🎧ElectroHouse"}, {
type_id: 24,
type_name: "🎧越南鼓Dj"
}, {type_id: 30, type_name: "🎧Funky"}, {type_id: 31, type_name: "🎧Reggae"}, {
type_id: 32,
type_name: "🎧Rnb"
}, {type_id: 33, type_name: "🎧Hip Hop"}, {type_id: 34, type_name: "🎧Dubstep"}, {
type_id: 8017,
type_name: "🎧Hardstyle"
}, {type_id: 8018, type_name: "🎧Hands Up"}];
}
async setFilterObj() {
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl + "/dance/lists/id/10/1")
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
const link = this.siteUrl + "/dance/lists/id/" + tid + "/" + pg;
let $ = await this.getHtml(link)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailFromDoc(id);
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(id)
const audio = $("body audio[src*=http]");
this.playUrl = audio[0].attribs.src
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + "/index.php/dance/so/key?key=" + wd + "&cid=0&p=1")
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new DJ0898Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+246
View File
@@ -0,0 +1,246 @@
/*
* @File : doll.js
* @Author : jade
* @Date : 2024/1/4 14:15
* @Email : [email protected]
* @Software : Samples
* @Desc : doll
*/
import {Spider} from "./spider.js";
import {Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class Doll extends Spider {
constructor() {
super();
this.siteUrl = "https://hongkongdollvideo.com"
}
getImgHeader(){
let headers = this.getHeader()
headers["Proxy"] = true
return headers
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getImgHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getImgHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
return super.getHtml(url, true, headers);
}
getName() {
return "🔞┃玩偶姐姐┃🔞"
}
getAppName() {
return "玩偶姐姐"
}
getJSName() {
return "doll"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"row\"]").find("[class=\"video-detail\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
let videoInfoElements = $($(vodElement).find("[class=\"video-info\"]")).find("a")
vodShort.vod_name = videoInfoElements[0].attribs["title"]
vodShort.vod_remarks = $(videoInfoElements[1]).text()
let pic = $(vodElement).find("img")[0].attribs["data-src"]
// if (this.catOpenStatus) {
// vodShort.vod_pic = this.jsBase + Utils.base64Encode(pic)
// } else {
// vodShort.vod_pic = pic
// }
vodShort.vod_pic = pic
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($, key) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"container-fluid\"]")
vodDetail.vod_name = $($(vodElement).find("[class=\"page-title\"]")[0]).text()
vodDetail.vod_remarks = $(vodElement).find("[class=\"tag my-1 text-center\"]")[0].attribs["href"].replaceAll("/", "")
let pic = $(vodElement).find("video")[0].attribs["poster"]
// if (this.catOpenStatus) {
// vodDetail.vod_pic = this.jsBase + Utils.base64Encode(pic)
// } else {
// vodDetail.vod_pic = pic
// }
vodDetail.vod_pic = pic
let html = $.html()
let voteTag = Utils.getStrByRegex(/var voteTag="(.*?)";/g, html)
// let videoInfoStr = Utils.getStrByRegex(/<script type="application\/ld\+json">(.*?)<\/script>/g, html)
// let videoInfo = JSON.parse(videoInfoStr)
//
// try {
// let play_url_1 = await this.fetch(videoInfo["contentUrl"], null, this.getHeader())
// await this.jadeLog.debug(`播放链接为:${play_url_1}`)
// } catch (e) {
// await this.jadeLog.error(e)
// }
voteTag = Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(voteTag))
let code = []
for (let i = 0; i < voteTag.length; i++) {
let k = i % key.length;
code.push(String.fromCharCode(voteTag.charCodeAt(i) ^ key.charCodeAt(k)))
}
let play_url_2 = decodeURIComponent(Crypto.enc.Utf8.stringify(Crypto.enc.Base64.parse(code.join(""))))
vodDetail.vod_play_from = "玩偶姐姐"
vodDetail.vod_play_url = "玩偶姐姐" + "$" + play_url_2
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"list-unstyled topnav-menu d-flex d-lg-block align-items-center justify-content-center flex-fill topnav-menu-left m-0\"]").find("li")
let index = 1
let class_id = index.toString()
this.classes = []
this.classes.push({"type_name": "首页", "type_id": "1"})
this.filterObj[class_id] = []
for (const navElement of navElements) {
let type_list = $(navElement).text().split("\n")
let valueElements = $(navElement).find("a")
let valueList = [{"n": "全部", "v": class_id}]
let type_id = index.toString()
for (const valueElement of valueElements) {
let title = $(valueElement).text().replaceAll("\n", "")
let href = valueElement.attribs["href"]
if (href !== undefined) {
valueList.push({"n": title, "v": href})
}
}
type_list = type_list.filter(element => element !== "");
this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": valueList})
//下面这段是为了切割使用
// let new_value_list = []
// for (let i = 0; i < valueList.length; i++) {
// new_value_list.push(valueList[i])
// if (i % 8 === 0 && i !== 0) {
// this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": new_value_list})
// new_value_list = []
// }
// }
// this.filterObj[class_id].push({"key": type_id, "name": type_list[0], "value": new_value_list})
}
let menuElements = $("[id=\"side-menu\"]").find("li")
for (const menuElement of menuElements) {
let type_id = $(menuElement).find("a")[0].attribs["href"]
if (type_id !== undefined && type_id.indexOf(this.siteUrl) > -1) {
let type_dic = {
"type_name": $(menuElement).text(), "type_id": type_id
}
this.classes.push(type_dic)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (extend["1"] !== undefined) {
if (extend["1"] !== "1") {
tid = extend[1]
}
}
await this.jadeLog.info(`tid = ${tid}`)
let cateUrl = ""
if (tid.indexOf(this.siteUrl) > -1) {
cateUrl = tid + pg.toString() + ".html"
} else {
cateUrl = this.siteUrl
}
this.limit = 36
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
let key = Utils.getStrByRegex(/video\/(\w+).html/, id)
this.vodDetail = await this.parseVodDetailFromDoc($, key)
}
async setPlay(flag, id, flags) {
this.playUrl = id
this.playHeader = {}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + "search/" + encodeURIComponent(wd)
let $ = await this.getHtml(searchUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async proxy(segments, headers) {
return super.proxy(segments, headers);
}
}
let spider = new Doll()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+636
View File
@@ -0,0 +1,636 @@
/*
* @File : nivod.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
import {_, Crypto} from "../lib/cat.js";
class DoubanSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://frodo.douban.com/api/v2'
this.apiKey = "0ac44ae016490db2204ce0a042db2916"
this.UserAgents = ["api-client/1 com.douban.frodo/7.22.0.beta9(231) Android/23 product/Mate 40 vendor/HUAWEI model/Mate 40 brand/HUAWEI rom/android network/wifi platform/AndroidPad", "api-client/1 com.douban.frodo/7.18.0(230) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.1.0(205) Android/29 product/perseus vendor/Xiaomi model/Mi MIX 3 rom/miui6 network/wifi platform/mobile nd/1", "api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
}
getHeader() {
return {
"Host": "frodo.douban.com",
"Connection": "Keep-Alive",
"Referer": "https://servicewechat.com/wx2f9b06c1de1ccfca/84/page-frame.html",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat"
}
}
getSearchHeader() {
let randomNumber = Math.floor(Math.random() * this.UserAgents.length); // 生成一个介于0到9之间的随机整数
return {
'User-Agent': this.UserAgents[randomNumber]
}
}
getName() {
return "🍥┃豆瓣┃🍥"
}
getAppName() {
return "豆瓣"
}
getJSName() {
return "douban"
}
getType() {
return 3
}
async setClasses() {
let classes = [{
"type_name": "热门电影", "type_id": "hot_gaia"
}, {
"type_name": "热播剧集", "type_id": "tv_hot"
}, {
"type_name": "热播综艺", "type_id": "show_hot"
}, {
"type_name": "电影筛选", "type_id": "movie"
}, {
"type_name": "电视筛选", "type_id": "tv"
}, {
"type_name": "电影榜单", "type_id": "rank_list_movie"
}, {
"type_name": "电视剧榜单", "type_id": "rank_list_tv"
}]
for (const class_dic of classes) {
this.classes.push({"type_name": class_dic["type_name"], "type_id": class_dic["type_id"]})
}
}
async setFilterObj() {
this.filterObj = {
"hot_gaia": [{
"key": "sort", "name": "排序", "value": [{
"n": "热度", "v": "recommend"
}, {
"n": "最新", "v": "time"
}, {
"n": "评分", "v": "rank"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": "全部"
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}]
}], "tv_hot": [{
"key": "type", "name": "分类", "value": [{
"n": "综合", "v": "tv_hot"
}, {
"n": "国产剧", "v": "tv_domestic"
}, {
"n": "欧美剧", "v": "tv_american"
}, {
"n": "日剧", "v": "tv_japanese"
}, {
"n": "韩剧", "v": "tv_korean"
}, {
"n": "动画", "v": "tv_animation"
}]
}], "show_hot": [{
"key": "type", "name": "分类", "value": [{
"n": "综合", "v": "show_hot"
}, {
"n": "国内", "v": "show_domestic"
}, {
"n": "国外", "v": "show_foreign"
}]
}], "movie": [{
"key": "类型", "name": "类型", "value": [{
"n": "全部类型", "v": ""
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "爱情", "v": "爱情"
}, {
"n": "动作", "v": "动作"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "动画", "v": "动画"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "犯罪", "v": "犯罪"
}, {
"n": "惊悚", "v": "惊悚"
}, {
"n": "冒险", "v": "冒险"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "历史", "v": "历史"
}, {
"n": "奇幻", "v": "奇幻"
}, {
"n": "恐怖", "v": "恐怖"
}, {
"n": "战争", "v": "战争"
}, {
"n": "传记", "v": "传记"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "武侠", "v": "武侠"
}, {
"n": "情色", "v": "情色"
}, {
"n": "灾难", "v": "灾难"
}, {
"n": "西部", "v": "西部"
}, {
"n": "纪录片", "v": "纪录片"
}, {
"n": "短片", "v": "短片"
}]
}, {
"key": "地区", "name": "地区", "value": [{
"n": "全部地区", "v": ""
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "中国大陆", "v": "中国大陆"
}, {
"n": "美国", "v": "美国"
}, {
"n": "中国香港", "v": "中国香港"
}, {
"n": "中国台湾", "v": "中国台湾"
}, {
"n": "英国", "v": "英国"
}, {
"n": "法国", "v": "法国"
}, {
"n": "德国", "v": "德国"
}, {
"n": "意大利", "v": "意大利"
}, {
"n": "西班牙", "v": "西班牙"
}, {
"n": "印度", "v": "印度"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "俄罗斯", "v": "俄罗斯"
}, {
"n": "加拿大", "v": "加拿大"
}, {
"n": "澳大利亚", "v": "澳大利亚"
}, {
"n": "爱尔兰", "v": "爱尔兰"
}, {
"n": "瑞典", "v": "瑞典"
}, {
"n": "巴西", "v": "巴西"
}, {
"n": "丹麦", "v": "丹麦"
}]
}, {
"key": "sort", "name": "排序", "value": [{
"n": "近期热度", "v": "T"
}, {
"n": "首映时间", "v": "R"
}, {
"n": "高分优先", "v": "S"
}]
}, {
"key": "年代", "name": "年代", "value": [{
"n": "全部年代", "v": ""
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2010年代", "v": "2010年代"
}, {
"n": "2000年代", "v": "2000年代"
}, {
"n": "90年代", "v": "90年代"
}, {
"n": "80年代", "v": "80年代"
}, {
"n": "70年代", "v": "70年代"
}, {
"n": "60年代", "v": "60年代"
}, {
"n": "更早", "v": "更早"
}]
}], "tv": [{
"key": "类型", "name": "类型", "value": [{
"n": "不限", "v": ""
}, {
"n": "电视剧", "v": "电视剧"
}, {
"n": "综艺", "v": "综艺"
}]
}, {
"key": "电视剧形式", "name": "电视剧形式", "value": [{
"n": "不限", "v": ""
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "爱情", "v": "爱情"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "动画", "v": "动画"
}, {
"n": "武侠", "v": "武侠"
}, {
"n": "古装", "v": "古装"
}, {
"n": "家庭", "v": "家庭"
}, {
"n": "犯罪", "v": "犯罪"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "恐怖", "v": "恐怖"
}, {
"n": "历史", "v": "历史"
}, {
"n": "战争", "v": "战争"
}, {
"n": "动作", "v": "动作"
}, {
"n": "冒险", "v": "冒险"
}, {
"n": "传记", "v": "传记"
}, {
"n": "剧情", "v": "剧情"
}, {
"n": "奇幻", "v": "奇幻"
}, {
"n": "惊悚", "v": "惊悚"
}, {
"n": "灾难", "v": "灾难"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "音乐", "v": "音乐"
}]
}, {
"key": "综艺形式", "name": "综艺形式", "value": [{
"n": "不限", "v": ""
}, {
"n": "真人秀", "v": "真人秀"
}, {
"n": "脱口秀", "v": "脱口秀"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "歌舞", "v": "歌舞"
}]
}, {
"key": "地区", "name": "地区", "value": [{
"n": "全部地区", "v": ""
}, {
"n": "华语", "v": "华语"
}, {
"n": "欧美", "v": "欧美"
}, {
"n": "国外", "v": "国外"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "中国大陆", "v": "中国大陆"
}, {
"n": "中国香港", "v": "中国香港"
}, {
"n": "美国", "v": "美国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "中国台湾", "v": "中国台湾"
}, {
"n": "意大利", "v": "意大利"
}, {
"n": "法国", "v": "法国"
}, {
"n": "德国", "v": "德国"
}, {
"n": "西班牙", "v": "西班牙"
}, {
"n": "俄罗斯", "v": "俄罗斯"
}, {
"n": "瑞典", "v": "瑞典"
}, {
"n": "巴西", "v": "巴西"
}, {
"n": "丹麦", "v": "丹麦"
}, {
"n": "印度", "v": "印度"
}, {
"n": "加拿大", "v": "加拿大"
}, {
"n": "爱尔兰", "v": "爱尔兰"
}, {
"n": "澳大利亚", "v": "澳大利亚"
}]
}, {
"key": "sort", "name": "排序", "value": [{
"n": "近期热度", "v": "T"
}, {
"n": "首播时间", "v": "R"
}, {
"n": "高分优先", "v": "S"
}]
}, {
"key": "年代", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2010年代", "v": "2010年代"
}, {
"n": "2000年代", "v": "2000年代"
}, {
"n": "90年代", "v": "90年代"
}, {
"n": "80年代", "v": "80年代"
}, {
"n": "70年代", "v": "70年代"
}, {
"n": "60年代", "v": "60年代"
}, {
"n": "更早", "v": "更早"
}]
}, {
"key": "平台", "name": "平台", "value": [{
"n": "全部", "v": ""
}, {
"n": "腾讯视频", "v": "腾讯视频"
}, {
"n": "爱奇艺", "v": "爱奇艺"
}, {
"n": "优酷", "v": "优酷"
}, {
"n": "湖南卫视", "v": "湖南卫视"
}, {
"n": "Netflix", "v": "Netflix"
}, {
"n": "HBO", "v": "HBO"
}, {
"n": "BBC", "v": "BBC"
}, {
"n": "NHK", "v": "NHK"
}, {
"n": "CBS", "v": "CBS"
}, {
"n": "NBC", "v": "NBC"
}, {
"n": "tvN", "v": "tvN"
}]
}], "rank_list_movie": [{
"key": "榜单", "name": "榜单", "value": [{
"n": "实时热门电影", "v": "movie_real_time_hotest"
}, {
"n": "一周口碑电影榜", "v": "movie_weekly_best"
}, {
"n": "豆瓣电影Top250", "v": "movie_top250"
}]
}], "rank_list_tv": [{
"key": "榜单", "name": "榜单", "value": [{
"n": "实时热门电视", "v": "tv_real_time_hotest"
}, {
"n": "华语口碑剧集榜", "v": "tv_chinese_best_weekly"
}, {
"n": "全球口碑剧集榜", "v": "tv_global_best_weekly"
}, {
"n": "国内口碑综艺榜", "v": "show_chinese_best_weekly"
}, {
"n": "国外口碑综艺榜", "v": "show_global_best_weekly"
}]
}]
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const item of obj) {
let vod_short = new VodShort()
vod_short.vod_id = "msearch:" + item["id"]
if (item["title"] === undefined) {
vod_short.vod_name = item["target"]["title"]
} else {
vod_short.vod_name = item["title"]
}
if (item["pic"] === undefined) {
vod_short.vod_pic = item["target"]["cover_url"]
} else {
vod_short.vod_pic = item["pic"]["normal"]
}
if (item["rating"] === undefined) {
vod_short.vod_remarks = "评分:" + item["target"]["rating"]["value"].toString()
} else {
vod_short.vod_remarks = "评分:" + item["rating"]["value"].toString()
}
vod_list.push(vod_short);
}
return vod_list
}
get_tags(extend) {
let tag_list = []
for (const key of Object.keys(extend)) {
if (key !== "sort") {
tag_list.push(extend[key])
}
}
return tag_list.join(",")
}
sign(url, ts, method = 'GET') {
let _api_secret_key = "bf7dddc7c9cfe6f7"
let url_path = "%2F" + url.split("/").slice(3).join("%2F")
let raw_sign = [method.toLocaleUpperCase(), url_path, ts.toString()].join("&")
return Crypto.HmacSHA1(raw_sign, _api_secret_key).toString(Crypto.enc.Base64)
}
async setHomeVod() {
let url = this.siteUrl + "/subject_collection/subject_real_time_hotest/items"
let content = await this.fetch(url, {"apikey": this.apiKey}, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let items = content_json["subject_collection_items"]
this.homeVodList = await this.parseVodShortListFromJson(items)
}
}
async setCategory(tid, pg, filter, extend) {
let sort = extend["sort"] ?? "show_hot";
let tag_str = this.get_tags(extend)
this.count = 0
this.limit = 20;
this.total = 0;
let start = 0
if (parseInt(pg) > 1) {
start = (parseInt(pg) - 1) * this.limit
}
let cateUrl = ""
let params = {"start": start.toString(), "count": this.limit.toString()}
let itemKey = "items"
switch (tid) {
case "hot_gaia":
sort = extend["sort"] ?? "recommend"
let area = extend["area"] ?? "全部"
params["sort"] = sort
params["area"] = area
cateUrl = "/movie/hot_gaia"
break
case "tv_hot":
let type = extend["type"] ?? "tv_hot"
cateUrl = "/subject_collection/" + type + "/items"
itemKey = "subject_collection_items"
break
case "show_hot":
let showType = extend["type"] ?? "show_hot"
cateUrl = "/subject_collection/" + showType + "/items"
itemKey = "subject_collection_items";
break
case "movie":
params["sort"] = sort
params["tags"] = tag_str
cateUrl = "/movie/recommend"
break
case "tv":
params["sort"] = sort
params["tags"] = tag_str
cateUrl = "/tv/recommend"
break
case "rank_list_movie":
let rankMovieType = extend["榜单"] ?? "movie_real_time_hotest"
cateUrl = "/subject_collection/" + rankMovieType + "/items"
itemKey = "subject_collection_items"
break
case "rank_list_tv":
let rankTVType = extend["榜单"] ?? "tv_real_time_hotest"
cateUrl = "/subject_collection/" + rankTVType + "/items"
itemKey = "subject_collection_items"
break
default:
break
}
params["apikey"] = this.apiKey
let content = await this.fetch(this.siteUrl + cateUrl, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let items = content_json[itemKey]
this.vodList = await this.parseVodShortListFromJson(items)
}
}
async setSearch(wd, quick, pg) {
let _api_url = "https://frodo.douban.com/api/v2"
let _api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
let url = _api_url + "/search/movie"
let date = new Date()
let ts = date.getFullYear().toString() + ('0' + (date.getMonth() + 1)).slice(-2).toString() + date.getDate().toString()
const limit = 20
let params = {
'_sig': this.sign(url, ts),
'_ts': ts,
'apiKey': _api_key,
'count': limit,
'os_rom': 'android',
'q': encodeURIComponent(wd),
'start': parseInt(pg)
}
let content = await this.fetch(url, params, this.getSearchHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
this.vodList = await this.parseVodShortListFromJson(content_json["items"])
const page = parseInt(pg);
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
}
}
let spider = new DoubanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+75
View File
@@ -0,0 +1,75 @@
/*
* @File : dubo.js
* @Author : jade
* @Date : 2024/4/16 18:46
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {TianTianSpider} from "./tiantian.js"
class DuboSpider extends TianTianSpider {
constructor() {
super();
this.siteUrl = "http://v.rbotv.cn"
this.cookie = ""
this.extendObj = {"extend": "类型", "area": "地区", "year": "年代"}
this.parseMap = {};
}
getName() {
return "🛶┃独播影视┃🛶"
}
getAppName() {
return "独播影视"
}
getJSName() {
return "dubo"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = false
}
}
let spider = new DuboSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+280
View File
@@ -0,0 +1,280 @@
/*
* @File : dygangs.js
* @Author : jade
* @Date : 2024/2/21 15:06
* @Email : [email protected]
* @Software : Samples
* @Desc : 电影港
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {_, load} from "../lib/cat.js";
class MoviePortSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.dygangs.org"
}
getAppName() {
return "电影港"
}
getName() {
return "🏖️┃电影港┃🏖️"
}
getJSName() {
return "dygangs"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"top-nav\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = navElement.attribs.href.replaceAll(this.siteUrl, "")
let type_name = $(navElement).text()
if (type_id !== "/") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($, index) {
let element = $("[class=\"nav-down-2 clearfix\"]")[index]
let extend_list = []
if (element !== undefined) {
let name = "按类型"
let extend_dic = {"key": name, "name": name, "value": []}
extend_dic["name"] = name
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(element).find("a")) {
let type_name = $(ele).html()
let type_id = ele.attribs.href.split("/").slice(-2)[0]
extend_dic["value"].push({"n": type_name, "v": type_id})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
let index = 0
for (const type_dic of this.classes.slice(1, 5)) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `${type_id}`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($, index)
}
index = index + 1
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $(element).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(element).find("i")[0]).text().replaceAll(" ", "").replaceAll("\n", "")
if (_.isEmpty(vodShort.vod_pic)){
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dygang.jpg"
}
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"index-tj-l\"]").find("li")
for (const vodElement of vodElements) {
let vodShortElement = $(vodElement).find("a")[0]
let vodShort = this.parseVodShortFromElement($, vodShortElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"index-area clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShortElement = $(vodElement).find("a")[0]
let vodShort = this.parseVodShortFromElement($, vodShortElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodDetailElement = $("[ class=\"ct mb clearfix\"]")
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs["src"]
vodDetail.vod_name = Utils.getStrByRegex(/◎片  名 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_area = Utils.getStrByRegex(/◎产  地 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_year = Utils.getStrByRegex(/◎年  代 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.type_name = Utils.getStrByRegex(/◎类  别 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_remarks = Utils.getStrByRegex(/◎集  数 (.*?)<br>/, $(vodDetailElement).html())
let content = Utils.getStrByRegex(/   (.*?)<\/p>/s, $(vodDetailElement).html())
if (_.isEmpty(content)) {
content = Utils.getStrByRegex(/   (.*?)<\/p>/s, $(vodDetailElement).html())
}
let actor_list = []
for (const actor of content.split("\n")) {
actor_list.push(actor.replaceAll("    &nbsp;  ", "").replaceAll("<br>", "").replaceAll("     ", ""))
}
vodDetail.vod_actor = actor_list.join("/")
vodDetail.vod_director = Utils.getStrByRegex(/◎导  演 (.*?)<br>/, $(vodDetailElement).html())
vodDetail.vod_content = Utils.getStrByRegex(/  <\/p>(.*?)<br>/s, $(vodDetailElement).html()).replaceAll("<p>", "").replaceAll("\n", "")
if (_.isEmpty(vodDetail.vod_content)) {
vodDetail.vod_content = Utils.getStrByRegex(/  <br>(.*?)<\/p>/s, $(vodDetailElement).html()).replaceAll("<p>", "").replaceAll("\n", "")
}
let vod_play_from_list = []
let vod_play_list = []
let playFormatElements = $("[class=\"playfrom tab8 clearfix\"]")
let playUrlElements = $("[class=\"videourl clearfix\"]")
for (let i = 0; i < playFormatElements.length; i++) {
let playFormatElement = playFormatElements[i]
let format_name = $($(playFormatElement).find("li")).html()
vod_play_from_list.push(format_name.replaceAll("<i class=\"playerico ico-Azhan\"></i> ", ""))
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = playUrlElement.attribs.title
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
let playFormatElement = $($(vodDetailElement).find("span")[0]).find("span")
if (playFormatElement.length > 0) {
let format_name = $(playFormatElement).html()
vod_play_from_list.push(Utils.getStrByRegex(/【(.*?)】/, format_name.replaceAll("下载地址", "磁力链接")))
let vodItems = []
for (const playUrlElement of $($($(vodDetailElement).find("tbody")).find("tr")).find("a")) {
let episodeName = $(playUrlElement).html().replaceAll(".mp4", "")
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid
if (extend["按类型"] !== undefined && extend["按类型"] !== "0") {
url = url + `${extend["按类型"]}/`
}
if (parseInt(pg) > 1) {
url = url + `index_${pg}.html`
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/e/search/index.php"
let params = {"keyboard": wd, "submit": "搜 索", "show": "title,zhuyan", "tempid": "1"}
let resp = await this.post(url, params, this.getHeader())
let $ = load(resp)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
if (id.indexOf("http") > -1) {
let $ = await this.getHtml(id)
let url = Utils.getStrByRegex(/url: '(.*?)',/, $.html())
if (_.isEmpty(url)) {
let videoUrl = $($("[class=\"video\"]")[0]).find("iframe")[0].attribs["src"]
let html = await this.fetch(videoUrl, null, {"User-Agent": Utils.CHROME})
this.playUrl = Utils.getStrByRegex(/url: '(.*?)',/, html)
if (_.isEmpty(this.playUrl)){
let urlHost = Utils.getHost(videoUrl)
this.playUrl = urlHost + Utils.getStrByRegex(/var main = "(.*?)";/, html)
}
} else {
this.playUrl = url
}
} else {
this.playUrl = id
}
}
}
let spider = new MoviePortSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+214
View File
@@ -0,0 +1,214 @@
/*
* @File : freeok.js
* @Author : jade
* @Date : 2024/1/19 10:26
* @Email : [email protected]
* @Software : Samples
* @Desc : 电影天堂(已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class DyttSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.dy2018.com"
this.dyttReconnectTimes = 0
}
getName() {
return `👼┃电影天堂BT┃👼`
}
getAppName() {
return "电影天堂BT"
}
getJSName() {
return "dyttbt"
}
getType() {
return 3
}
// getHeader() {
// return {"User-Agent": "PostmanRuntime/7.36.1", "Host":"www.dy2018.com"};
// }
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
try {
let buffer = await this.fetch(url, null, headers, false, false, 1)
let html = Utils.decode(buffer, "gb2312")
if (!_.isEmpty(html) && Utils.getStrByRegex(/<script src="(.*?)"><\/script>/, html) !== "/_guard/auto.js") {
return load(html)
} else {
if (this.dyttReconnectTimes < this.maxReconnectTimes) {
Utils.sleep(2)
this.dyttReconnectTimes = this.dyttReconnectTimes + 1
return await this.getHtml(url, headers)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
} catch (e) {
await this.jadeLog.error(`获取html出错,出错原因为${e}`)
}
}
async setFilterObj() {
}
async setClasses() {
let $ = await this.getHtml()
let vodShortElements = $("[class=\"title_all\"]")
for (const vodShortElement of vodShortElements) {
let spanElement = $(vodShortElement).find("span")[0]
let aElement = $(vodShortElement).find("a")[0]
let type_name = $(spanElement).text()
let type_id = aElement.attribs["href"]
if (type_id.indexOf("https:") === -1 && type_id.indexOf("http:") === -1) {
type_id = this.siteUrl + type_id
}
this.classes.push(this.getTypeDic(type_name, type_id))
}
let containElements = $($("[id=\"menu\"]").find("[class=\"contain\"]")).find("a").slice(0, -3)
for (const contaElement of containElements) {
let type_name = $(contaElement).text()
let type_id = contaElement.attribs["href"]
if (type_id.indexOf("https:") === -1 && type_id.indexOf("http:") === -1) {
type_id = this.siteUrl + type_id
}
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodShortElements = $($("[class=\"co_content8\"]")[0]).find("tbody")
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElements = $(vodShortElement).find("tr")
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/, $(vodElements[1]).text())
vodShort.vod_id = $(vodElements[1]).find("a").slice(-1)[0].attribs.href
vodShort.vod_remarks = "日期:" + Utils.getStrByRegex(/日期:(.*?) /, $(vodElements[2]).text()) + " 热度:" + Utils.getStrByRegex(/点击:(.*?) /, $(vodElements[2]).text())
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dytt.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodShortElements = $($("[class=\"co_area2\"]")[0]).find("li").slice(1)
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
let vodElement = $(vodShortElement).find("a")[0]
vodShort.vod_id = vodElement.attribs["href"]
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/, vodElement.attribs["title"])
vodShort.vod_remarks = $($(vodShortElement).find("span")).text().replaceAll("", "")
vodShort.vod_pic = Utils.RESOURCEURL + "/resources/dytt.jpg"
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = Utils.getStrByRegex(/《(.*?)》/, Utils.getStrByRegex(/<title>(.*?)<\/title>/, $.html()))
let zoomElement = $("[id=\"Zoom\"]")
vodDetail.vod_pic = $(zoomElement).find("img")[0].attribs.src
let content = $(zoomElement).text()
vodDetail.vod_year = Utils.getStrByRegex(/年  代 (.*?)◎/, content)
vodDetail.type_name = Utils.getStrByRegex(/类  别 (.*?)◎/, content)
vodDetail.vod_area = Utils.getStrByRegex(/产  地 (.*?)◎/, content)
vodDetail.vod_director = Utils.getStrByRegex(/导  演 (.*?)◎/, content)
vodDetail.vod_content = Utils.getStrByRegex(/简  介 (.*?)◎/, content)
vodDetail.vod_actor = Utils.getStrByRegex(/主  演(.*?)◎/, content).replaceAll("      ", "*")
vodDetail.vod_remarks = Utils.getStrByRegex(/豆瓣评分 (.*?)\//, content)
vodDetail.vod_play_from = "磁力链接"
let playList = $(zoomElement).find("[class=\"player_list\"]").find("a")
let vodItems = []
for (const playEle of playList) {
vodItems.push($(playEle).text() + "$" + playEle.attribs.href);
}
vodDetail.vod_play_url = [vodItems.join("#")].join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let cateUrl = tid
if (tid.indexOf("index") > -1){
cateUrl = tid.split(".html")[0] + "_" + pg + ".html"
}
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
let spider = new DyttSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+96
View File
@@ -0,0 +1,96 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : [email protected]
* @Software : Samples
* @Desc : 非凡资源 (已失效)
*/
import {VodSpider} from "./vodSpider.js";
class FeiFanSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = true
this.type_id_18 = 34
}
getAppName() {
return "非凡资源"
}
getName() {
return `🥗┃非凡资源┃🥗`
}
getJSName() {
return "feifan"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new FeiFanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+96
View File
@@ -0,0 +1,96 @@
/*
* @File : feifan.js
* @Author : jade
* @Date : 2024/02/06 14:58
* @Email : [email protected]
* @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}
+333
View File
@@ -0,0 +1,333 @@
/*
* @File : freeok.js
* @Author : jade
* @Date : 2024/1/19 10:26
* @Email : [email protected]
* @Software : Samples
* @Desc : OK资源网 已失效
*/
import {_} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {player} from "../lib/freeok_setttings.js";
const OCR_API = 'https://api.nn.ci/ocr/b64/text';//ocr在线识别接口
class OkSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.freeok.vip"
}
getName() {
return `🆗┃OK资源网┃🆗`
}
getAppName() {
return `OK资源网`
}
getJSName() {
return "freeok"
}
getType() {
return 3
}
async init(cfg) {
this.cookie = await this.load_cache()
await super.init(cfg);
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"module\"]")).find("a").slice(0, 12)
for (const vodElement of vodElements) {
vod_list.push(this.parseVodShortFromElement($, vodElement))
}
return vod_list
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_name = element.attribs["title"]
vodShort.vod_id = element.attribs["href"]
vodShort.vod_remarks = $($(element).find("[class=\"module-item-note\"]")).text()
vodShort.vod_pic = $(element).find("[class=\"lazy lazyload\"]")[0].attribs["data-original"]
return vodShort
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let itemElements = $($("[class=\"module-items module-poster-items-base \"]")).find("a")
for (const itemElement of itemElements) {
vod_list.push(this.parseVodShortFromElement($, itemElement))
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const result of obj["Data"]["result"]){
let vodShort = new VodShort()
vodShort.vod_id = result["vod_url"].replaceAll(this.siteUrl,"")
vodShort.vod_pic = result["vod_pic"]
vodShort.vod_name = result["vod_name"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByHot($) {
let vod_list = []
let itemElement = $($("[class=\"module-items module-card-items\"]"))[0]
let titleElements = $(itemElement).find("[class=\"module-card-item-title\"]").find("a")
let infoElements = $(itemElement).find("[class=\"module-card-item-info\"]")
let picElements = $(itemElement).find("[class=\"module-item-pic\"]").find("img")
for (let i = 0; i < titleElements.length; i++) {
let vodShort = new VodShort();
vodShort.vod_id = titleElements[i].attribs["href"]
vodShort.vod_name = $(titleElements[i]).text()
vodShort.vod_pic = picElements[i].attribs["data-original"]
vodShort.vod_remarks = $($(infoElements[i])).text().split("\n")[5]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let moudleElements = $("[class=\"module-info-tag-link\"]").find("a")
let mobilePlay = $("[class=\"module-mobile-play\"]").find("a")[0]
vodDetail.vod_name = mobilePlay.attribs["title"].replaceAll("立刻播放", "")
vodDetail.vod_content = $($("[class=\"module-info-introduction-content\"]")).text().replaceAll("\n", "").replaceAll(" ", "")
let type_list = []
for (const moudleElement of moudleElements.slice(2)) {
type_list.push($(moudleElement).text())
}
vodDetail.type_name = type_list.join("/")
vodDetail.vod_year = $(moudleElements[0]).text()
vodDetail.vod_area = $(moudleElements[1]).text()
let itemElements = $("[class=\"module-info-item\"]")
let itemText = ""
for (const itemElement of itemElements) {
itemText = itemText + $(itemElement).text().replaceAll("\n", "").replaceAll("", ":") + "\n"
}
vodDetail.vod_pic = $("[class=\"module-item-pic\"]").find("img")[0].attribs["data-original"]
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?)\n/, itemText)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?)\n/, itemText)
vodDetail.vod_year = Utils.getStrByRegex(/上映:(.*?)\n/, itemText)
vodDetail.vod_remarks = Utils.getStrByRegex(/备注:(.*?)\n/, itemText)
if (_.isEmpty(vodDetail.vod_remarks)) {
vodDetail.vod_remarks = Utils.getStrByRegex(/集数:(.*?)\n/, itemText)
}
let playElements = $($("[class=\"module-tab-items-box hisSwiper\"]")).find("span")
let play_from_list = []
let playUrlElements = $("[class=\"module-list sort-list tab-list his-tab-list\"]")
let play_url_list = []
for (let i = 0; i < playElements.length; i++) {
let text = $(playElements[i]).text()
if (text.indexOf("夸克") === -1) {
let playDetailElements = $(playUrlElements[i]).find("a")
let vodItems = []
for (const playDetailElement of playDetailElements) {
let play_name = playDetailElement.attribs["title"].replaceAll("播放", "").replaceAll(vodDetail.vod_name, "")
let play_url = playDetailElement.attribs["href"]
vodItems.push(`${play_name}$${play_url}`)
}
play_url_list.push(vodItems.join("#"))
play_from_list.push($(playElements[i]).text())
}
}
vodDetail.vod_play_from = play_from_list.join("$$$")
vodDetail.vod_play_url = play_url_list.join("$$$")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl, this.getHeader())
let navElements = $($("[class=\"navbar-items swiper-wrapper\"]")).find("a")
let type_name = $(navElements.slice(0, 8).slice(-1)[0]).text().replaceAll("\n", "")
let type_id = navElements.slice(0, 8).slice(-1)[0].attribs["href"]
this.classes.push({"type_name": type_name, "type_id": type_id})
for (const navElement of navElements.slice(0, 8)) {
let type_name = $(navElement).text().replaceAll("\n", "")
if (type_name !== "首页" && type_name !== "热榜") {
let type_id = navElement.attribs["href"].split("/").slice(-1)[0].split(".")[0]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
}
}
async getFilter($) {
let titleElements = $("[class=\"module-item-title\"]")
let boxElements = $("[class=\"module-item-box\"]")
let extend_list = []
let type_id_dic = {"类型": 1, "剧情": 4, "地区": 2, "语言": 5, "年份": 12, "排序": 3}
for (let i = 0; i < titleElements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": $(titleElements[i]).text(), "value": []}
let typeElements = $(boxElements[i]).find("a")
for (let j = 0; j < typeElements.length; j++) {
let type_name = $(typeElements[j]).text()
let type_id = decodeURIComponent(typeElements[j].attribs["href"].split("-")[type_id_dic[$(titleElements[i]).text()]]).replaceAll(".html", "")
extend_dic["value"].push({"n": type_name, "v": $(titleElements[i]).text() + "-" + type_id})
}
extend_list.push(extend_dic)
}
return extend_list;
}
async setFilterObj() {
for (const class_dic of this.classes) {
if (class_dic["type_name"] !== "最近更新" && class_dic["type_name"] !== "热榜") {
let cateUrl = this.siteUrl + `/vod-show/${class_dic["type_id"]}--------1---.html`
let $ = await this.getHtml(cateUrl, this.getHeader())
this.filterObj[class_dic["type_id"]] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl, this.getHeader())
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getCateUrl(tid, pg, extend) {
let value_list = Object.values(extend)
let type_id_dic = {"类型": 1, "剧情": 3, "地区": 1, "语言": 4, "年份": 11, "排序": 2}
let urlParams = [tid.toString(), "", "","","", "", "", "", "", "", "",""]
urlParams[8] = pg.toString()
for (const value of value_list) {
if (value.split("-")[0] === "类型") {
urlParams[0] = value.split("-")[1].split("show/")[1].toString()
} else {
let type_index = type_id_dic[value.split("-")[0]]
urlParams[type_index] = value.split("-")[1]
}
}
return this.siteUrl + `/vod-show/` + urlParams.join("-") + ".html"
}
async setCategory(tid, pg, filter, extend) {
let cateUrl
if (tid.indexOf(".html") > -1) {
cateUrl = this.siteUrl + tid
let $ = await this.getHtml(cateUrl, this.getHeader());
this.vodList = await this.parseVodShortListFromDocByHot($)
} else {
cateUrl = this.getCateUrl(tid, pg, extend)
let $ = await this.getHtml(cateUrl, this.getHeader());
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
async setSearch(wd, quick) {
let url = `http://123.207.150.253/zxapi/public/?service=App.F.Fetch&req_p=${wd}&type=okys`
let content = await this.fetch(url,null,this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async refreshCookie() {
let passUrl = this.siteUrl + "/index.php/verify/index.html?"
let passHtml = await this.fetch(passUrl,null,this.getHeader(),false,true)
let response2 = await this.post(OCR_API,passHtml["content"],this.getHeader())
this.cookie = Utils.getStrByRegex(/(.*?);/,passHtml["cookie"])
let verifyUrl = this.siteUrl + "/index.php/ajax/verify_check?type=search&verify=5286"
let headers = this.getHeader()
headers["cookie"] = this.cookie
let response = await this.post(verifyUrl,null,headers)
await this.write_cache()
}
async load_cache() {
try {
return await local.get("freeok_cookie", "cookie")
} catch (e) {
return ""
}
}
async write_cache() {
await local.set("freeok_cookie", "cookie", JSON.stringify(this.cookie))
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id, this.getHeader())
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id, this.getHeader())
const js = JSON.parse($('script:contains(player_)').html().replace('var player_aaaa=', ''));
let url = this.siteUrl + "/okplayer/"
let params = {
"url": decodeURIComponent(js.url), "next": decodeURIComponent(js.url_next), "title": js.vod_data.vod_name
}
let playHtml = await this.fetch(url, params, this.getHeader());
let view_port_id = Utils.getStrByRegex(/<meta name="viewport"(.*?)>/, playHtml).split("id=\"")[1].replaceAll("now_", "")
let player_id = Utils.getStrByRegex(/meta charset="UTF-8" id="(.*?)">/, playHtml).replaceAll("now_", "")
let player_url = Utils.getStrByRegex(/"url": "(.*?)",/, playHtml)
this.playUrl = player(player_url, view_port_id, player_id)
}
}
let spider = new OkSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+231
View File
@@ -0,0 +1,231 @@
/*
* @File : gitcafe.js
* @Author : jade
* @Date : 2024/1/18 9:56
* @Email : [email protected]
* @Software : Samples
* @Desc : 阿里纸条
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import { detailContent,initCloud,playContent,getHeaders} from "../lib/cloud.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class GitCafeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://ali.gitcafe.ink"
}
getName() {
return "🦊┃阿里纸条┃🦊"
}
getAppName() {
return "阿里纸条"
}
getJSName() {
return "gitcafe"
}
getType() {
return 3
}
async getApiUrl() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let paper_js_url = Utils.getStrByRegex(/<script src='(.*?)'><\/script>/, html)
let paper_js_content = await this.fetch(paper_js_url, null, this.getHeader())
return {
"api": "https:" + Utils.getStrByRegex(/ return '(.*?)' \+ /, paper_js_content) + new Date().getTime(),
"search_api": Utils.getStrByRegex(/const SEARCH_API = '(.*?)';/, paper_js_content)
}
}
}
async getContentJson() {
let url_json = await this.getApiUrl()
let content = await this.fetch(url_json["api"], null, this.getHeader())
this.search_api = url_json["search_api"]
if (!_.isEmpty(content)) {
return JSON.parse(content)
}
}
async spiderInit() {
this.content_json = await this.getContentJson()
this.token_dic = await this.load_cache()
}
async init(cfg) {
await this.spiderInit()
await super.init(cfg);
await initCloud(this.cfgObj);
}
async parseClassFromJson(obj) {
let data_list = Object.keys(obj["data"]).slice(0, 19)
for (const data_key of data_list) {
this.classes.push({"type_name": obj["data"][data_key]["name"], "type_id": data_key})
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
let class_id_list = this.getClassIdList()
for (const data_obj of obj) {
let vodShort = new VodShort()
if (class_id_list.includes(data_obj["cat"])) {
vodShort.vod_id = JSON.stringify(data_obj)
vodShort.vod_name = data_obj["title"]
vodShort.vod_remarks = data_obj["date"]
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let classNamesList = this.getClassNameList()
let classIdList = this.getClassIdList()
let vodDetail = new VodDetail()
vodDetail.vod_name = obj["title"]
vodDetail.vod_remarks = obj["creatime"] ?? obj["date"]
vodDetail.type_name = classNamesList[classIdList.indexOf(obj["cat"])]
vodDetail.vod_content = obj["des"]
let ali_url = "https://www.aliyundrive.com/s/" + obj["alikey"]
let playVod = await detailContent([ali_url],vodDetail.type_name)
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setClasses() {
await this.parseClassFromJson(this.content_json)
}
async setHomeVod() {
this.homeVodList = await this.parseVodShortListFromJson(this.content_json["info"]["new"])
}
async setDetail(id) {
let content_json = JSON.parse(id)
this.vodDetail = await this.parseVodDetailfromJson(content_json)
}
async setCategory(tid, pg, filter, extend) {
this.vodList = await this.parseVodShortListFromJson(this.content_json["data"][tid]["catdata"])
}
async setSearch(wd, quick) {
await this.refreshToken();
let params = {
"action": "search", "from": "web", "token": this.token_dic["token"], "keyword": wd
}
let content = await this.post(this.search_api, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
this.vodList = await this.parseVodShortListFromJson(content_json["data"])
}
}
async refreshToken() {
let this_time = new Date().getTime()
if (_.isEmpty(this.token_dic["token"])) {
await this.get_token()
await this.jadeLog.debug("Token为空,刷新Token")
} else if (this_time - parseInt(this.token_dic["date"]) > 24 * 60 * 60 * 1000) {
await this.jadeLog.debug(`Token到期,上次获取Token时间为:${this_time},当前时间为:${parseInt(this.token_dic["date"])},刷新Token`)
await this.get_token()
} else {
await this.jadeLog.debug(`Token仍然有效,无需刷新`, true)
}
}
async get_token() {
try {
let params = {
"action": "get_token", "from": "web",
}
let content = await this.post(this.search_api, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let this_time = new Date().getTime()
this.token_dic["token"] = content_json["data"]
this.token_dic["date"] = this_time.toString()
await this.write_cache()
}
} catch (e) {
await this.jadeLog.error("获取Token失败,失败原因为:" + e)
}
}
async write_cache() {
await local.set("gitcafe_token", "token", JSON.stringify(this.token_dic))
}
async load_cache() {
try {
let str = await local.get("gitcafe_token", "token")
return JSON.parse(str)
} catch (e) {
return {"token": "", "date": ""}
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
let spider = new GitCafeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+156
View File
@@ -0,0 +1,156 @@
/*
* @File : haiwaikan.js
* @Author : jade
* @Date : 2024/04/02 9:15
* @Email : [email protected]
* @Software : Samples
* @Desc : 海外看
*/
import {VodSpider} from "./vodSpider.js";
class HaiWaiKanSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://haiwaikan.com"
this.remove18 = true
this.type_id_18 = 0
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getAppName() {
return "海外看"
}
getName() {
return "☕┃海外看┃☕墙"
}
getJSName() {
return "haiwaikan"
}
getType() {
return 3
}
async setClasses() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const class_dic of content_json["class"]) {
if (class_dic["type_id"] < 26 ) {
this.classes.push(this.getTypeDic(class_dic["type_name"], class_dic["type_id"].toString()))
}
}
this.content_json = content_json
}
async getFilter(type_id,obj) {
let extend_list = []
let extend_dic = {"key": "1", "name": "全部类别", "value": [{"n":"全部类别","v":type_id.toString()}]}
for (const type_dic of obj["class"]){
let a_type_id = type_dic["type_id"]
let max_type_id = 0
let min_type_id = 0
if (type_id === 20){
max_type_id = 50
min_type_id = 27
}
if (type_id === 21){
max_type_id = 128
min_type_id = 100
}
if (type_id === 22){
max_type_id = 143
min_type_id = 134
}
if (type_id === 23){
max_type_id = 135
min_type_id = 127
}
if (a_type_id < max_type_id && a_type_id > min_type_id){
extend_dic["value"].push({"n":type_dic["type_name"],"v":a_type_id.toString()})
}
}
if (extend_dic["value"].length > 1){
extend_list.push(extend_dic)
return extend_list
}else{
return null
}
}
async setFilterObj() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const type_dic of this.classes){
let type_id = type_dic["type_id"]
if (type_id !== "最近更新"){
let extend_list = await this.getFilter(parseInt(type_id),content_json)
if (extend_list !== null){
this.filterObj[type_id] = extend_list
}
}
}
}
}
let spider = new HaiWaiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+625
View File
@@ -0,0 +1,625 @@
/*
* @File : hanxiucao.js
* @Author : jade
* @Date : 2024/04/13 19:38
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, Crypto} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {Spider} from "./spider.js";
import * as Utils from "../lib/utils.js";
function He(e, {key: t, iv: s} = {}) {
let VITE_APP_AES_KEY = "B77A9FF7F323B5404902102257503C2F"
let VITE_APP_AES_IV = "B77A9FF7F323B5404902102257503C2F"
var o = Crypto.enc.Utf8.parse(e)
, A = Crypto.AES.encrypt(o, Crypto.enc.Utf8.parse(t || VITE_APP_AES_KEY), {
iv: Crypto.enc.Utf8.parse(s || VITE_APP_AES_IV),
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
});
return Crypto.enc.Base64.stringify(A.ciphertext)
}
function Kt() {
const e = new Date;
return He(parseInt(e.getTime() / 1e3) + e.getTimezoneOffset() * 60 + -1)
}
function bt(e) {
const wA = "46cc793c53dc451b"
let t = Crypto.enc.Utf8.parse(wA)
, s = Crypto.AES.decrypt(e, t, {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7
});
return Crypto.enc.Utf8.stringify(s).toString()
}
class HanXiuCaoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.qianyuewenhua.xyz"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "imgBt", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'imgBt/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.spiderInit(null)
}
getAppName() {
return "含羞草"
}
getName() {
return "🔞┃含羞草┃🔞"
}
getJSName() {
return "hanxiucao"
}
getType() {
return 3
}
getParams(params) {
return {"endata": He(JSON.stringify(params)), "ents": Kt()}
}
async setClasses() {
let params = this.getParams({"channel": "pc"})
let response = await this.post(this.siteUrl + "/panel/list", params, this.getHeader(), "")
let resJson = JSON.parse(response)
for (const data of resJson["data"]["list"]) {
let type_id = data["panelId"]
let type_name = data["panelName"]
if (type_name !== "首页") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter(Layouts) {
let extend_list = []
for (const data of Layouts) {
let layoutObj = JSON.parse(data["layoutContent"])
for (const layout of layoutObj["sortKeys"]) {
let extend_dic = {}
if (layout["label"] !== "综合排序") {
extend_dic = {"key": "sorts", "name": layout["label"].toString(), value: []}
extend_dic["value"].push({"n": "升序", "v": layout["value"].toString() + "-" + "升序"})
extend_dic["value"].push({"n": "降序", "v": layout["value"].toString() + "-" + "降序"})
} else {
extend_dic = {"key": "sorts", "name": "排序", value: []}
extend_dic["value"].push({"n": layout["label"].toString(), "v": layout["value"].toString()})
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async getNvYouFilter(Layouts) {
let extend_list = []
let params = {
"uids": [],
"page": 1,
"length": 20
}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
let layoutObj = JSON.parse(data["layoutContent"])
params["uids"] = layoutObj["list"]
let resJson = JSON.parse(await this.post(this.siteUrl + "/user/getUpList", this.getParams(params), this.getHeader(), ""))
let extend_dic = {"key": `tags`, "name": data["layoutName"], value: []}
for (const layout of resJson["data"]["list"]) {
extend_dic["value"].push({"n": layout["user_nicename"], "v": JSON.stringify(layout)})
}
extend_list.push(extend_dic)
}
let sort_list = [
{
"key": "sorts",
"name": "发布时间",
"value": [
{
"n": "升序",
"v": "1-升序"
},
{
"n": "降序",
"v": "1-降序"
}
]
},
{
"key": "sorts",
"name": "点赞数量",
"value": [
{
"n": "升序",
"v": "5-升序"
},
{
"n": "降序",
"v": "5-降序"
}
]
},
{
"key": "sorts",
"name": "收藏数量",
"value": [
{
"n": "升序",
"v": "6-升序"
},
{
"n": "降序",
"v": "6-降序"
}
]
}
]
return [...extend_list, ...sort_list]
}
async getZhuanTiFilter(Layouts) {
let extend_list = []
let params = {
"page": 1,
"length": 36,
"subjectIds": []
}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
let layoutObj = JSON.parse(data["layoutContent"])
params["subjectIds"] = layoutObj["list"]
let resJson = JSON.parse(await this.post(this.siteUrl + "/subject/list", this.getParams(params), this.getHeader(), ""))
let extend_dic = {"key": `tags`, "name": data["layoutName"], value: []}
for (const layout of resJson["data"]["list"]) {
extend_dic["value"].push({"n": layout["name"], "v": JSON.stringify(layout)})
}
extend_list.push(extend_dic)
}
let sort_dic = {
"key": "sorts",
"name": "排序",
"value": [
{
"n": "推荐",
"v": "8"
},
{
"n": "最新",
"v": "1"
},
{
"n": "最热",
"v": "2"
}
]
}
extend_list.push(sort_dic)
return extend_list
}
async getChuanMeiFilter(Layouts) {
let extend_list = []
let extend_dic = {"key": `tags`, "name": "传媒", value: []}
for (let i = 0; i < Layouts.length; i++) {
let data = Layouts[i]
extend_dic["value"].push({"n": data["layoutName"], "v": data["layoutContent"]})
}
extend_list.push(extend_dic)
for (const layout of JSON.parse(Layouts[0]["layoutContent"])["moreOrderType"]) {
extend_dic = {"key": "sorts", "name": layout["label"].toString(), value: []}
extend_dic["value"].push({"n": "升序", "v": layout["value"].toString() + "-" + "升序"})
extend_dic["value"].push({"n": "降序", "v": layout["value"].toString() + "-" + "降序"})
extend_list.push(extend_dic)
}
extend_list.push(extend_dic)
return extend_list
}
async getHeJiFilter(Layouts) {
let extend_list = []
let params = {
"page": 1,
"length": 24,
"gatherType": 1,
"gatherIds": []
}
let extend_dic = {"key": `tags`, "name": "合集", value: []}
let resJson = JSON.parse(await this.post(this.siteUrl + "/gather/getList", this.getParams(params), this.getHeader(), ""))
for (const data of resJson["data"]["list"]) {
extend_dic["value"].push({"n": data["name"], "v": data["gatherId"].toString()})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (let i = 0; i < this.classes.length; i++) {
let type_dic = this.classes[i]
let type_id = type_dic["type_id"]
let type_name = type_dic["type_name"]
let filterList = []
if (type_id !== "最近更新") {
type_id = parseInt(type_id)
let params = this.getParams({"panelId": type_id})
let response = await this.post(this.siteUrl + "/panel/get", params, this.getHeader(), "")
let resJson = JSON.parse(response)
let layoutList = resJson["data"]["info"]["Layouts"]
let layOutObj = JSON.parse(resJson["data"]["info"]["Layouts"][0]["layoutContent"])
if (type_id > 174 && type_id < 181) {
let layOutObj = JSON.parse(resJson["data"]["info"]["Layouts"][0]["layoutContent"])
type_id = type_id + "$" + JSON.stringify(layOutObj)
filterList = await this.getFilter(layoutList)
} else {
switch (type_id) {
case 172:
filterList = await this.getHeJiFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
case 173:
filterList = await this.getChuanMeiFilter(layoutList)
type_id = type_id + "$" + JSON.stringify(layOutObj)
break
case 182:
filterList = await this.getNvYouFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
case 209:
filterList = await this.getZhuanTiFilter(layoutList)
type_id = type_id + "$" + filterList[0]["value"][0]["v"]
break
default:
break
}
}
this.classes[i] = this.getTypeDic(type_name, type_id)
this.filterObj[type_id] = filterList
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["coverImgUrl"])
if (data["hot"] === undefined) {
vodShort.vod_remarks = "观看:" + (data["seeCount"] / 10000).toFixed(1).toString() + "W"
} else {
vodShort.vod_remarks = "热度:" + (data["hot"] / 1000).toFixed(1).toString() + "K"
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromGatherJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["gatherId"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["coverImgUrl"])
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc(detailObj) {
let vodDetail = new VodDetail()
vodDetail.vod_name = detailObj["name"]
vodDetail.vod_year = detailObj["addTime"]
vodDetail.vod_pic = this.jsBase + Utils.base64Encode(detailObj["coverImgUrl"])
vodDetail.type_name = detailObj["typeName"]
vodDetail.vod_content = detailObj["tags"]
let vodItems = []
let params = {
"videoId": detailObj["id"]
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/videos/getPreUrl", this.getParams(params), this.getHeader(), ""))
let playList = resJson["data"]["url"].split("?")
let playUrl = playList[0] + "?sign" + playList[1].split("&sign").slice(-1)[0]
vodItems.push(vodDetail.vod_name + "$" + playUrl)
let playObj = {"线路1": vodItems.join("#")}
vodDetail.vod_play_url = _.values(playObj).join('$$$');
vodDetail.vod_play_from = _.keys(playObj).join('$$$');
return vodDetail
}
async getHomeVod(params) {
let params_str = this.getParams(params)
let response = await this.post(this.siteUrl + "/videos/getList", params_str, this.getHeader(), "")
return await this.parseVodShortListFromJson(JSON.parse(response)["data"]["list"])
}
async setHomeVod() {
let vod_list1 = await this.getHomeVod({
"page": 1,
"length": 16,
"offset": 0,
"typeIds": [],
"orderType": 1,
"payType": [3, 4]
})
let vod_list2 = await this.getHomeVod({
"page": 1,
"length": 16,
"offset": 0,
"typeIds": [],
"orderType": 3,
"payType": [
1
]
})
let vod_list3 = await this.getHomeVod({
"page": 1,
"length": 32,
"offset": 0,
"typeIds": [],
"orderType": 1,
"payType": [
3
]
})
this.homeVodList = [...vod_list1, ...vod_list2, ...vod_list3];
}
getSortParams(params, extend) {
let orderTypeStr = extend["sorts"] ?? ""
if (!_.isEmpty(orderTypeStr)) {
let orderType = orderTypeStr.split("-")[0]
params["orderType"] = parseInt(orderType)
let orderModeStr = orderTypeStr.split("-")[1]
let orderMode = 0
if (orderModeStr === "升序") {
orderMode = "1"
} else {
orderMode = "0"
}
params["orderMode"] = parseInt(orderMode)
}
return params
}
getTopParams(type_id, layOutObj, pg, extend) {
let defaultOderType
if (type_id === 180) {
defaultOderType = "1"
} else {
defaultOderType = "7"
}
let orderMode = "1"
let orderType
let orderTypeStr = extend["sorts"] ?? defaultOderType
let isOrderModel = false
if (orderTypeStr.indexOf("-") > -1) {
orderType = orderTypeStr.split("-")[0]
let orderModeStr = orderTypeStr.split("-")[1]
if (orderModeStr === "升序") {
orderMode = "1"
} else {
orderMode = "0"
}
isOrderModel = true
} else {
orderType = defaultOderType
}
let params = {
"orderType": parseInt(orderType), //或者7
"tags": [],
"length": 11,
"page": parseInt(pg),
"typeIds": layOutObj["classs"],
"payType": layOutObj["payType"],
}
if (isOrderModel) {
params["orderMode"] = parseInt(orderMode)
}
return params
}
getChuanMeiParams(layOutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layOutObj
}
let params = {
"page": parseInt(pg),
"length": 32,
"offset": 32 * parseInt(pg - 1),
"tag": obj["videoLables"].join(","),
"typeIds": obj["classs"],
"orderType": obj["orderType"],
"payType": obj["payType"]
}
params = this.getSortParams(params, extend)
return params
}
getNvYouParams(layoutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layoutObj
}
let params = {"videoSort": 1, "touid": obj["id"], "page": parseInt(pg), "length": 12, "orderType": 1}
params = this.getSortParams(params, extend)
return params
}
getZhuantiParams(layoutObj, pg, extend) {
let obj
if (!_.isEmpty(extend["tags"])) {
obj = JSON.parse(extend["tags"])
} else {
obj = layoutObj
}
let orderType = extend["sorts"] ?? "8"
return {
"page": parseInt(pg),
"length": 12,
"offset": 12 * (parseInt(pg) - 1),
"orderType": parseInt(orderType),
"subjectId": obj["id"]
}
}
async setCategory(tid, pg, filter, extend) {
let tid_list = tid.split("$")
let type_id = parseInt(tid_list[0])
let layOutObj = JSON.parse(tid_list[1])
let params = {}
let url = "/videos/getList"
if (type_id > 174 && type_id < 181) {
params = this.getTopParams(type_id, layOutObj, pg, extend)
} else {
switch (type_id) {
case 173:
params = this.getChuanMeiParams(layOutObj, pg, extend)
break
case 182:
params = this.getNvYouParams(layOutObj, pg, extend)
url = "/user/getSpaceVideo"
break
case 209:
params = this.getZhuantiParams(layOutObj, pg, extend)
break
case 172:
let gatherId = extend["tags"] ?? layOutObj
params = {
"gatherId": parseInt(gatherId)
}
url = "/gather/getDetail"
break
default:
break
}
}
let resJson = JSON.parse(await this.post(this.siteUrl + url, this.getParams(params), this.getHeader(), ""))
if (type_id === 172) {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["info"]["videos"])
} else {
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
}
}
async setDetail(id) {
let params = {
"videoId": parseInt(id),
"videoSort": 1
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/videos/getInfo", this.getParams(params), this.getHeader(), ""))
this.vodDetail = await this.parseVodDetailFromDoc(resJson["data"]["info"])
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'imgBt') {
let response = await req(url, {buffer: 0});
return JSON.stringify({
code: 200,
buffer: 2,
content: bt(response.content).replaceAll("data:image/jpeg;base64,", "").replaceAll("data:image/jpg;base64,", "").replaceAll("data:image/png;base64", ""),
headers: headers,
});
}
}
async setSearch(wd, quick, pg) {
let params = {
"page": parseInt(pg),
"length": 12,
"type": 1,
"key": wd
}
let resJson = JSON.parse(await this.post(this.siteUrl + "/base/globalSearch", this.getParams(params), this.getHeader(), ""))
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["infos"])
this.result.setPage(parseInt(pg), resJson["data"]["count"] / 12, 12, resJson["data"]["count"])
}
}
let spider = new HanXiuCaoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider, bt}
+273
View File
@@ -0,0 +1,273 @@
/*
* @File : haoxi.js
* @Author : jade
* @Date : 2024/2/7 14:24
* @Email : [email protected]
* @Software : Samples
* @Desc : 好戏追剧 已失效
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class HaoXiSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://haoxi.vip"
}
getAppName() {
return `好戏追剧`
}
getName() {
return `🌿┃好戏追剧┃🌿`
}
getJSName() {
return "haoxi"
}
getType() {
return 3
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort();
vodShort.vod_id = $(element).find("a")[0].attribs.href
vodShort.vod_name = $(element).find("a")[0].attribs.title
if (vodShort.vod_name === undefined) {
vodShort.vod_name = $($($(element).find("[class=\"thumb-txt cor4 hide\"]")).find("a")).html()
}
vodShort.vod_pic = $(element).find("img")[0].attribs["data-src"]
vodShort.vod_remarks = $($(element).find("[class=\"public-list-prb hide ft2\"]")).html()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"flex bottom4\"]").find("[class=\"public-list-box public-pic-a [swiper]\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"public-list-box public-pic-b [swiper]\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"public-list-box search-box flex rel\"]")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetailElement = $("[class=\"vod-detail style-detail rel cor1 hader0\"]")
let vodDetail = new VodDetail();
vodDetail.vod_pic = $(vodDetailElement).find("img")[0].attribs.src
vodDetail.vod_name = $($(vodDetailElement).find("[class=\"slide-info-title hide\"]")).html()
let elements = $(vodDetailElement).find("[class=\"slide-info hide\"]")
vodDetail.vod_year = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[0]).find("a")[0]).html()
vodDetail.vod_area = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[1]).find("a")[0]).html()
vodDetail.type_name = $($($(elements[0]).find("[class=\"slide-info-remarks\"]")[2]).find("a")[0]).html()
vodDetail.vod_remarks = $(elements[1]).text().replaceAll("备注 :", "")
vodDetail.vod_director = $(elements[2]).text().replaceAll("导演 :", "")
vodDetail.vod_actor = $(elements[3]).text().replaceAll("演员 :", "")
vodDetail.vod_content = $($("[class=\"text cor3\"]")).text()
let playElements = $("[class=\"box-width cor5\"]")
let playFormatElements = playElements.find("[class=\"swiper-slide\"]")
let playUrlElements = playElements.find("[class=\"anthology-list-box none\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElements.length; i++) {
let playFormatElement = playFormatElements[i]
let format_name = playFormatElement.children[1].data
format_name = format_name.replaceAll(" ", "")
vod_play_from_list.push(format_name)
let vodItems = []
if (format_name === "http下载") {
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
if (episodeName !== "复制地址") {
vodItems.push(episodeName + "$" + episodeUrl)
}
}
} else {
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"head flex between no-null header_nav0\"]").find("li")
for (const navElement of navElements) {
let type_name = $($(navElement).find("a")).text()
let type_id = Utils.getStrByRegex(/\/vodtype\/(.*?)\//, $(navElement).find("a")[0].attribs.href)
if (Utils.isNumeric(type_id)) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let elements = $("[class=\"nav-swiper rel\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
let name = $($($(elements[i]).find("[class=\"filter-text bj cor5\"]")[0]).find("span")).html()
if (name !== "已选" && name !== "频道") {
extend_dic["name"] = name
for (const ele of $(elements[i]).find("li")) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
}
}
let sortElments = $("[class=\"site-tabs b-b br\"]")
let extend_dic = {"key": (elements.length + 1).toString(), "name": "排序", "value": []}
extend_dic["value"].push({"n": "全部", "v": "/"})
for (const ele of $(sortElments).find("a")) {
let type_id_list = ele.attribs.href.split("-")
extend_dic["value"].push({"n": $(ele).text(), "v": type_id_list[2]})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (Utils.isNumeric(type_id)) {
let url = this.siteUrl + `/vodshow/${type_id}-----------`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
get_extend_sort_dic(tid) {
return {
"3": 3, "4": 1, "5": 11, "6": 4, "9": 5, "10": 2,
}
}
async setCategory(tid, pg, filter, extend) {
// "1-大陆-hits-Netflix-英语-A----正片--2023/version/4K/"
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
if (extend[key] !== "全部") {
urlParams[extend_dic[key]] = extend[key]
}
}
}
let reqUrl = this.siteUrl + '/vodshow/' + urlParams.join("-");
if (extend[7] !== undefined && extend[7] !== "全部") {
reqUrl = reqUrl + `/version/${extend[7]}/`
}
await this.jadeLog.debug(`分类URL:${reqUrl}`)
let $ = await this.getHtml(reqUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + `/vodsearch/-------------/?wd=${wd}`)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
if (flag !== "http下载") {
let $ = await this.getHtml(this.siteUrl + id)
let playConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/, $.html()))
this.playUrl = playConfig['url']
} else {
this.playUrl = id
}
}
}
let spider = new HaoXiSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+153
View File
@@ -0,0 +1,153 @@
/*
* @File : hscangku.js
* @Author : jade
* @Date : 2024/01/03 19:19
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class HsCangkuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://hsck12.shop/"
}
getName() {
return "🔞┃黄色仓库┃🔞"
}
getAppName() {
return "黄色仓库"
}
getJSName() {
return "hscangku"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"stui-vodlist clearfix\"]").find("li")
for (const vod_element of vodElements) {
let vodShort = new VodShort()
let vodElement = $(vod_element).find("a")[0]
vodShort.vod_id = vodElement.attribs["href"]
vodShort.vod_name = vodElement.attribs["title"]
vodShort.vod_pic = vodElement.attribs["data-original"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let element = $($("[class=\"stui-pannel__head clearfix\"]")[1]).find("h3")
let stui_pannel_bd_element = $("div.stui-pannel-bd > div")
let video_element = stui_pannel_bd_element.find("video")[0]
vodDetail.vod_name = element.text()
vodDetail.vod_pic = video_element.attribs["poster"]
vodDetail.vod_play_from = "黄色仓库"
vodDetail.vod_play_url = $(video_element).find("source")[0].attribs["src"]
return vodDetail
}
async setClasses() {
this.classes = [
{
"type_name": "国产视频",
"type_id": "?type=gc"
},
{
"type_name": "国产新片",
"type_id": "?type=ycgc"
},
{
"type_name": "无码中文字幕",
"type_id": "?type=wz"
},
{
"type_name": "有码中文字幕",
"type_id": "?type=yz"
},
{
"type_name": "日本无码",
"type_id": "?type=rw"
}
]
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid + "&p=" + pg.toString()
let html = await this.fetch(url, null,this.getHeader())
this.limit = 40;
if (html !== null) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
this.total = parseInt($("[class=\"active\"]").find("span").text())
}
}
async setDetail(id) {
let url = this.siteUrl + id
let html = await this.fetch(url,null,this.getHeader())
if (html !== null) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
this.playHeader = {}
}
}
let spider = new HsCangkuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
export {spider}
+709
View File
@@ -0,0 +1,709 @@
/*
* @File : huya.js
* @Author : jade
* @Date : 2024/3/7 9:13
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class HuyaSpider extends Spider {
constructor() {
super();
this.isJustLive = false
this.dataFrom = ""
this.customArea = ""
this.huYaPlayForamtObj = {"AL": "蓝光8M", "TX": "蓝光4M", "HW": "超清", "HS": "流畅"}
this.livePlayForamtObj = {"HD": "蓝光8M", "LD": "蓝光4M", "SD": "超清", "OD": "流畅"}
}
getName() {
return "🐯┃虎牙直播┃🐯"
}
getAppName() {
return "虎牙直播"
}
getJSName() {
return "huya"
}
getType() {
return 3
}
async spiderInit() {
if (this.cfgObj.hasOwnProperty('custom')) {
this.customArea = this.cfgObj.custom;
}
if (this.cfgObj.hasOwnProperty('from')) {
this.dataFrom = this.cfgObj.from;
}
if (this.dataFrom !== 'justlive') {
this.siteUrl = 'https://www.huya.com';
} else {
this.siteUrl = 'http://live.yj1211.work';
this.isJustLive = true;
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit()
}
getHeader() {
let header = super.getHeader();
header["User-Agent"] = Utils.MOBILEUA
return header
}
async setClasses() {
this.classes = [{
"type_id": "1", "type_name": "网游"
}, {"type_id": "2", "type_name": "单机"}, {"type_id": "3", "type_name": "手游"}, {
"type_id": "8", "type_name": "娱乐"
}]
}
async setFilterObj() {
this.filterObj = {
"1": [{
"key": "cateId",
"name": "分类",
"init": "1",
"value": [{"n": "英雄联盟", "v": "1"}, {"n": "CS2", "v": "862"}, {
"n": "穿越火线", "v": "4"
}, {"n": "lol云顶之弈", "v": "5485"}, {"n": "无畏契约", "v": "5937"}, {
"n": "CFHD", "v": "6079"
}, {"n": "逆战", "v": "135"}, {"n": "炉石传说", "v": "393"}, {"n": "DOTA2", "v": "7"}, {
"n": "地下城与勇士", "v": "2"
}, {"n": "魔兽世界", "v": "8"}, {"n": "坦克世界", "v": "802"}, {"n": "DOTA1", "v": "6"}, {
"n": "梦三国", "v": "489"
}, {"n": "魔兽争霸3", "v": "4615"}, {"n": "问道", "v": "107"}, {
"n": "命运方舟", "v": "3058"
}, {"n": "QQ飞车", "v": "9"}, {"n": "星际争霸", "v": "5"}, {
"n": "网游竞技", "v": "100023"
}, {"n": "射击综合游戏", "v": "100141"}, {"n": "暴雪专区", "v": "100043"}, {
"n": "彩虹岛Online", "v": "683"
}, {"n": "剑灵", "v": "897"}, {"n": "军事游戏", "v": "100133"}, {
"n": "冒险岛", "v": "2243"
}, {"n": "暗黑破坏神", "v": "1123"}, {"n": "诛仙3", "v": "1646"}, {
"n": "热血江湖", "v": "387"
}, {"n": "英魂之刃", "v": "1830"}, {"n": "武林外传一世琴缘", "v": "1661"}, {
"n": "起凡:群雄逐鹿", "v": "1612"
}, {"n": "神武4电脑版", "v": "3227"}, {"n": "龙之谷", "v": "15"}, {
"n": "炉石战棋", "v": "5751"
}, {"n": "御龙在天", "v": "675"}, {"n": "逆水寒", "v": "2952"}, {
"n": "千年3", "v": "878"
}, {"n": "永恒之塔", "v": "446"}, {"n": "体育游戏", "v": "100135"}, {
"n": "寻仙", "v": "734"
}, {"n": "战舰世界", "v": "1947"}, {"n": "QQ三国", "v": "1090"}, {
"n": "流放之路", "v": "427"
}, {"n": "反恐精英Online", "v": "1918"}, {"n": "反恐行动online", "v": "861"}, {
"n": "征途", "v": "2715"
}, {"n": "战争雷霆", "v": "624"}, {"n": "丝路传说2", "v": "1026"}, {
"n": "星际战甲", "v": "627"
}, {"n": "NBA2KOL系列", "v": "3959"}, {"n": "九阴真经", "v": "1009"}, {
"n": "跑跑卡丁车", "v": "162"
}, {"n": "诛仙世界", "v": "7749"}, {"n": "QQ华夏", "v": "1878"}, {
"n": "天涯明月刀", "v": "1219"
}, {"n": "大话西游:归来", "v": "8239"}, {"n": "荒野行动PC版", "v": "3185"}, {
"n": "新剑侠情缘", "v": "586"
}, {"n": "剑网3", "v": "900"}, {"n": "生死狙击2", "v": "6091"}, {
"n": "全球使命", "v": "939"
}, {"n": "梦想世界3", "v": "486"}, {"n": "枪神纪", "v": "496"}, {
"n": "新天龙八部", "v": "5671"
}, {"n": "铁甲雄兵", "v": "2765"}, {"n": "神泣", "v": "2531"}, {
"n": "斗战神", "v": "591"
}, {"n": "造梦西游OL", "v": "6815"}, {"n": "天堂", "v": "1966"}, {
"n": "大话西游2", "v": "2975"
}, {"n": "使命召唤:战区", "v": "5911"}, {"n": "希望OL", "v": "1161"}, {
"n": "极光世界 弑神传", "v": "514"
}, {"n": "守望先锋归来", "v": "2174"}, {"n": "QQ自由幻想", "v": "1862"}, {
"n": "命运2", "v": "2942"
}, {"n": "奇迹世界2", "v": "766"}, {"n": "坦克大战", "v": "4359"}, {
"n": "生死狙击", "v": "2471"
}, {"n": "天翼决", "v": "779"}, {"n": "QQ幻想", "v": "2419"}, {
"n": "新飞飞(FlyFF)", "v": "1582"
}, {"n": "刀剑英雄", "v": "915"}, {"n": "FIFA Online系列", "v": "100079"}, {
"n": "全球使命3", "v": "2953"
}, {"n": "完美端游系列", "v": "3034"}, {"n": "战意", "v": "2599"}, {
"n": "泡泡堂", "v": "440"
}, {"n": "赛尔号", "v": "2755"}, {"n": "大唐无双零", "v": "1584"}, {
"n": "QQ炫舞", "v": "2440"
}, {"n": "007:传奇", "v": "1135"}, {"n": "天下", "v": "1597"}, {
"n": "天谕", "v": "1899"
}, {"n": "新倩女幽魂", "v": "1579"}, {"n": "传世无双", "v": "984"}, {
"n": "剑侠世界", "v": "903"
}, {"n": "Warhaven", "v": "9053"}, {"n": "诺亚传说", "v": "190"}, {
"n": "新挑战", "v": "583"
}, {"n": "超激斗梦境", "v": "5691"}, {"n": "QQ音速", "v": "1085"}, {"n": "征途2", "v": "677"}, {
"n": "征程", "v": "678"
}, {"n": "蜀门", "v": "4711"}, {"n": "完美世界:诸神之战", "v": "7217"}, {
"n": "战之刃:幸存者", "v": "8627"
}, {"n": "黎明之光", "v": "41"}, {"n": "天命西游", "v": "1086"}, {
"n": "炫舞时代", "v": "3353"
}, {"n": "荣誉空间", "v": "225"}, {"n": "卡拉彼丘", "v": "9073"}, {
"n": "成吉思汗怀旧版", "v": "640"
}, {"n": "英雄年代3", "v": "1232"}, {"n": "天书奇谈", "v": "2225"}, {
"n": "劲舞团", "v": "2420"
}, {"n": "远征Online梦想版", "v": "142"}, {"n": "奇迹:传奇", "v": "3917"}, {
"n": "封印者", "v": "2294"
}, {"n": "上古世纪", "v": "1046"}, {"n": "梦幻诛仙2", "v": "488"}, {
"n": "TERA Online", "v": "1072"
}, {"n": "倚天Ⅱ", "v": "959"}, {"n": "街头篮球", "v": "206"}, {
"n": "永恒轮回:无限", "v": "7847"
}, {"n": "火线精英", "v": "2550"}, {"n": "忍者村大战2", "v": "2369"}, {
"n": "领地人生", "v": "2282"
}, {"n": "仙侠世界", "v": "995"}, {"n": "洛奇英雄传", "v": "432"}, {
"n": "KARDS", "v": "8261"
}, {"n": "无限法则", "v": "3189"}, {"n": "全面战争:竞技场", "v": "5901"}, {
"n": "自由篮球", "v": "243"
}, {"n": "FC Online4", "v": "3683"}, {"n": "战地之王", "v": "618"}, {
"n": "古剑奇谭OL", "v": "1892"
}, {"n": "QQ仙侠传", "v": "2291"}, {"n": "300英雄", "v": "1132"}]
}], "2": [{
"key": "cateId",
"name": "分类",
"init": "2793",
"value": [{"n": "天天吃鸡", "v": "2793"}, {"n": "永劫无间", "v": "6219"}, {
"n": "主机游戏", "v": "100032"
}, {"n": "猛兽派对", "v": "6165"}, {"n": "互动点播", "v": "5907"}, {
"n": "我的世界", "v": "1732"
}, {"n": "方舟", "v": "1997"}, {"n": "单机热游", "v": "100002"}, {
"n": "怀旧游戏", "v": "100125"
}, {"n": "逃离塔科夫", "v": "3493"}, {"n": "俄罗斯钓鱼4", "v": "5495"}, {
"n": "部落:上升", "v": "1318"
}, {"n": "Dark and Darker", "v": "7905"}, {"n": "The Front", "v": "9497"}, {
"n": "Apex英雄", "v": "5011"
}, {"n": "生化危机4重制版", "v": "8013"}, {"n": "DayZ独立版", "v": "1125"}, {
"n": "星空", "v": "7857"
}, {"n": "互动剧游", "v": "6919"}, {"n": "艾尔登法环", "v": "5801"}, {
"n": "恐惧之间", "v": "6679"
}, {"n": "SCUM", "v": "4245"}, {"n": "Dread Hunger", "v": "7601"}, {
"n": "塞尔达传说:王国之泪", "v": "7883"
}, {"n": "欧洲卡车模拟", "v": "475"}, {"n": "洛克王国", "v": "2864"}, {
"n": "卧龙:苍天陨落", "v": "7859"
}, {"n": "无人深空", "v": "2566"}, {"n": "帝国神话", "v": "6821"}, {
"n": "饥荒", "v": "74"
}, {"n": "森林之子", "v": "7943"}, {"n": "星球大战系列", "v": "554"}, {
"n": "极限竞速:地平线", "v": "2634"
}, {"n": "最终幻想16", "v": "7869"}, {"n": "Among Us", "v": "6163"}, {
"n": "怪物猎人:崛起", "v": "6479"
}, {"n": "怪物猎人物语", "v": "7101"}, {"n": "骑马与砍杀系列", "v": "4783"}, {
"n": "荒野大镖客2", "v": "4319"
}, {"n": "太荒初境", "v": "7685"}, {"n": "罗布乐思", "v": "5771"}, {
"n": "只狼:影逝二度", "v": "4505"
}, {"n": "双人成行", "v": "6737"}, {"n": "重生边缘", "v": "6201"}, {
"n": "海贼王 寻秘世界", "v": "5097"
}, {"n": "战神:诸神黄昏", "v": "7771"}, {"n": "恐鬼症", "v": "6205"}, {
"n": "鬼谷八荒", "v": "6571"
}, {"n": "霍格沃茨之遗", "v": "7881"}, {"n": "全面战争", "v": "3521"}, {
"n": "仁王2", "v": "5795"
}, {"n": "奥拉星", "v": "2846"}, {"n": "甜蜜之家", "v": "6739"}, {
"n": "仙剑奇侠传七", "v": "6509"
}, {"n": "消逝的光芒2", "v": "7581"}, {"n": "渡神记", "v": "6231"}, {
"n": "归家异途", "v": "2949"
}, {"n": "博德之门3", "v": "6147"}, {"n": "看门狗:军团", "v": "6155"}, {
"n": "使命召唤系列", "v": "100137"
}, {"n": "育碧游戏", "v": "100139"}, {"n": "帝国时代4", "v": "4835"}, {
"n": "英灵神殿", "v": "6609"
}, {"n": "蛮荒志异:起源", "v": "9709"}, {"n": "岛", "v": "3019"}, {
"n": "沙盒与副本", "v": "9151"
}, {"n": "扫雷", "v": "2349"}, {"n": "街机游戏", "v": "5999"}, {
"n": "幽灵线:东京", "v": "7669"
}, {"n": "怪物猎人世界", "v": "3519"}, {"n": "盗贼之海", "v": "3641"}, {
"n": "纸人", "v": "5257"
}, {"n": "黑色像素人", "v": "28"}, {"n": "对马岛之魂", "v": "6039"}, {
"n": "瑞奇与叮当", "v": "2455"
}, {"n": "港诡实录", "v": "5853"}, {"n": "剑士", "v": "1467"}, {
"n": "魔法门之英雄无敌系列", "v": "2096"
}, {"n": "星露谷物语", "v": "2443"}, {"n": "仙剑奇侠传四", "v": "1659"}, {
"n": "伤害世界", "v": "2337"
}, {"n": "禁闭求生", "v": "6065"}, {"n": "真三国无双", "v": "1599"}, {
"n": "恐怖黎明", "v": "3435"
}, {"n": "其他单机", "v": "3069"}, {"n": "幽灵行动:荒野", "v": "2794"}, {
"n": "边缘", "v": "151"
}, {"n": "阿凡达", "v": "106"}, {"n": "全面战争:三国", "v": "3004"}, {
"n": "黎明之星", "v": "40"
}, {"n": "翼星求生", "v": "7463"}, {"n": "黎明传说", "v": "39"}, {
"n": "恶魔之魂", "v": "6151"
}, {"n": "艾兰岛", "v": "3855"}, {"n": "龙与地下城:秘影历代记HD", "v": "17"}, {
"n": "龙与地下城:匕首谷", "v": "18"
}, {"n": "沙石镇时光", "v": "7687"}, {"n": "三国志曹操传", "v": "2592"}, {
"n": "FIFA足球", "v": "1888"
}, {"n": "最终幻想7:重制版", "v": "5809"}, {"n": "四海兄弟", "v": "5995"}, {
"n": "最终幻想:起源", "v": "7653"
}, {"n": "摔跤城大乱斗", "v": "7773"}, {"n": "音乐游戏", "v": "2761"}, {
"n": "精灵与萤火意志", "v": "5895"
}, {"n": "桥梁建造师", "v": "3275"}, {"n": "哈迪斯", "v": "6153"}, {
"n": "小缇娜的奇幻之地", "v": "7647"
}, {"n": "宝可梦:剑盾", "v": "5715"}, {"n": "边境", "v": "4779"}, {
"n": "人类一败涂地", "v": "3289"
}, {"n": "糖豆人:终极淘汰赛", "v": "6083"}, {"n": "精灵宝可梦Let's Go", "v": "4375"}, {
"n": "战锤40K:暗潮", "v": "3016"
}, {"n": "石油骚动", "v": "2585"}, {"n": "紫塞秋风", "v": "6045"}, {
"n": "阿尔比恩", "v": "8115"
}, {"n": "猎人:荒野的召唤", "v": "2906"}, {"n": "FIFA 23", "v": "7789"}, {
"n": "都市:天际线", "v": "2201"
}, {"n": "乐高大电影:游戏版", "v": "1439"}, {"n": "全面战争:阿提拉", "v": "2383"}, {
"n": "斩妖行", "v": "6105"
}, {"n": "马里奥赛车8", "v": "5947"}, {"n": "复仇者联盟", "v": "6121"}, {"n": "霓虹深渊", "v": "5743"}]
}], "3": [{
"key": "cateId",
"name": "分类",
"init": "2336",
"value": [{"n": "王者荣耀", "v": "2336"}, {"n": "和平精英", "v": "3203"}, {
"n": "英雄联盟手游", "v": "6203"
}, {"n": "CF手游", "v": "2413"}, {"n": "金铲铲之战", "v": "7185"}, {
"n": "三国杀", "v": "1669"
}, {"n": "原神", "v": "5489"}, {"n": "棋牌桌游", "v": "100036"}, {
"n": "综合手游", "v": "100029"
}, {"n": "劲乐幻想", "v": "7691"}, {"n": "新游广场", "v": "100052"}, {
"n": "崩坏:星穹铁道", "v": "7349"
}, {"n": "火影忍者手游", "v": "2429"}, {"n": "第五人格", "v": "3115"}, {
"n": "问道手游", "v": "2477"
}, {"n": "暗区突围", "v": "7209"}, {"n": "QQ飞车手游", "v": "2928"}, {
"n": "球球大作战", "v": "2411"
}, {"n": "明日之后", "v": "3483"}, {"n": "皇室战争", "v": "2439"}, {
"n": "COD手游", "v": "4769"
}, {"n": "手游休闲", "v": "100004"}, {"n": "二次元手游", "v": "100091"}, {
"n": "摸了个鱼", "v": "9283"
}, {"n": "MMORPG", "v": "100273"}, {"n": "动作游戏", "v": "100197"}, {
"n": "战争冲突", "v": "7449"
}, {"n": "王者模拟战", "v": "5699"}, {"n": "逆水寒手游", "v": "7725"}, {
"n": "幻塔", "v": "6437"
}, {"n": "欢乐斗地主", "v": "1749"}, {"n": "神武4手游", "v": "3135"}, {
"n": "阴阳师", "v": "2598"
}, {"n": "DNF手游", "v": "4921"}, {"n": "欢乐麻将", "v": "1751"}, {
"n": "英雄联盟电竞经理", "v": "7177"
}, {"n": "狼人杀手游", "v": "100049"}, {"n": "新天龙八部手游", "v": "6945"}, {
"n": "中国象棋", "v": "1671"
}, {"n": "天天象棋", "v": "4997"}, {"n": "传奇世界3D", "v": "3961"}, {
"n": "御龙在天手游", "v": "2568"
}, {"n": "高能英雄", "v": "8359"}, {"n": "天龙八部手游", "v": "2852"}, {
"n": "三国志战略版", "v": "5619"
}, {"n": "忍者必须死3", "v": "4041"}, {"n": "SKY光遇", "v": "3719"}, {
"n": "虎牙领主争霸", "v": "7529"
}, {"n": "云上城之歌", "v": "5977"}, {"n": "晶核", "v": "7279"}, {
"n": "仙境传说RO", "v": "2675"
}, {"n": "天天狼人", "v": "2774"}, {"n": "JJ棋牌", "v": "3841"}, {
"n": "奇迹MU:觉醒", "v": "3116"
}, {"n": "指尖四川麻将", "v": "7215"}, {"n": "部落冲突", "v": "1797"}, {
"n": "新剑侠情缘手游", "v": "6259"
}, {"n": "萌宠远征", "v": "9385"}, {"n": "暗黑破坏神:不朽", "v": "6385"}, {
"n": "英雄杀", "v": "2688"
}, {"n": "热血江湖手游", "v": "2817"}, {"n": "蛋仔派对", "v": "6909"}, {
"n": "完美世界手游", "v": "4237"
}, {"n": "巅峰战舰", "v": "2502"}, {"n": "狼人杀", "v": "2785"}, {
"n": "斗罗大陆:魂师对决", "v": "6745"
}, {"n": "武侠乂手游", "v": "4929"}, {"n": "诛仙手游", "v": "2647"}, {
"n": "斗破苍穹手游", "v": "4337"
}, {"n": "迷你世界", "v": "2683"}, {"n": "风云", "v": "3061"}, {
"n": "妄想山海", "v": "6007"
}, {"n": "曙光英雄", "v": "6169"}, {"n": "三国战纪2", "v": "6049"}, {
"n": "梦幻新诛仙", "v": "5975"
}, {"n": "黎明觉醒:生机", "v": "6131"}, {"n": "远征", "v": "7837"}, {
"n": "航海王:燃烧意志", "v": "3943"
}, {"n": "火炬之光:无限", "v": "6399"}, {"n": "巅峰极速", "v": "6979"}, {
"n": "圣境之塔", "v": "7055"
}, {"n": "魔力宝贝", "v": "2891"}, {"n": "香肠派对", "v": "3639"}, {
"n": "创造与魔法", "v": "2931"
}, {"n": "JJ斗地主", "v": "6271"}, {"n": "永恒纪元:戒", "v": "2646"}, {
"n": "天涯明月刀手游", "v": "5115"
}, {"n": "狼人杀官方", "v": "3679"}, {"n": "混沌起源", "v": "5985"}, {
"n": "多多自走棋", "v": "5133"
}, {"n": "梦幻诛仙手游", "v": "2672"}, {"n": "鸿图之下", "v": "6027"}, {
"n": "新笑傲江湖", "v": "5669"
}, {"n": "凡人修仙传:人界篇", "v": "8297"}, {"n": "多乐棋牌", "v": "6209"}, {
"n": "口袋觉醒", "v": "5953"
}, {"n": "跑跑卡丁车手游", "v": "2620"}, {"n": "奶块", "v": "2775"}, {
"n": "月圆之夜", "v": "4339"
}, {"n": "率土之滨", "v": "2691"}, {"n": "征途2手游", "v": "2811"}, {
"n": "英魂之刃口袋版", "v": "2760"
}, {"n": "精灵盛典:黎明", "v": "6123"}, {"n": "方舟手游", "v": "4035"}, {
"n": "掼蛋", "v": "6225"
}, {"n": "绝世仙王", "v": "6619"}, {"n": "流星群侠传", "v": "3927"}, {
"n": "寻仙手游", "v": "2979"
}, {"n": "一梦江湖", "v": "3082"}, {"n": "Lost Light(萤火突击国际服)", "v": "6859"}, {
"n": "弹幕云游戏", "v": "7001"
}, {"n": "猎魂觉醒", "v": "3071"}, {"n": "冒险岛:枫之传说", "v": "8005"}, {
"n": "征途手游", "v": "2556"
}, {"n": "海岛奇兵", "v": "2624"}, {"n": "倩女幽魂手游", "v": "2503"}, {
"n": "超凡先锋", "v": "6507"
}, {"n": "龙之谷2手游", "v": "2736"}, {"n": "崩坏3", "v": "2639"}, {
"n": "猫和老鼠", "v": "2758"
}, {"n": "七人传奇:光与暗之交战", "v": "8125"}, {"n": "JJ麻将", "v": "9487"}, {
"n": "拉轰西游", "v": "9543"
}, {"n": "三国战纪", "v": "6047"}, {"n": "自由幻想手游", "v": "4015"}, {
"n": "秦时明月世界", "v": "5279"
}, {"n": "新斗罗大陆", "v": "6657"}, {"n": "新神魔大陆", "v": "5939"}, {
"n": "逃跑吧!少年", "v": "4137"
}, {"n": "太古神王2", "v": "6649"}, {"n": "剑侠世界3", "v": "7183"}, {
"n": "天天吃鸡手机版", "v": "4341"
}, {"n": "时空猎人3", "v": "6411"}, {"n": "合金弹头:觉醒", "v": "6931"}, {
"n": "明日方舟", "v": "4925"
}, {"n": "原始征途", "v": "7713"}, {"n": "奇迹:最强者", "v": "3215"}, {
"n": "天天酷跑", "v": "1715"
}, {"n": "FC 足球世界", "v": "3873"}, {"n": "万国觉醒", "v": "6159"}, {
"n": "机动都市阿尔法", "v": "5411"
}, {"n": "航海王热血航线", "v": "6181"}, {"n": "幻世九歌", "v": "7199"}, {
"n": "植物大战僵尸", "v": "485"
}, {"n": "无悔华夏", "v": "7063"}, {"n": "时空猎人", "v": "1742"}, {
"n": "荒野乱斗", "v": "4613"
}, {"n": "拳皇98终极之战OL", "v": "2687"}, {"n": "蛇蛇争霸", "v": "2680"}, {
"n": "王牌竞速", "v": "6463"
}, {"n": "重返帝国", "v": "6955"}, {"n": "吞噬星空:黎明", "v": "6651"}, {
"n": "口袋妖怪", "v": "2541"
}, {"n": "QQ炫舞手游", "v": "2991"}, {"n": "一拳超人:最强之男", "v": "4629"}, {
"n": "荣耀新三国", "v": "6943"
}, {"n": "少年三国志2", "v": "6125"}, {"n": "我的起源", "v": "5365"}, {
"n": "决战平安京", "v": "3064"
}, {"n": "剑灵2", "v": "7223"}, {"n": "开心消消乐", "v": "1712"}, {
"n": "小小蚁国", "v": "7803"
}, {"n": "最强NBA", "v": "2988"}, {"n": "剑侠情缘手游", "v": "2621"}, {
"n": "长安幻想", "v": "6727"
}, {"n": "我叫MT4", "v": "4087"}, {"n": "全明星街球派对", "v": "8401"}, {
"n": "大话西游手游", "v": "2626"
}, {"n": "荣耀大天使", "v": "6477"}, {"n": "镇魂街:天生为王", "v": "6557"}, {
"n": "摩尔庄园", "v": "5981"
}, {"n": "游戏王:决斗链接", "v": "4451"}, {"n": "剑侠世界2手游", "v": "3150"}, {
"n": "青云诀2", "v": "6009"
}, {"n": "战地无疆", "v": "7909"}, {"n": "一念逍遥", "v": "6419"}, {
"n": "永劫无间手游", "v": "7579"
}, {"n": "尘白禁区", "v": "7297"}, {"n": "元梦之星", "v": "9521"}, {
"n": "不良人3", "v": "5891"
}, {"n": "剑灵:革命", "v": "4545"}, {"n": "魔力宝贝:旅人", "v": "7573"}, {
"n": "米加小镇", "v": "7269"
}, {"n": "龙武手游", "v": "5219"}, {"n": "斗罗大陆2:绝世唐门", "v": "6581"}, {
"n": "西行纪燃魂", "v": "8303"
}, {"n": "坦克世界闪击战", "v": "4977"}, {"n": "军棋", "v": "2561"}, {
"n": "饥荒:新家", "v": "6491"
}, {"n": "拳皇命运", "v": "3379"}, {"n": "实况足球", "v": "3741"}, {
"n": "战舰世界闪击战", "v": "4101"
}, {"n": "时空召唤", "v": "2551"}, {"n": "王牌战争:文明重启", "v": "5479"}, {
"n": "雀魂麻将", "v": "7107"
}, {"n": "欢乐升级", "v": "3925"}, {"n": "绿色征途", "v": "4227"}, {
"n": "弹弹堂手游", "v": "2857"
}, {"n": "太极熊猫3:猎龙", "v": "2778"}, {"n": "哈利波特:魔法觉醒", "v": "5835"}, {
"n": "天地劫:幽城再临", "v": "5987"
}, {"n": "热血街篮", "v": "5859"}, {"n": "神雕侠侣手游", "v": "1781"}, {
"n": "山海镜花", "v": "5089"
}, {"n": "三国志战棋版", "v": "7937"}, {"n": "神雕侠侣2", "v": "4209"}, {
"n": "仙魔决", "v": "1674"
}, {"n": "王者荣耀星之破晓", "v": "7927"}, {"n": "我在江湖之神魔道", "v": "7699"}, {
"n": "梦幻模拟战", "v": "3481"
}, {"n": "单机手游", "v": "2777"}, {"n": "斗罗大陆-斗神再临", "v": "6631"}, {
"n": "未来之役", "v": "6831"
}, {"n": "风云岛行动", "v": "4695"}, {"n": "新游推荐", "v": "3160"}, {
"n": "火影忍者OL", "v": "3901"
}, {"n": "九灵神域", "v": "7719"}, {"n": "武动乾坤", "v": "3829"}, {
"n": "秦时明月2", "v": "1784"
}, {"n": "文明与征服", "v": "7071"}, {"n": "战双:帕弥什", "v": "4133"}, {
"n": "大航海时代:海上霸主", "v": "6929"
}, {"n": "剑网1:归来", "v": "7361"}, {"n": "绝区零", "v": "7711"}, {
"n": "黑色沙漠手游", "v": "7287"
}, {"n": "虎牙吃鸡", "v": "7465"}, {"n": "一剑斩仙", "v": "6843"}, {
"n": "传奇天下", "v": "6927"
}, {"n": "斗斗堂", "v": "7133"}, {"n": "斗罗大陆", "v": "6119"}, {
"n": "天谕手游", "v": "5925"
}, {"n": "坎公骑冠剑", "v": "6641"}, {"n": "最终幻想觉醒", "v": "2721"}, {
"n": "神将三国", "v": "6621"
}, {"n": "灌篮高手正版授权手游", "v": "5399"}, {"n": "剑与家园", "v": "2838"}, {
"n": "极无双2", "v": "7825"
}, {"n": "光明大陆", "v": "2832"}, {"n": "荒野行动", "v": "3084"}, {
"n": "战斗法则", "v": "9513"
}, {"n": "疯狂原始人", "v": "4619"}, {"n": "逆战手游", "v": "7575"}, {
"n": "石器时代:觉醒", "v": "9159"
}]
}], "8": [{
"key": "cateId",
"name": "分类",
"init": "1663",
"value": [{"n": "星秀", "v": "1663"}, {"n": "户外", "v": "2165"}, {
"n": "一起看", "v": "2135"
}, {"n": "二次元", "v": "2633"}, {"n": "虚拟偶像", "v": "6055"}, {"n": "旅游", "v": "6791"}, {
"n": "放映厅", "v": "6245"
}, {"n": "娱乐天地", "v": "100022"}, {"n": "交友", "v": "4079"}, {
"n": "组队", "v": "5367"
}, {"n": "吃喝玩乐", "v": "100044"}, {"n": "原创", "v": "6861"}, {
"n": "虎牙文化", "v": "4089"
}, {"n": "体育", "v": "2356"}, {"n": "虎牙地方", "v": "5123"}, {"n": "颜值", "v": "2168"}, {
"n": "科技", "v": "2408"
}, {"n": "音乐", "v": "3793"}, {"n": "趣分享", "v": "5883"}, {"n": "一起买", "v": "7759"}, {
"n": "派对", "v": "7785"
}]
}],
};
if (this.customArea.length > 0) {
const filterCfg = this.customArea.split('#');
this.classes.unshift({"type_id": "custom", "type_name": "自选"});
const filterList = _.map(filterCfg, (it) => {
const filterKv = it.split(',');
return {
n: filterKv[1], v: filterKv[0],
};
});
const defKey = filterList[0];
this.filterObj["custom"] = [{"key": "cateId", "name": "分类", "init": defKey.v, "value": filterList}];
}
if (this.isJustLive) {
// key-value映射修改
const filterKeys = Object.keys(this.filterObj);
for (const filterKey of filterKeys) {
const filterItem = this.filterObj[filterKey];
for (const typeItem of filterItem) {
typeItem.value = _.map(typeItem.value, (it) => {
// 修改默认值
if (it.v === typeItem.init) {
typeItem.init = it.n;
}
return {
n: it.n, v: it.n,
};
});
}
}
}
this.classes.unshift({"type_id": "home", "type_name": "首页"});
}
async setHome(filter) {
await this.setClasses()
await this.setFilterObj()
}
async parseVodShortListFromJson(obj) {
let vod_list = []
if (this.isJustLive) {
for (const it of obj["data"]) {
let vodShort = new VodShort()
vodShort.vod_id = it["roomId"]
vodShort.vod_name = it["ownerName"] + it["roomName"]
vodShort.vod_pic = it["roomPic"]
vodShort.vod_remarks = it["categoryName"]
vod_list.push(vodShort)
}
} else {
for (const it of obj.data.datas) {
let vodShort = new VodShort()
vodShort.vod_id = it["profileRoom"]
vodShort.vod_name = it["nick"] + it["introduction"]
vodShort.vod_pic = it["screenshot"]
vodShort.vod_remarks = it["gameFullName"]
vod_list.push(vodShort)
}
}
return vod_list
}
getPlayUrlData(streamInfo, ratio) {
const hlsUrl = streamInfo["sHlsUrl"] + '/' + streamInfo["sStreamName"] + '.' + streamInfo["sHlsUrlSuffix"];
const srcAntiCode = unescape(streamInfo["sHlsAntiCode"]);
let codeList = srcAntiCode.split('&');
codeList = codeList.filter(code => code !== '');
let cryptoInfo = {};
for (const code of codeList) {
const [k, v] = code.split('=');
cryptoInfo[k] = v;
}
const fm = Utils.unquote(cryptoInfo["fm"]);
const fmDecoded = Utils.base64Decode(fm);
const hashPrefix = fmDecoded.split('_')[0];
const ctype = cryptoInfo["ctype"] || '';
const txyp = cryptoInfo["txyp"] || '';
const fs = cryptoInfo.fs || '';
const t = cryptoInfo.t || '';
const u = 1463993859134;
const curTime = Date.now();
const seqid = Math.floor(curTime + u);
const wsTime = (Math.floor(curTime / 1e3) + 3600).toString(16);
const v0 = seqid + '|' + ctype + '|' + t;
const v1 = Utils.md5Encode(v0);
const v2 = hashPrefix + '_' + u + '_' + streamInfo["sStreamName"] + '_' + v1 + '_' + wsTime;
const hash = Utils.md5Encode(v2);
// ratio = ""
const purl = `${hlsUrl}?wsSecret=${hash}&wsTime=${wsTime}&seqid=${seqid}&ctype=${ctype}&ver=1&txyp=${txyp}&fs=${fs}&ratio=${ratio}&u=${u}&t=${t}&sv=2107230339`;
return {
cdnType: streamInfo["sCdnType"], playUrl: purl,
};
}
async parseVodDetailfromJson(liveInfo, streamInfoList, bitInfoList) {
let vodDetail = new VodDetail()
vodDetail.vod_name = liveInfo["introduction"] ?? liveInfo["sIntroduction"]
vodDetail.vod_pic = liveInfo["screenshot"] ?? liveInfo["sScreenshot"]
vodDetail.vod_remarks = liveInfo["gameFullName"] ?? liveInfo["sGameFullName"]
vodDetail.type_name = liveInfo["gameFullName"] ?? liveInfo["sGameFullName"]
vodDetail.vod_director = liveInfo["nick"] ?? liveInfo["sNick"]
vodDetail.vod_content = liveInfo["activityCount"] ?? liveInfo["lActivityCount"]
vodDetail.vod_content = vodDetail.vod_content + '人在线'
let vod_play_from_list = []
let vod_play_list = []
for (const streamInfo of streamInfoList) {
let vodItems = []
for (const bitinfo of bitInfoList) {
let format_name = this.huYaPlayForamtObj[streamInfo["sCdnType"]]
if (format_name === bitinfo["sDisplayName"]) {
const urlData = this.getPlayUrlData(streamInfo, bitinfo["iBitRate"]);
vod_play_from_list.push(format_name)
vodItems.push("虎牙直播" + '$' + urlData["playUrl"])
vod_play_list.push(vodItems.join("#"))
break
}
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodDetailFromDoc(vodData, playData) {
let vodDetail = new VodDetail()
vodDetail.vod_name = vodData["data"]["roomName"]
vodDetail.vod_director = vodData["data"]["ownerName"]
vodDetail.vod_pic = vodData["data"]["roomPic"]
vodDetail.vod_remarks = vodData["data"]["categoryName"]
vodDetail.vod_content = vodData["data"]["online"] + "人在线"
let vod_play_from_list = []
let vod_play_list = []
for (const key of Object.keys(this.livePlayForamtObj)) {
let vodItems = []
if (playData.data.hasOwnProperty(key)) {
vod_play_from_list.push(this.livePlayForamtObj[key])
vodItems.push("JustLive" + '$' + playData["data"][key])
vod_play_list.push(vodItems.join("#"))
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodShortListFromDocBySearch(data) {
let vod_list = [];
for (const vod of data.response['3']["docs"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod["room_id"]
vodShort.vod_name = vod["game_nick"] + vod["game_introduction"]
vodShort.vod_pic = vod["game_screenshot"]
vodShort.vod_remarks = vod["game_name"]
vod_list.push(vodShort)
}
return vod_list
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0 || typeof pg == 'undefined') pg = 1;
let url = '';
let data = {}
if (this.isJustLive) {
if (tid === 'home') {
url = this.siteUrl + '/api/live/getRecommendByPlatform?platform=huya&size=20&page=' + pg;
} else {
url = this.siteUrl + '/api/live/getRecommendByPlatformArea?platform=huya&size=20&area=' + extend.cateId + '&page=' + pg;
}
data = JSON.parse(await this.fetch(url, null, this.getHeader()));
} else {
if (tid === 'home') {
url = this.siteUrl + '/cache.php?m=LiveList&do=getLiveListByPage&tagAll=1&page=' + pg;
} else {
url = this.siteUrl + '/cache.php?m=LiveList&do=getLiveListByPage&gameId=' + extend["cateId"] + '&tagAll=0&page=' + pg;
}
data = JSON.parse(await this.fetch(url, null, this.getHeader()));
}
this.vodList = await this.parseVodShortListFromJson(data)
}
async setDetail(id) {
let liveInfo = null;
let streamInfoList = null;
if (this.isJustLive) {
await this.jadeLog.debug("JustLive", true)
const vodInfo = await this.fetch(this.siteUrl + `/api/live/getRoomInfo?platform=huya&roomId=${id}`, null, this.getHeader())
const playInfo = await this.fetch(this.siteUrl + `/api/live/getRealUrl?platform=huya&roomId=${id}`, null, this.getHeader())
const vodData = JSON.parse(vodInfo);
const playData = JSON.parse(playInfo)
this.vodDetail = await this.parseVodDetailFromDoc(vodData, playData)
} else {
await this.jadeLog.debug("虎牙直播", true)
const resp = await this.fetch('https://mp.huya.com/cache.php?m=Live&do=profileRoom&roomid=' + id, null, this.getHeader());
const data = JSON.parse(resp);
liveInfo = data.data["liveData"];
let bitInfo = JSON.parse(liveInfo["bitRateInfo"])
streamInfoList = data.data.stream["baseSteamInfoList"];
this.vodDetail = await this.parseVodDetailfromJson(liveInfo, streamInfoList, bitInfo)
}
/** 网页链接
*
* await this.jadeLog.debug("虎牙直播",true)
* const headers = {
* 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': Utils.MOBILEUA,
* };
* let content = await this.fetch('https://m.huya.com/' + id, null, headers);
* let liveData = JSON.parse(Utils.getStrByRegex(/<script> window.HNF_GLOBAL_INIT = (.*?)<\/script>/, content))
* const vodData = liveData["roomInfo"];
* liveInfo = vodData["tLiveInfo"];
* streamInfoList = vodData["tLiveInfo"]["tLiveStreamInfo"]["vStreamInfo"]["value"]
* let bitInfoList = vodData["tLiveInfo"]["tLiveStreamInfo"]["vBitRateInfo"]["value"]
* this.vodDetail = await this.parseVodDetailfromJson(liveInfo, streamInfoList, bitInfoList)
* */
}
async setSearch(wd, quick) {
const resp = await this.fetch('https://search.cdn.huya.com/?m=Search&do=getSearchContent&q=' + wd + '&uid=0&v=4&typ=-5&livestate=0&rows=40&start=0', null, this.getHeader());
const data = JSON.parse(resp);
this.vodList = await this.parseVodShortListFromDocBySearch(data)
}
}
let spider = new HuyaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+319
View File
@@ -0,0 +1,319 @@
/*
* @File : ikanbot.js
* @Author : jade
* @Date : 2024/1/15 10:32
* @Email : [email protected]
* @Software : Samples
* @Desc : 爱看机器人(已失效:上盾)
*/
import {Spider} from "./spider.js";
import {load, _} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
function _0xf746(_0xbb40c4, _0x1cb776) {
const _0x45e084 = _0x45e0();
return _0xf746 = function (_0xf74696, _0x4d32af) {
_0xf74696 = _0xf74696 - 0x1a8;
let _0xcbfa28 = _0x45e084[_0xf74696];
return _0xcbfa28;
}, _0xf746(_0xbb40c4, _0x1cb776);
}
function _0x45e0() {
const _0x58b10c = ['1580630GngmmA', '117uvwflw', 'join', 'current_id', '565448Apkhig', '23092JwmytW', '707152yowhOv', 'getElementById', '855936CGaczt', 'length', '2966831GCGpvn', '611266nfcTEf', 'value', 'substring'];
_0x45e0 = function () {
return _0x58b10c;
};
return _0x45e0();
}
(function (_0x27923d, _0x43d7fc) {
const _0x439396 = _0xf746, _0x30f164 = _0x27923d();
while (!![]) {
try {
const _0xa560eb = -parseInt(_0x439396(0x1b4)) / 0x1 + parseInt(_0x439396(0x1ad)) / 0x2 + -parseInt(_0x439396(0x1b1)) / 0x3 * (-parseInt(_0x439396(0x1b5)) / 0x4) + -parseInt(_0x439396(0x1b0)) / 0x5 + parseInt(_0x439396(0x1aa)) / 0x6 + parseInt(_0x439396(0x1ac)) / 0x7 + parseInt(_0x439396(0x1a8)) / 0x8;
if (_0xa560eb === _0x43d7fc) break; else _0x30f164['push'](_0x30f164['shift']());
} catch (_0x3ae316) {
_0x30f164['push'](_0x30f164['shift']());
}
}
}(_0x45e0, 0x4a3d9));
function get_tks(play_id, e_token) {
const _0xf07220 = _0xf746;
let _0x35162d = play_id, _0xf25678 = e_token;
if (!_0x35162d || !_0xf25678) return;
let _0x3882a3 = _0x35162d['length'], _0x52a097 = _0x35162d[_0xf07220(0x1af)](_0x3882a3 - 0x4, _0x3882a3),
_0x2d9d1b = [];
for (let _0x570711 = 0x0; _0x570711 < _0x52a097[_0xf07220(0x1ab)]; _0x570711++) {
let _0x23e537 = parseInt(_0x52a097[_0x570711]), _0x48b93d = _0x23e537 % 0x3 + 0x1;
_0x2d9d1b[_0x570711] = _0xf25678[_0xf07220(0x1af)](_0x48b93d, _0x48b93d + 0x8), _0xf25678 = _0xf25678[_0xf07220(0x1af)](_0x48b93d + 0x8, _0xf25678[_0xf07220(0x1ab)]);
}
return _0x2d9d1b[_0xf07220(0x1b2)]('');
}
class IKanBotSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://v.ikanbot.com"
}
getName() {
return `🤖┃爱看机器人┃🤖`
}
getAppName() {
return "爱看机器人"
}
getJSName() {
return "ikanbot"
}
getType() {
return 3
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromDoc($) {
let vod_list = [];
let VodShortElements = $($("[class=\"row list-wp\"]")).find("a")
for (const vodShortElement of VodShortElements) {
let vodShort = new VodShort()
let reElement = $(vodShortElement).find("img")[0]
vodShort.vod_id = vodShortElement.attribs["href"]
vodShort.vod_pic = this.jsBase + Utils.base64Encode(reElement.attribs["data-src"])
vodShort.vod_name = reElement.attribs["alt"]
vod_list.push(vodShort)
}
return vod_list
}
getChildren(detail, index) {
try {
return detail[index].children[0].data;
} catch (e) {
return ""
}
}
async parseVodDetailFromDoc($) {
const detail = $('div.detail > .meta');
let vodDetail = new VodDetail();
vodDetail.vod_pic = this.jsBase + Utils.base64Encode($('div.item-root > img')[0].attribs['data-src'])
vodDetail.vod_name = this.getChildren(detail, 0)
vodDetail.vod_year = this.getChildren(detail, 1)
vodDetail.vod_area = this.getChildren(detail, 3);
vodDetail.vod_actor = this.getChildren(detail, 4);
let id = Utils.getStrByRegex(/<input type="hidden" id="current_id" value="(.*?)"/, $.html())
let token = Utils.getStrByRegex(/<input type="hidden" id="e_token" value="(.*?)"/, $.html())
let mtype = Utils.getStrByRegex(/<input type="hidden" id="mtype" value="(.*?)"/, $.html())
let params = {
"videoId": id, "mtype": mtype, "token": get_tks(id, token),
}
let content = await this.fetch(this.siteUrl + '/api/getResN', params, this.getHeader())
const list = JSON.parse(content)["data"]["list"];
let playlist = {};
let index = 0
let form_list = []
for (const l of list) {
const flagData = JSON.parse(l["resData"]);
for (const f of flagData) {
index = index + 1
const from = f.flag;
const urls = f.url;
if (!from || !urls) continue;
if (playlist[from]) continue;
form_list.push(`线路${index}`)
playlist[from] = urls;
}
}
vodDetail.vod_play_from = form_list.join('$$$');
vodDetail.vod_play_url = _.values(playlist).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
const items = $('div.media > div.media-left > a');
for (const item of items) {
let vodShort = new VodShort();
const img = $(item).find('img:first')[0];
vodShort.vod_id = item.attribs.href
vodShort.vod_name = img.attribs.alt
vodShort.vod_pic = this.jsBase + Utils.base64Encode(img.attribs['data-src'])
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let html = await this.fetch(this.siteUrl + "/category", null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let classElements = $($($("[class=\"row visible-xs-block visible-sm-block\"]")).find("li")).find("a")
for (const classElement of classElements) {
this.classes.push({"type_name": $(classElement).text(), "type_id": classElement.attribs["href"]})
}
}
}
async setFilterObj() {
for (const class_dic of this.classes.slice(1, 9)) {
let type_id = class_dic["type_id"]
if (type_id.indexOf("category") === -1 || type_id.indexOf(",") > -1) {
let type_url = type_id.split(",").slice(-1)[0]
let html = await this.fetch(this.siteUrl + type_url, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let containerElement = $("[class=\"row visible-xs-block visible-sm-block\"]")
let filterElements = containerElement.find("[class=\"nav nav-pills\"]").find("a")
let value_list = []
if (type_id.indexOf(",") > -1) {
value_list.push({"n": "全部", "v": type_id.split(",")[0]})
}
let extend_dic = {
"key": type_id, "name": $(containerElement.find("h5")).text(), "value": value_list
}
for (const filterElement of filterElements) {
value_list.push({"n": $(filterElement).text(), "v": filterElement.attribs["href"]})
}
if (value_list.length > 0) {
this.filterObj[type_id] = [extend_dic]
}
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let categoryUrl = (this.siteUrl + (extend[tid] || tid.split(",")[0]))
let update_page = false
if (categoryUrl.indexOf("html") > -1) {
categoryUrl = categoryUrl.replace('.html', pg > 1 ? `-p-${pg}.html` : '.html');
} else {
categoryUrl = categoryUrl + `?p=${pg}`
update_page = true
}
await this.jadeLog.debug(`分类URL:${categoryUrl}`)
let html = await this.fetch(categoryUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let pageDoc = $('div.page-more > a:contains(下一页)')
if (update_page) {
this.page = parseInt(pageDoc[0].attribs["href"].split("p=")[1])
}
const hasMore = pageDoc.length > 0;
this.limit = 24
this.count = hasMore ? parseInt(pg) + 1 : parseInt(pg);
this.total = this.limit * this.count
}
}
async setDetail(id) {
let html = await this.fetch(this.siteUrl + id, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setSearch(wd, quick) {
const html = await this.fetch(this.siteUrl + '/search?q=' + wd, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = id
}
}
let spider = new IKanBotSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+317
View File
@@ -0,0 +1,317 @@
/*
* @File : jable.js
* @Author : jade
* @Date : 2024/3/4 9:44
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class JableTVSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://jable.tv"
this.cookie = ""
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getImgHeaders());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getImgHeaders());
}
}
getImgHeaders(){
return {
"User-Agent": "PostmanRuntime/7.37.3",
"Postman-Token": "c2602692-1a05-4bb0-93cd-270afad97e87",
"Host": "assets-cdn.jable.tv",
"Proxy": true
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getAppName() {
return "Jable"
}
getName() {
return "🔞┃Jable┃🔞"
}
getJSName() {
return "jable"
}
getType() {
return 3
}
getHeader() {
// let header = super.getHeader()
let header = {}
header["User-Agent"] = "PostmanRuntime/7.36.3"
header["Host"] = "jable.tv"
header["Postman-Token"] = "33290483-3c8d-413f-a160-0d3aea9e6f95"
return header
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
return super.getHtml(url, true, headers);
}
async setClasses() {
let $ = await this.getHtml(this.siteUrl)
let navElements = $("[class=\"title-box\"]")
let defaultTypeIdElements = $("div.row")
for (const navElement of $(defaultTypeIdElements[0]).find("a")) {
let type_name = $(navElement).text()
let type_id = navElement.attribs.href
if (type_id.indexOf(this.siteUrl) > -1) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
navElements = navElements.slice(1, 9)
defaultTypeIdElements = defaultTypeIdElements.slice(1, 9)
for (let i = 0; i < navElements.length; i++) {
let typeId = $(defaultTypeIdElements[i]).find("a")[0].attribs["href"]
this.classes.push(this.getTypeDic("标签", typeId));
break
}
}
async getSortFilter($) {
let sortElements = $("[class=\"sorting-nav\"]").find("a")
let extend_dic = {"name": "排序", "key": "sort", "value": []}
for (const sortElement of sortElements) {
let typeId = sortElement.attribs["data-parameters"].split("sort_by:")[1]
let typeName = $(sortElement).text()
extend_dic["value"].push({"n": typeName, "v": typeId})
}
return extend_dic
}
async getFilter($, index, type_id, type_name) {
let extend_list = []
if (index < 4) {
let extend_dic = {"name": type_name, "key": "type", "value": []}
let type_seletc_list = ["div.img-box > a", "[class=\"horizontal-img-box ml-3 mb-3\"] > a", "", "sort"]
let type_id_select_list = ["div.absolute-center > h4", "div.detail"]
let default$ = await this.getHtml(type_id)
for (const element of default$(type_seletc_list[index])) {
let typeId = element.attribs["href"]
let typeName = $($(element).find(type_id_select_list[index])).text().replaceAll("\t", "").replaceAll("\n", '').replaceAll(" ", "");
extend_dic["value"].push({"n": typeName, "v": typeId})
}
if (extend_dic.value.length > 0) {
extend_list.push(extend_dic)
//排序
let sortDetail$ = await this.getHtml(extend_dic["value"][0]["v"])
let sort_extend_dic = await this.getSortFilter(sortDetail$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
} else {
//排序
let sort_extend_dic = await this.getSortFilter(default$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
}
} else {
let defaultTypeIdElements = $("div.row").slice(1, 9)
let navElements = $("[class=\"title-box\"]").slice(1, 9)
for (let i = 0; i < navElements.length; i++) {
let extend_dic = {"name": $($(navElements[i]).find("h2")).text(), "key": "type", "value": []}
for (const filterElement of $(defaultTypeIdElements[i]).find("a")) {
let filter_type_id = filterElement.attribs.href
if (filter_type_id.indexOf(this.siteUrl) > -1) {
extend_dic["value"].push({"n": $(filterElement).text(), "v": filter_type_id})
}
}
extend_list.push(extend_dic)
}
let sortDetail$ = await this.getHtml(type_id)
let sort_extend_dic = await this.getSortFilter(sortDetail$)
if (sort_extend_dic.value.length > 0) {
extend_list.push(sort_extend_dic)
}
}
return extend_list
}
async setFilterObj() {
let $ = await this.getHtml(this.siteUrl)
let classes = this.classes.slice(1)
for (let i = 0; i < classes.length; i++) {
let type_name = classes[i].type_name
let type_id = classes[i].type_id
// if (type_id.indexOf("models") > 1) {
// type_id = `https://jable.tv/models/?mode=async&function=get_block&block_id=list_models_models_list&sort_by=total_videos&_=${new Date().getTime()}`
// }
let extend_list = await this.getFilter($, i, type_id, type_name)
if (extend_list.length > 1 && i < 4) {
type_id = extend_list[0]["value"][0]["v"]
this.classes[i + 1] = this.getTypeDic(type_name, type_id)
}
this.filterObj[type_id] = extend_list
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("div.video-img-box")
for (const element of vodElements) {
let vodShort = new VodShort()
let vod_pic = $(element).find("img").attr("data-src")
if (vod_pic !== undefined) {
vodShort.vod_pic = vod_pic
// if (this.catOpenStatus) {
// vodShort.vod_pic = this.jsBase + Utils.base64Encode(vod_pic)
// } else {
// vodShort.vod_pic = vod_pic
// }
let url = $(element).find("a").attr("href");
vodShort.vod_id = url.split("/")[4];
vodShort.vod_name = url.split("/")[4];
let remarks_list = $($(element).find("[class=\"sub-title\"]")).text().split("\n")
if (remarks_list.length > 1) {
vodShort.vod_remarks = remarks_list[1].replaceAll(" ", "").replaceAll("\t", "")
} else {
vodShort.vod_remarks = "精选"
}
if (!_.isEmpty(vodShort.vod_pic) && vodShort.vod_remarks !== "[限時優惠]只需1元即可無限下載") {
vod_list.push(vodShort);
}
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let leftElement = $("[class=\"header-left\"]")
vodDetail.vod_name = $($(leftElement).find("h4")).text();
let vod_pic = Utils.getStrByRegex(/<video poster="(.*?)" id=/, $.html())
vodDetail.vod_pic = vod_pic
// if (this.catOpenStatus) {
// vodDetail.vod_pic = this.jsBase + Utils.base64Encode(vod_pic)
// } else {
// vodDetail.vod_pic = vod_pic
// }
vodDetail.vod_year = $($("[class=\"inactive-color\"]")).text()
let episodeName = $($("[class=\"header-right d-none d-md-block\"] > h6")).text().replaceAll("\n", "").replaceAll("●", "")
let vodItems = []
let episodeUrl = Utils.getStrByRegex(/var hlsUrl = '(.*?)';/, $.html())
vodItems.push(episodeName + "$" + episodeUrl)
let vod_play_list = []
vod_play_list.push(vodItems.join("#"))
let vod_play_from_list = ["Jable"]
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + "/videos/" + id + "/")
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let extend_type = extend["type"] ?? tid
let sort_by = extend["sort"] ?? "video_viewed"
this.limit = 24
let cateUrl;
this.total = 0
this.count = 0
if (tid.indexOf("latest-updates") > 1) {
cateUrl = `https://jable.tv/latest-updates/?mode=async&function=get_block&block_id=list_videos_latest_videos_list&sort_by=post_date&from=${pg}&_=1709730132217`
} else {
cateUrl = extend_type + `/${pg}/?mode=async&function=get_block&block_id=list_videos_common_videos_list&sort_by=${sort_by}&_=${new Date().getTime()}`
}
let $ = await this.getHtml(cateUrl);
this.vodList = await this.parseVodShortListFromDoc($)
let page = $($("[class=\"page-item\"]").slice(-1)[0]).text()
if (page.indexOf("最後") > -1) {
} else {
if (parseInt(page) === this.page || _.isEmpty(page)) {
await this.jadeLog.debug("分类页面到底了")
this.total = this.page
this.count = this.page
}
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + `/search/${wd}/`
let $ = await this.getHtml(searchUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new JableTVSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+295
View File
@@ -0,0 +1,295 @@
/*
* @File : jiafeimao.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : [email protected]
* @Software : Samples
* @Desc : 加菲猫 (已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class JiaFeiMaoSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://jfmys.app"
}
getAppName() {
return "加菲猫"
}
getName() {
return `🐈┃加菲猫┃🐈`
}
getJSName() {
return "jiafeimao"
}
getType() {
return 3
}
getPic(url){
if (url.indexOf("http:") > -1 || url.indexOf("https:") > -1){
return url
}else{
return this.siteUrl + url
}
}
parseVodShortFromElement($, element) {
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/id\/(.*?)\//,$(element).find("a")[0].attribs.href)
vodShort.vod_name = $(element).find("a")[0].attribs.title
vodShort.vod_pic = this.getPic($(element).find("img")[0].attribs["data-src"])
vodShort.vod_remarks = $($(element).find("[class=\"v-tips\"]")).html()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $(".icon > .container").find("[class=\"imain clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"tv-list clearfix\"]").find("li")
for (const vodElement of vodElements) {
let vodShort = this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $($("[class=\"iptit\"]").find("h3")).html().split(" ")[0]
vodDetail.vod_content = $($("[class=\"idetail container\"]").find("[class=\"infor_intro\"]")).text()
let vodPlayElements = $("[class=\"fjcon\"]")
let vod_play_from_list = []
let vod_play_list = []
let playFormatElemets = $($(vodPlayElements).find("[class=\"fjtop clearfix\"]")).find("a")
let playUrlElements = $(vodPlayElements).find("[class=\"xjn_ul play-list\"]")
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push("线路" +( i+1).toString())
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
parseVodDetail(vod_data) {
let vodDetail = new VodDetail()
vodDetail.vod_name = vod_data["vod_name"]
vodDetail.vod_pic = this.getPic(vod_data["vod_pic"])
vodDetail.vod_remarks = vod_data["vod_remarks"]
vodDetail.vod_area = vod_data["vod_area"]
vodDetail.vod_year = vod_data["vod_year"]
vodDetail.vod_actor = vod_data["vod_actor"]
vodDetail.vod_director = vod_data["vod_director"]
vodDetail.vod_content = vod_data["vod_content"].replaceAll("<p>","").replaceAll("</p>","")
let vod_play_from = []
for (let i = 0; i < vod_data["vod_play_from"].split("$$$").length; i++) {
vod_play_from.push("线路"+(i+1).toString())
}
vodDetail.vod_play_from = vod_play_from.join("$$$")
vodDetail.vod_play_url = vod_data["vod_play_url"]
vodDetail.type_name = vod_data["type_name"]
return vodDetail
}
async parseVodDetailfromJson(obj) {
let vodDetail;
let vod_data_list = obj["list"]
if (vod_data_list.length > 0) {
let vod_data = vod_data_list[0]
vodDetail = this.parseVodDetail(vod_data)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"tv-bd search-list\"]").find("[class=\"item clearfix\"]")
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/id\/(.*?).html/, $($(vodElement).find("[class=\"s_tit\"]")).find("a")[0].attribs.href)
vodShort.vod_name = $($($(vodElement).find("[class=\"s_tit\"]")).find("a")).text()
vodShort.vod_pic = this.getPic($(vodElement).find("img")[0].attribs.src)
vodShort.vod_remarks = $($(vodElement).find("[class=\"s_score\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let $ = await this.getHtml()
let content = $($("[class=\"container\"]").find("script")).html()
let navContent = Utils.getStrByRegex(/document.write\('(.*?);/, content)
for (const navElement of $(navContent).find("a")) {
let type_id = navElement.attribs["href"]
let type_name = $(navElement).text()
if (type_id !== "/" && type_name !== "专题" && type_name !== "站长模板") {
this.classes.push(this.getTypeDic(type_name, Utils.getStrByRegex(/id\/(.*?).html/, type_id)))
}
}
}
async getFilter($) {
let elements = $($("[class=\"container\"]").find("[class=\"select_list clearfix\"]")).find("li")
let extend_list = []
let key_value_dic = {
"分类": /id\/(.*?).html/,
"地区": /area\/(.*?)\//,
"年份": /year\/(.*?).html/,
"字母": /letter\/(.*?).html/,
"排序": /by\/(.*?)\//,
}
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
let name = $($($(element).find("[class=\"v-tit\"]"))).text().replaceAll("", "")
if (name !== "频道") {
let extend_dic = {"key": (i + 1).toString(), "name": name, "value": []}
for (const ele of $(element).find("a")) {
let type_id = Utils.getStrByRegex(key_value_dic[name], ele.attribs.href)
if (_.isEmpty(type_id)) {
type_id = "/"
}
extend_dic["value"].push({"n": $(ele).text(), "v": decodeURIComponent(type_id)})
}
extend_list.push(extend_dic)
}
}
let sortElments = $("[class=\"v-hd clearfix\"]")
let extend_dic = {"key": (elements.length + 1).toString(), "name": "排序", "value": []}
extend_dic["value"].push({"n": "全部", "v": "/"})
for (const ele of $(sortElments).find("a")) {
let type_id = Utils.getStrByRegex(key_value_dic["排序"], ele.attribs.href)
if (_.isEmpty(type_id)) {
type_id = "/"
}
extend_dic["value"].push({"n": $(ele).text(), "v": type_id})
}
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + `/index.php/vod/show/id/${type_id}.html`)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtend(extend, key, value) {
if (extend[key] !== undefined && extend[key] !== "/") {
return value + "/" + extend[key] + "/"
} else {
return ""
}
}
async setCategory(tid, pg, filter, extend) {
let area = this.getExtend(extend, "3", "area")
let sort = this.getExtend(extend, "6", "by")
let id = this.getExtend(extend, "2", "id")
let letter = this.getExtend(extend, "5", "letter")
let year = this.getExtend(extend, "4", "year")
if (_.isEmpty(id)) {
id = "id/" + tid + "/"
}
let url = this.siteUrl + `/index.php/vod/show/${area}${sort}${id}${letter}${year}page/${pg}.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": id
}, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(content))
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + "/index.php/vod/search.html?wd="+wd)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new JiaFeiMaoSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+482
View File
@@ -0,0 +1,482 @@
/*
* @File : jianpian.js
* @Author : jade
* @Date : 2024/1/15 10:32
* @Email : [email protected]
* @Software : Samples
* @Desc : 完成荐片所有功能(添加弹幕)
*/
import {Spider} from "./spider.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class JianPianSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://api2.rinhome.com"
// this.siteUrl = "https://ownjpykxttjzuhy.jiesiwa.com"
}
getName() {
return "🌼┃荐片┃🌼"
}
getAppName() {
return "荐片"
}
getJSName() {
return "jianpian"
}
getType() {
return 3
}
getHeader() {
return {
"User-Agent": "jianpian-android/360",
"JPAUTH": "y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv",
"Referer": "www.jianpianapp.com"
}
}
async spiderInit(inReq=null) {
if (inReq !== null){
this.jsBase = await js2Proxy(inReq,"img",this.getHeader());
}else{
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.spiderInit(null)
}
async parseVodShortListFromJson(data_list) {
let vod_list = [];
for (const data of data_list) {
let vodShort = new VodShort();
vodShort.vod_id = data["id"]
if (data["path"] !== undefined) {
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["path"])
} else {
vodShort.vod_pic = this.jsBase + Utils.base64Encode(data["thumbnail"])
}
vodShort.vod_name = data["title"]
if (data["mask"] !== undefined){
vodShort.vod_remarks = data["mask"]
}else{
vodShort.vod_remarks = data["playlist"]["title"]
}
vod_list.push(vodShort)
}
return vod_list
}
objToList(list, key, split_value = "*") {
let value_list = []
for (const dic of list) {
value_list.push(dic[key])
}
return value_list.join(split_value)
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail();
vodDetail.vod_id = obj["id"]
vodDetail.vod_year = obj["year"]["title"]
if (!this.catOpenStatus) {
vodDetail.vod_pic = obj["thumbnail"] + "@Referer=www.jianpianapp.com@User-Agent=jianpian-version353@JPAUTH=y261ow7kF2dtzlxh1GS9EB8nbTxNmaK/QQIAjctlKiEv"
} else {
vodDetail.vod_pic = this.jsBase + Utils.base64Encode(obj["thumbnail"])
}
vodDetail.type_name = obj["category"][0]["title"]
vodDetail.vod_name = obj["title"]
vodDetail.vod_content = obj["description"]
vodDetail.vod_area = obj["area"]["title"]
vodDetail.vod_director = this.objToList(obj["directors"], "name")
vodDetail.vod_actor = this.objToList(obj["actors"], "name")
vodDetail.vod_remarks = "评分:" + obj["score"]
let playKeyList = [{"btbo_downlist": "btbo"}, {"xunlei_downlist": "迅雷"}, {"m3u8_downlist": "m3u8"}, {"new_ftp_list": "new_ftp"}, {"new_m3u8_list": "new_m3u8"}]
let playlist = {}
let urlList = []
for (const dic of playKeyList) {
let key = Object.keys(dic)[0]
let value = Object.values(dic)[0]
if (obj[key].length > 0) {
let url_str_list = []
for (const dic of obj[key]) {
url_str_list.push(dic["title"] + "$" + dic["url"])
}
if (urlList.indexOf(url_str_list.join("#")) === -1) {
urlList.push(url_str_list.join("#"))
playlist[value] = url_str_list.join("#")
} else {
await this.jadeLog.warning(`key为:${key},播放链接重复,无需保存`)
}
}
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async setClasses() {
let type_name_list = ["全部", "电影", "电视剧", "动漫", "综艺"]
let type_id_list = ["0", "1", "2", "3", "4"]
for (let i = 0; i < type_name_list.length; i++) {
let type_name = type_name_list[i]
let type_id = type_id_list[i]
this.classes.push({"type_name": type_name, "type_id": type_id})
}
}
async setFilterObj() {
this.filterObj = {
"0": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "1": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "2": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "3": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}], "4": [{
"key": "area", "name": "地區", "value": [{
"n": "全部", "v": "0"
}, {
"n": "国产", "v": "1"
}, {
"n": "中国香港", "v": "3"
}, {
"n": "中国台湾", "v": "6"
}, {
"n": "美国", "v": "5"
}, {
"n": "韩国", "v": "18"
}, {
"n": "日本", "v": "2"
}]
}, {
"key": "year", "name": "年份", "value": [{
"n": "全部", "v": "0"
}, {
"n": "2024", "v": "119"
}, {
"n": "2023", "v": "153"
}, {
"n": "2022", "v": "101"
}, {
"n": "2021", "v": "118"
}, {
"n": "2020", "v": "16"
}, {
"n": "2019", "v": "7"
}, {
"n": "2018", "v": "2"
}, {
"n": "2017", "v": "3"
}, {
"n": "2016", "v": "22"
}]
}, {
"key": "by", "name": "排序", "value": [{
"n": "热门", "v": "hot"
}, {
"n": "更新", "v": "updata"
}, {
"n": "评分", "v": "rating"
}]
}]
}
}
async setHomeVod() {
let content = await this.fetch(this.siteUrl + "/api/tag/hand?code=unknown601193cf375db73d&channel=wandoujia", null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data_list = content_json["data"][0]["video"]
this.homeVodList = await this.parseVodShortListFromJson(data_list)
}
}
async setCategory(tid, pg, filter, extend) {
let cateId = extend["cateId"] ?? tid
let area = extend["area"] ?? "0";
let year = extend["year"] ?? "0";
let by = extend["by"] ?? "hot";
this.limit = 24
let categoryUrl = this.siteUrl + `/api/crumb/list?area=${area}&category_id=${cateId}&page=${pg}&type=0&limit=24&sort=${by}&year=${year}`
await this.jadeLog.debug(`分类URL:${categoryUrl}`)
let content = await this.fetch(categoryUrl, null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data = content_json["data"]
this.vodList = await this.parseVodShortListFromJson(data)
}
}
async setDetail(id) {
let url = this.siteUrl + "/api/node/detail?channel=wandoujia&token=&id=" + id;
let content = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content);
let data_list = content_json["data"]
this.vodDetail = await this.parseVodDetailfromJson(data_list)
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/api/video/search?page=1" + "&key=" + wd;
const content = await this.fetch(url, null, this.getHeader());
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
let data_list = content_json["data"]
this.vodList = await this.parseVodShortListFromJson(data_list)
}
}
async setPlay(flag, id, flags) {
await this.jadeLog.debug(`播放链接为:${id}`)
this.playUrl = id
}
}
let spider = new JianPianSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+174
View File
@@ -0,0 +1,174 @@
/*
* @File : jiujiuliu.js
* @Author : jade
* @Date : 2024/1/4 14:15
* @Email : [email protected]
* @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}
+308
View File
@@ -0,0 +1,308 @@
/*
* @File : kankan70.js
* @Author : jade
* @Date : 2023/12/29 15:33
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
function get_qp_name44(qp_type) {
if (qp_type === 'zd') return '最大';
if (qp_type === 'yj') return '永久';
if (qp_type === 'hn') return '牛牛';
if (qp_type === 'gs') return '光波';
if (qp_type === 'sn') return '新朗';
if (qp_type === 'wl') return '涡轮';
if (qp_type === 'lz') return '良子';
if (qp_type === 'fs') return 'F速';
if (qp_type === 'ff') return '飞飞';
if (qp_type === 'bd') return '百度';
if (qp_type === 'uk') return '酷U';
if (qp_type === 'wj') return '无天';
if (qp_type === 'bj') return '八戒';
if (qp_type === 'tk') return '天空';
if (qp_type === 'ss') return '速速';
if (qp_type === 'kb') return '酷播';
if (qp_type === 'sd') return '闪电';
if (qp_type === 'xk') return '看看';
if (qp_type === 'tp') return '淘淘';
if (qp_type === 'jy') return '精英';
return qp_type;
}
class Kankan70Spider extends Spider {
constructor() {
super();
this.siteUrl = "http://cqdb6.com";
}
getName() {
return "📺┃70看看┃📺"
}
getAppName() {
return "70看看"
}
getJSName() {
return "kankan70"
}
getType() {
return 3
}
paraseUrlObject(js_str) {
let content_list = js_str.split(";")
let urlObject = {}
let js_name = ""
let play_id = 0
let pldy_id = 0
let js_key = ""
for (let i = 0; i < content_list.length; i++) {
let content = content_list[i]
if (content.indexOf("var lianzaijs") > -1) {
js_name = content.split("=")[0].split(" ")[1]
js_key = js_name.split("_")[1]
} else if (content.indexOf("pl_id=") > -1) {
play_id = content.split("=")[1]
urlObject[js_name] = {"play_id": play_id, "list": [], "pl_dy": pldy_id}
} else if (content.indexOf("var pl_dy") > -1) {
pldy_id = content.split("=")[1]
}
if (content.indexOf(`playarr_${js_key}[`) > -1) {
let play_url = content.split("=\"")[1].split(",")[0]
urlObject[js_name]["list"].push(play_url)
}
}
let play_url_list = [], play_format_list = [];
for (const key of Object.keys(urlObject)) {
if (key.indexOf("_") > -1) {
let play_format_name = get_qp_name44(key.split("_")[1])
play_format_list.push(play_format_name)
let vodItems = []
let index = 0
for (const play_url of urlObject[key]["list"]) {
index = index + 1
vodItems.push("第" + index.toString() + "集" + "$" + play_url)
}
play_url_list.push(vodItems.join("#"))
}
}
return {"play_format": play_format_list.join("$$$"), "play_url": play_url_list.join("$$$")}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vod_elements = $("a.li-hv")
for (const vod_element of vod_elements) {
let vodShort = new VodShort()
vodShort.vod_id = "/" + vod_element.attribs["href"]
vodShort.vod_name = vod_element.attribs["title"]
vodShort.vod_pic = $(vod_element).find("img")[0].attribs["data-original"]
let remarkEle = $(vod_element).find("p.bz")[0]
if (remarkEle.length > 0) {
vodShort.vod_remarks = remarkEle.children[0].data
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let infoElement = $("[class=info]")
let dtElement = $(infoElement).find("dt.name")[0]
vodDetail.vod_name = dtElement.children[0].data
vodDetail.vod_remarks = dtElement.children[1].children[0].data
let ddString = $(infoElement).find("dd").text()
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?) /, ddString)
vodDetail.vod_year = Utils.getStrByRegex(/年代:(.*?)\n/, ddString)
vodDetail.type_name = Utils.getStrByRegex(/类型:(.*?)\n/, ddString)
vodDetail.vod_content = $(infoElement).find("[class=des2]").text().replaceAll("\n", "").replaceAll("剧情:", "")
vodDetail.vod_pic = $("img.lazy")[0].attribs["data-original"]
return vodDetail
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const vod_object of obj) {
let vodShort = new VodShort()
vodShort.vod_id = vod_object["url"]
vodShort.vod_pic = vod_object["thumb"]
vodShort.vod_remarks = vod_object["time"]
vodShort.vod_name = vod_object["title"]
vod_list.push(vodShort)
}
return vod_list
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
let elements = $("[class=index-list-l]")
for (const element of elements) {
let typeElement = $($(element).find("[class=\"h1 clearfix\"]")[0]).find("a")
let type_id = typeElement[0].attribs["href"]
let type_name = $(typeElement[1]).text()
if (!_.isEmpty(type_name)) {
this.classes.push({"type_id": type_id, "type_name": type_name})
}
}
}
}
async getFilter(type_id) {
let url = this.siteUrl + type_id
let html = await this.fetch(url, null, this.getHeader())
let extend_list = []
if (!_.isEmpty(html)) {
let $ = load(html)
let elements = $("[class=\"sy scon clearfix\"]").find("dl")
let i = 0
for (const element of elements) {
let type_name = $($(element).find("dt")).text().replace("按", "").replace("", "")
let extend_dic = {
"key": (i + 1).toString(), "name": type_name, "value": []
}
let type_elements = $(element).find("a")
let index = 0
if (type_name === "剧情") {
index = 3
} else if (type_name === "年代") {
index = 2
} else if (type_name === "地区") {
index = 4
}
for (const type_element of type_elements) {
let type_id_list = type_element.attribs["href"].split("/")
extend_dic["value"].push({"n": $(type_element).text(), "v": type_id_list[index]})
}
extend_list.push(extend_dic)
i = i + 1
}
}
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes) {
let type_id = class_dic["type_id"]
if (type_id !== "最近更新") {
this.filterObj[type_id] = await this.getFilter(type_id)
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let url = this.siteUrl + tid
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let class_name = tid.split("/")[1]
let id = tid.split("/")[2]
let api_str = Utils.getStrByRegex(/var _yu_gda_s="(.*?)";/, html)
let params = {
"action": class_name,
"page": parseInt(pg),
"year": extend["2"] ?? "0",
"area": extend["3"] ?? "all",
"class": extend["1"] ?? "0",
"dect": "",
"id": id
}
let cate_html = await this.fetch(api_str, params, this.getHeader())
if (cate_html !== null) {
let $ = load(cate_html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id
let html = await this.fetch(detailUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
let mather = /<script type="text\/javascript" src="http:\/\/test.gqyy8.com:8077\/ne2(.*?)"><\/script>/g.exec(html)
let js_url = "http://test.gqyy8.com:8077/ne2" + mather[1]
let js_str = await this.fetch(js_url, null, this.getHeader())
if (!_.isEmpty(js_str)) {
let playObject = this.paraseUrlObject(js_str)
this.vodDetail.vod_play_url = playObject["play_url"]
this.vodDetail.vod_play_from = playObject["play_format"]
}
}
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search.php"
let html = await this.fetch(url, null, this.getHeader())
if (!_.isEmpty(html)) {
let params = {
"top": 10, "q": wd,
}
let api_url = Utils.getStrByRegex(/var my_search='(.*?)';/, html)
let content = await this.fetch(api_url, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content.replaceAll("",""))
this.vodList = await this.parseVodShortListFromJson(content_json)
}
}
}
}
let spider = new Kankan70Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+444
View File
@@ -0,0 +1,444 @@
/*
* @File : kuaikan.js
* @Author : jade
* @Date : 2024/3/19 11:12
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {jinja2, _, dayjs, Crypto} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
const charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
function randStr(len, withNum) {
let _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (let i = 0; i < len; i++) {
let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11);
_str += charStr[idx];
}
return _str;
}
function randDevice() {
return {
brand: 'Huawei',
model: 'HUAWEI Mate 20',
release: '10',
buildId: randStr(3, false).toUpperCase() + _.random(11, 99) + randStr(1, false).toUpperCase(),
};
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
function jsonParse(input, json) {
try {
let url = json.url ?? '';
if (url.startsWith('//')) {
url = 'https:' + url;
}
if (!url.startsWith('http')) {
return {};
}
let headers = json['headers'] || {};
let ua = (json['user-agent'] || '').trim();
if (ua.length > 0) {
headers['User-Agent'] = ua;
}
let referer = (json['referer'] || '').trim();
if (referer.length > 0) {
headers['Referer'] = referer;
}
_.keys(headers).forEach((hk) => {
if (!headers[hk]) delete headers[hk];
});
return {
header: headers, url: url,
};
} catch (error) {
}
return {};
}
class KuaiKanSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://api1.baibaipei.com:8899';
this.device = {}
this.parse = []
}
getName() {
return "🛥︎┃快看视频┃🛥︎"
}
getAppName() {
return "快看视频"
}
getJSName() {
return "kuaikan"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
await this.setDevice();
}
async request(reqUrl, postData, agentSp, get) {
let ts = dayjs().valueOf().toString();
let rand = randStr(32);
let sign = Crypto.enc.Hex.stringify(Crypto.MD5('H58d2%gLbeingX*%D4Y8!C!!@G_' + ts + '_' + rand))
.toString()
.toLowerCase();
let headers = {
'user-agent': agentSp || this.device.ua,
};
if (reqUrl.includes('baibaipei')) {
headers['device-id'] = this.device.id;
headers['sign'] = sign;
headers['time'] = ts;
headers['md5'] = rand;
headers['version'] = '2.1.5';
headers['system-model'] = this.device.model;
headers['system-brand'] = this.device.brand;
headers['system-version'] = this.device.release;
headers["host"] = "api1.baibaipei.com:8899"
}
if (!get) {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
let res = await req(reqUrl, {
method: get ? 'get' : 'post', headers: headers, data: postData || {}, postType: 'form'
});
await this.jadeLog.debug(`URL:${reqUrl},headers:${JSON.stringify(headers)},data:${[JSON.stringify(postData)]}`)
let content = res.content;
try {
let key = Crypto.enc.Utf8.parse('IjhHsCB2B5^#%0Ag');
let iv = Crypto.enc.Utf8.parse('y8_m.3rauW/>j,}.');
let src = Crypto.enc.Base64.parse(content);
let dst = Crypto.AES.decrypt({ciphertext: src}, key, {iv: iv, padding: Crypto.pad.Pkcs7});
dst = Crypto.enc.Utf8.stringify(dst);
await this.jadeLog.debug(`response:${dst}`)
return JSON.parse(dst);
} catch (e) {
return JSON.parse(content)
}
}
async setDevice() {
let deviceKey = 'device';
let deviceInfo = await local.get(this.siteKey, deviceKey);
if (deviceInfo.length > 0) {
try {
this.device = JSON.parse(deviceInfo);
} catch (error) {
}
}
if (_.isEmpty(this.device)) {
this.device = randDevice();
this.device.id = randStr(13).toLowerCase();
this.device.ua = 'okhttp/3.14.9';
await local.set(this.siteKey, deviceKey, JSON.stringify(this.device));
}
}
async setClasses() {
await this.setDevice()
let response = await this.request(this.siteUrl + '/api.php/Index/getTopVideoCategory');
for (const type of response.data) {
let typeName = type["nav_name"];
if (typeName === '推荐') continue;
let typeId = type["nav_type_id"].toString();
this.classes.push({
type_id: typeId, type_name: typeName,
});
}
}
async getFilter(filterData) {
await this.jadeLog.debug(JSON.stringify(filterData))
let filterAll = []
for (let key of Object.keys(filterData)) {
let itemValues = filterData[key];
if (key === 'plot') key = 'class';
let typeExtendName = '';
switch (key) {
case 'class':
typeExtendName = '类型';
break;
case 'area':
typeExtendName = '地区';
break;
case 'lang':
typeExtendName = '语言';
break;
case 'year':
typeExtendName = '年代';
break;
case 'sort':
typeExtendName = '排序';
break;
}
if (typeExtendName.length === 0) continue;
let newTypeExtend = {
key: key, name: typeExtendName,
};
let newTypeExtendKV = [];
for (let j = 0; j < itemValues.length; j++) {
const name = itemValues[j];
let value = key === 'sort' ? j + '' : name === '全部' ? '0' : name;
newTypeExtendKV.push({n: name, v: value});
}
newTypeExtend['init'] = key === 'sort' ? '1' : newTypeExtendKV[0]['v'];
newTypeExtend.value = newTypeExtendKV;
filterAll.push(newTypeExtend);
}
return filterAll
}
async setFilterObj() {
for (const typeDic of this.classes) {
let typeId = typeDic["type_id"]
if (typeId !== "最近更新") {
let filterData = await this.request(this.siteUrl + '/api.php/Video/getFilterType', {type: typeId})
this.filterObj[typeId] = await this.getFilter(filterData["data"])
}
}
}
async parseVodShortListFromJSONByHome(obj) {
let vod_list = []
for (const data of obj["video"]) {
let video_vod_list = await this.parseVodShortListFromJson(data["list"])
vod_list.push(...video_vod_list)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["vod_id"]
vodShort.vod_name = data["vod_name"]
vodShort.vod_pic = data["vod_pic"]
vodShort.vod_remarks = data["vod_remarks"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.load_dic(JSON.stringify(obj))
vodDetail.vod_content = obj["vod_content"].trim()
vodDetail.type_name = obj["vod_class"]
let playlist = {};
for (const item of obj["vod_play"]) {
let from = item["playerForm"];
if (from === 'jp' && this.catOpenStatus) continue;
if (from === 'xg' && this.catOpenStatus) continue;
let urls = [];
for (const u of item.url) {
urls.push(formatPlayUrl(vodDetail.vod_name, u.title) + '$' + u.play_url);
}
if (!playlist.hasOwnProperty(from) && urls.length > 0) {
playlist[from] = urls;
}
}
this.parse = obj.parse || [];
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
let urls = _.values(playlist);
let vod_play_url = [];
for (const urlist of urls) {
vod_play_url.push(urlist.join('#'));
}
vodDetail.vod_play_url = vod_play_url.join('$$$');
return vodDetail
}
async setHomeVod() {
let data = await this.request(this.siteUrl + "/api.php/Index/getHomePage", {"p": "1", "type": "1"})
this.homeVodList = await this.parseVodShortListFromJSONByHome(data.data)
}
async setCategory(tid, pg, filter, extend) {
if (pg === 0) pg = 1;
let reqUrl = this.siteUrl + '/api.php/Video/getFilterVideoList';
let formData = JSON.parse(jinja2(`{
"type": "{{tid}}",
"p": "{{pg}}",
"area": "{{ext.area|default(0)}}",
"year": "{{ext.year|default(0)}}",
"sort": "{{ext.sort|default(0)}}",
"class": "{{ext.class|default(0)}}"}`, {ext: extend, tid: tid, pg: pg}));
console.log(formData);
let data = await this.request(reqUrl, formData);
this.vodList = await this.parseVodShortListFromJson(data["data"]["data"])
}
async setDetail(id) {
let data = await this.request(this.siteUrl + '/api.php/Video/getVideoInfo', {video_id: id})
this.vodDetail = await this.parseVodDetailfromJson(data["data"]["video"])
}
async setPlay(flag, id, flags) {
this.result.jx = 0
try {
if (id.indexOf('youku') >= 0 || id.indexOf('iqiyi') >= 0 || id.indexOf('v.qq.com') >= 0 || id.indexOf('pptv') >= 0 || id.indexOf('le.com') >= 0 || id.indexOf('1905.com') >= 0 || id.indexOf('mgtv') >= 0)
{
if (this.parse.length > 0) {
for (let index = 0; index < this.parse.length; index++) {
try {
const p = this.parse[index];
let res = await req(p + id, {
headers: {'user-agent': 'okhttp/4.1.0'},
});
await this.jadeLog.debug(`解析连接结果为:${JSON.stringify(res)}`)
let result = jsonParse(id, JSON.parse(res.content)["data"]);
if (result.url){
this.playUrl = result.url // 这里可以直接返回弹幕,无法进行快进操作
this.danmuUrl = await this.danmuSpider.getVideoUrl(id,0)
this.result.jx = 1
}
} catch (error) {
}
}
}
} else if (id.indexOf('jqq-') >= 0) {
let jqqHeaders = await this.request(this.siteUrl + '/jqqheader.json', null, null, true);
let ids = id.split('-');
let jxJqq = await req('https://api.juquanquanapp.com/app/drama/detail?dramaId=' + ids[1] + '&episodeSid=' + ids[2] + '&quality=LD', {headers: jqqHeaders});
let jqqInfo = JSON.parse(jxJqq.content);
if (jqqInfo.data["playInfo"]["url"]) {
this.playUrl = jqqInfo.data["playInfo"]["url"]
}
} else if (id.startsWith("ftp")) {
this.playUrl = id
} else {
let res = await this.request(this.siteUrl + '/video.php', {url: id});
let result = jsonParse(id, res.data);
if (result.url) {
if (result.url.indexOf("filename=1.mp4") > -1) {
this.playUrl = result.url
} else {
this.playUrl = await js2Proxy(true, this.siteType, this.siteKey, 'lzm3u8/' + Utils.base64Encode(result.url), {});
}
}
}
} catch (e) {
await this.jadeLog.error(e)
}
}
async setSearch(wd, quick) {
let data = await this.request(this.siteUrl + '/api.php/Search/getSearch', {key: wd, type_id: 0, p: 1})
this.vodList = await this.parseVodShortListFromJson(data["data"]["data"])
}
async proxy(segments, headers) {
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'lzm3u8') {
await this.jadeLog.debug(`使用代理播放,播放连接为:${url}`)
const resp = await req(url, {});
let hls = resp.content;
const jsBase = await js2Proxy(false, this.siteType, this.siteKey, 'lzm3u8/', {});
const baseUrl = url.substr(0, url.lastIndexOf('/') + 1);
await this.jadeLog.debug(hls.length)
hls = hls.replace(/#EXT-X-DISCONTINUITY\r*\n*#EXTINF:6.433333,[\s\S]*?#EXT-X-DISCONTINUITY/, '');
await this.jadeLog.debug(hls.length)
hls = hls.replace(/(#EXT-X-KEY\S+URI=")(\S+)("\S+)/g, function (match, p1, p2, p3) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + up + p3;
});
hls = hls.replace(/(#EXT-X-STREAM-INF:.*\n)(.*)/g, function (match, p1, p2) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + jsBase + Utils.base64Decode(up);
});
hls = hls.replace(/(#EXTINF:.*\n)(.*)/g, function (match, p1, p2) {
let up = (!p2.startsWith('http') ? baseUrl : '') + p2;
return p1 + up;
});
return JSON.stringify({
code: resp.code, content: hls, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new KuaiKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+93
View File
@@ -0,0 +1,93 @@
/*
* @File : liangzi.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : [email protected]
* @Software : Samples
* @Desc : 量子资源(已失效)
*/
import {VodSpider} from "./vodSpider.js";
class LiangziSpider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://cj.lzcaiji.com"
this.remove18 = true
}
getAppName() {
return "量子资源"
}
getName() {
return `🐝┃量子资源┃🐝`
}
getJSName() {
return "liangzi"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new LiangziSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+93
View File
@@ -0,0 +1,93 @@
/*
* @File : liangzi18.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : [email protected]
* @Software : Samples
* @Desc : 量子资源18+ (已失效)
*/
import {VodSpider} from "./vodSpider.js";
class Liangzi18Spider extends VodSpider {
constructor() {
super();
this.siteUrl = "https://cj.lzcaiji.com"
this.remove18 = false
}
getAppName() {
return "量子资源18+"
}
getName() {
return `🔞┃量子资源18+┃🔞`
}
getJSName() {
return "liangzi18"
}
getType() {
return 3
}
async spiderInit(inReq) {
await super.spiderInit(inReq);
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
}
let spider = new Liangzi18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+260
View File
@@ -0,0 +1,260 @@
/*
* @File : liujiushu.js
* @Author : jade
* @Date : 2024/04/23 10:02
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
import {formatContent} from "../lib/utils.js";
class LiuJiuShuSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.diyi69.com"
}
getAppName() {
return "六九书吧"
}
getJSName() {
return "liujiushu"
}
getType() {
return 10
}
getName() {
return "📚︎┃六九书吧┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
let bookShortElements = $(element).find("a")
bookShort.book_remarks = $(bookShortElements[2]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = bookShortElements[0].attribs.href
bookShort.book_pic = $(element).find("img")[0].attribs["src"]
return bookShort
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $($("[class=\"flex\"]")[0]).find("li")
for (const bookElement of bookElements) {
let bookShort = this.parseVodShortFromElement($, bookElement)
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let bookElements = $("ul.flex > li")
let books = [];
for (const item of bookElements) {
let bookShort = new BookShort()
bookShort.book_id = $(item).find('a:first')[0].attribs.href;
const img = $(item).find('img:first')[0];
bookShort.book_name = img.attribs.title
bookShort.book_pic = img.attribs["data-original"]
bookShort.book_remarks = $($(item).find('em:first')).text();
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let books = []
let bookElements = $('li.searchresult')
for (const bookElement of bookElements) {
let bookShort = new BookShort()
let bookShortElements = $(bookElement).find("a")
bookShort.book_remarks = $(bookShortElements[2]).text()
bookShort.book_name = $(bookShortElements[1]).text()
bookShort.book_id = bookShortElements[0].attribs.href
bookShort.book_pic = $(bookShortElements[0]).find("img")[0].attribs["data-original"]
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
bookDetail.book_name = $('[property$=title]')[0].attribs.content
bookDetail.book_year = $('[property$=update_time]')[0].attribs.content
bookDetail.book_director = $('[property$=author]')[0].attribs.content
bookDetail.book_content = $('[property$=description]')[0].attribs.content
bookDetail.book_remarks = $('[property$=category]')[0].attribs.content
bookDetail.book_pic = $('div.novel_info_main>img')[0].attribs.src
bookDetail.book_id = id
const playBook = {};
const sectionsElements = $("[class=\"flex ulcard\"]").find("li")
const urlElements = $("[class=\"section chapter_list\"]")
for (let i = 0; i < sectionsElements.length; i++) {
const sectionElement = sectionsElements[i]
const urlElemnet = urlElements[i]
let vodItems = []
for (const urlEle of $(urlElemnet).find("a")) {
const epName = $(urlEle).text();
const playUrl = epName + "-" + urlEle.attribs.href;
vodItems.push(epName + '$' + playUrl)
}
let name = $($(urlElemnet).find("[class=\"title jcc\"]")).text()
if (_.isEmpty(name)) {
let text = $(sectionElement).text().split("")[0]
playBook[text] = vodItems.join("#")
} else {
name = name.replaceAll("《","").replaceAll("》","").replaceAll(bookDetail.book_name,"")
playBook[name] = vodItems.reverse().join("#")
}
}
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
for (const a of $('div.navigation > nav > a[href!="/"]')) {
let type_id_list = a.attribs.href.split("/").slice(0, 3)
this.classes.push({
type_id: type_id_list.join("/"), type_name: a.children[0].data.trim(), tline: 2,
});
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
async setCategory(tid, pg, filter, extend) {
let $ = await this.getHtml(this.siteUrl + `${tid}/${pg}.html`);
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setPlay(flag, id, flags) {
let id_list = id.split("-")
id = id_list[1]
let content = id_list[0] + "\n\n"
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += Utils.formatContent($("[class=\"content\"]").html().trim().replaceAll("<p>", " ").replaceAll("</p>", "\n"));
id = $("[id=\"next_url\"]")[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content": content}
}
async setSearch(wd, quick) {
let params = {"searchkey": wd, "searchtype": "all", "Submit": ""}
let content = await this.fetch(this.siteUrl + "/search/", params, this.getHeader())
let $ = load(content)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'img') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + url)
let bookDetail = await this.parseVodDetailFromDoc($)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(bookDetail.book_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new LiuJiuShuSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+328
View File
@@ -0,0 +1,328 @@
/*
* @File : lovemovie.js
* @Author : jade
* @Date : 2024/4/29 09:36
* @Email : [email protected]
* @Software : Samples
* @Desc : 爱情电影网
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import {gbk_us} from "../lib/gbk_us.js";
class LoveMovieSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://b.aqdyje.com"
this.removeKey = "骑兵营"
}
getName() {
return "💕┃爱情电影网┃💕"
}
getAppName() {
return "爱情电影网"
}
getJSName() {
return "lovemovie"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
}
async getHtml(url = this.siteUrl, proxy = false, headers = this.getHeader()) {
let buffer = await this.fetch(url, null, headers, false, false, 1, proxy)
let html = Utils.decode(buffer, "gb2312")
await this.jadeLog.debug(`html content:${html}`)
if (!_.isEmpty(html)) {
return load(html)
} else {
return load(gbkDecode(buffer))
}
}
async getFilter($, navElements) {
let extend_list = []
let extend_dic = {"key": "class", "name": "类型", "value": [this.getFliterDic("全部", "全部")]}
for (const navElement of $(navElements).find("li")) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
extend_dic["value"].push(this.getFliterDic(type_name, type_id))
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav-item drop-down \"]")
for (const navElement of navElements) {
let elemenet = $(navElement).find("a")[0]
let type_name = $(elemenet).text()
let type_id = elemenet.attribs.href
if (type_name !== this.removeKey) {
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter($, navElement)
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"play-img\"]")
if (vodElements.length === 0) {
vodElements = $("[class=\"show-list list-mode fn-clear\"]").find("li")
}
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = vodElement.attribs.href
if (_.isEmpty(vodShort.vod_id)) {
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
}
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
for (const element of $(vodElement).find("label")) {
let text = $(element).text().trim()
if (!_.isEmpty(text)) {
vodShort.vod_remarks = text
break
}
}
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = $($(vodElement).find("p")[0]).text().replace("\n")
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $("[class=\"show-list\"]").find("li")
let vod_list = []
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_remarks = $($(vodElement).find("[class=\"type fn-left\"]")).text().replace("类型:", "")
if (vodShort.vod_remarks !== "社处片" && vodShort.vod_remarks !== "社保片" && vodShort.vod_remarks !== "撸丝片" && vodShort.vod_remarks !== "撸丝动漫") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let imgElement = $("[class=\"detail-pic fn-left\"]").find("img")[0]
vodDetail.vod_pic = imgElement.attribs.src
vodDetail.vod_name = imgElement.attribs.alt
let vodInfoElement = $("[class=\"info fn-clear\"]")
for (const vodDlElement of $(vodInfoElement).find("dl")) {
let text = $(vodDlElement).text()
if (text.indexOf("主演") > -1) {
vodDetail.vod_actor = text.replaceAll("主演:", "").replaceAll("\n", "")
}
if (text.indexOf("状态") > -1) {
vodDetail.vod_remarks = text.replaceAll("状态:", "").replaceAll("\n", "")
}
if (text.indexOf("类型") > -1) {
vodDetail.type_name = text.replaceAll("类型:", "").replaceAll("\n", "")
}
if (text.indexOf("地区") > -1) {
vodDetail.vod_area = text.replaceAll("地区:", "").replaceAll("\n", "")
}
if (text.indexOf("导演") > -1) {
vodDetail.vod_director = text.replaceAll("导演:", "").replaceAll("\n", "")
}
if (text.indexOf("年份") > -1) {
vodDetail.vod_year = text.replaceAll("年份:", "").replaceAll("\n", "")
}
if (text.indexOf("剧情") > -1) {
vodDetail.vod_content = text.replaceAll("剧情:", "").replaceAll("\n", "")
}
}
let playList = {}
let html = $.html()
let playListElements = $("[class=\"play-list\"]")
let index = 1
for (const playListElement of playListElements) {
let playName = `播放连接-${index}`
let vodItems = []
for (const playUrlElement of $(playListElement).find("a")) {
let playUrlName = playUrlElement.attribs.title
let playUrl = playUrlElement.attribs.href
vodItems.push(playUrlName + "$" + playUrl)
}
playList[playName] = vodItems.join("#")
index = index + 1
}
index = 1
let ciliListElements = $("[class=\"con4\"]")
for (const ciliListElement of ciliListElements) {
let playName = `磁力链接-${index}`
let vodItems = []
let playUrlName = playName
let playUrl = $($(ciliListElement).find("div")).find("a")[0].attribs.href
if (playUrl !== "javascript:void(0);") {
vodItems.push(playUrlName + "$" + playUrl)
playList[playName] = vodItems.join("#")
index = index + 1
}
}
vodDetail.vod_play_url = _.values(playList).join('$$$');
vodDetail.vod_play_from = _.keys(playList).join('$$$');
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
getExtend(extend) {
if (extend["class"] !== undefined) {
if (extend["class"] !== "全部") {
return extend["class"]
}
}
return undefined
}
async setCategory(tid, pg, filter, extend) {
let classes = this.getExtend(extend) ?? tid
let url
if (classes === tid) {
url = this.siteUrl + classes
} else {
if (parseInt(pg) === 1) {
url = this.siteUrl + classes
} else {
url = this.siteUrl + classes + `index${pg}.html`
}
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setPlay(flag, id, flags) {
if (flag.indexOf("磁力") > -1) {
this.playUrl = id
} else {
let idSplitList = id.split("-")
let flag_id = parseInt(idSplitList[1])
let episode = parseInt(idSplitList[2].split(".")[0])
let $ = await this.getHtml(this.siteUrl + id)
let playJsUrl = Utils.getStrByRegex(/<script type="text\/javascript" src="(.*?)">/, $.html())
let playJsContent = await this.fetch(this.siteUrl + playJsUrl, null, this.getHeader())
let playUrlListStr = Utils.getStrByRegex(/var VideoListJson=(.*?),urlinfo=/, playJsContent)
let playDic = eval(playUrlListStr)
this.playUrl = playDic[flag_id][1][episode].split("$")[1]
if (this.playUrl.indexOf("m3u8") === -1) {
let html = await this.fetch(this.playUrl, null, this.getHeader())
this.playUrl = Utils.getStrByRegex(/url: '(.*?)'/, html)
}
}
}
GBKEncode(str) {
var arr_index = 0x8140; //33088;
str += '';
var gbk = [];
var wh = '?'.charCodeAt(0); //gbk中没有的字符的替换符
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) gbk.push(charcode);
else {
var gcode = gbk_us.indexOf(charcode);
if (~gcode) {
gcode += arr_index;
gbk.push(0xFF & (gcode >> 8), 0xFF & gcode);
} else {
gbk.push(wh);
}
}
}
return gbk;
}
encode(str) {
let encodeStr = ""
for (const ch of str) {
let bitArr = this.GBKEncode(ch);
for (let i = 0; i < bitArr.length; i++) {
bitArr[i] = '%' + ('0' + bitArr[i].toString(16)).substr(-2).toUpperCase();
}
encodeStr = encodeStr + bitArr.join('');
}
return encodeStr
}
async setSearch(wd, quick) {
let params = {"searchword": this.encode(wd)}
let buffer = await this.post(this.siteUrl + "/search.asp", params, this.getHeader(), "form", 1)
let $ = load(Utils.decode(buffer, "gb2312"))
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new LoveMovieSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, LoveMovieSpider}
+133
View File
@@ -0,0 +1,133 @@
/*
* @File : lovemovie18.js
* @Author : jade
* @Date : 2024/4/29 09:36
* @Email : [email protected]
* @Software : Samples
* @Desc : 爱情电影网
*/
import {LoveMovieSpider} from "./lovemovie.js";
import {VodShort} from "../lib/vod.js";
class LoveMovie18Spider extends LoveMovieSpider {
constructor() {
super();
this.siteUrl = "https://b.aqdyje.com"
this.removeKey = "骑兵营"
}
getName() {
return "🔞┃爱情电影网18+┃🔞"
}
getAppName() {
return "爱情电影网18+"
}
getJSName() {
return "lovemovie18"
}
getType() {
return 3
}
async parseVodShortListFromDocBySearch($) {
let vodElements = $("[class=\"show-list\"]").find("li")
let vod_list = []
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
let imgElement = $(vodElement).find("img")[0]
vodShort.vod_pic = imgElement.attribs.src
vodShort.vod_name = imgElement.attribs.alt
vodShort.vod_remarks = $($(vodElement).find("[class=\"type fn-left\"]")).text().replace("类型:", "")
if (vodShort.vod_remarks === "社处片" || vodShort.vod_remarks === "社保片" || vodShort.vod_remarks === "撸丝片" || vodShort.vod_remarks === "撸丝动漫") {
vod_list.push(vodShort)
}
}
return vod_list
}
async getFilter(type_id) {
let $ = await this.getHtml(this.siteUrl + type_id)
let extend_list = []
let extend_dic = {"key": "class", "name": "类型", "value": []}
for (const navElement of $("[class=\"subnav-tv fn-left\"]").find("a")) {
let type_name = $(navElement).text()
let type_id = navElement.attribs.href
extend_dic["value"].push(this.getFliterDic(type_name, type_id))
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
return extend_list
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $("[class=\"nav-item drop-down \"]")
this.classes = []
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = $(element).text()
let type_id = element.attribs.href
if (type_name === this.removeKey) {
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter(type_id)
}
}
}
async setCategory(tid, pg, filter, extend) {
let classes = this.getExtend(extend) ?? tid
let url
if (parseInt(pg) === 1) {
url = this.siteUrl + classes
} else {
url = this.siteUrl + classes + `index${pg}.html`
}
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
let spider = new LoveMovie18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+181
View File
@@ -0,0 +1,181 @@
/*
* @File : mhdq.js
* @Author : jade
* @Date : 2024/1/24 9:15
* @Email : [email protected]
* @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}
+282
View File
@@ -0,0 +1,282 @@
/*
* @File : mp4movie.js
* @Author : jade
* @Date : 2024/2/19 9:41
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class DyttSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.mp4us.com"
this.apiUrl = "https://m.mp4us.com"
this.dyttReconnectTimes = 0
}
async spiderInit(inReq=null) {
if (inReq !== null){
this.jsBase = await js2Proxy(inReq,"detail",this.getHeader());
}else{
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
getName() {
return "🍚┃Mp4电影┃🍚"
}
getAppName() {
return "Mp4电影"
}
getJSName() {
return "mp4movie"
}
getType() {
return 3
}
// getHeader() {
// return {"User-Agent": Utils.CHROME, "Referer": this.siteUrl + "/","Connection":"keep-alive"};
// }
async getFilter() {
let extend_list = []
let $ = await this.getHtml()
let suoyinElement = $("[class=\"nav navbar-nav\"]").find("li").slice(-1)[0]
let souyinUrl = $(suoyinElement).find("a")[0].attribs.href
let souyin$ = await this.getHtml(this.siteUrl + souyinUrl)
let sortElements = souyin$("[class=\"sort-box\"]").find("[class=\"sort-list\"]").slice(1,-1)
for (const sortElement of sortElements){
let name = $($(sortElement).find("h5")).text().replace("","")
let extend_dic = {"key": name, "name":name, "value": []}
for (const ele of $(sortElement).find("a")) {
extend_dic["value"].push({"n": $(ele).text(), "v": ele.attribs.data.split("-")[1]})
}
extend_list.push(extend_dic)
}
return extend_list
}
// async setFilterObj() {
// for (const type_dic of this.classes) {
// let type_id = type_dic["type_id"]
// if (type_id !== "最近更新") {
// this.filterObj[type_id] = await this.getFilter()
// }
// }
// }
async setClasses() {
let $ = await this.getHtml()
let suoyinElement = $("[class=\"nav navbar-nav\"]").find("li").slice(-1)[0]
let souyinUrl = $(suoyinElement).find("a")[0].attribs.href
let souyin$ = await this.getHtml(this.siteUrl + souyinUrl)
let sortElements = souyin$("[class=\"sort-box\"]").find("[class=\"sort-list\"]")
let classElements = $(sortElements[0]).find("li")
for (const classElement of classElements) {
let type_name = $($(classElement).find("a")).text()
let type_id = $(classElement).find("a")[0].attribs.data.replaceAll("id-", "")
if (type_name !== "全部") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"index_today cclear\"]").find("a")
for (const vodElement of vodElements){
let vodShort = new VodShort();
vodShort.vod_name = vodElement.attribs.title
vodShort.vod_id = vodElement.attribs.href
vodShort.vod_pic = this.jsBase + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
return vod_list
}
getSearchHeader() {
let headers = this.getHeader()
headers["Cookie"] = "Hm_lvt_d8c8eecfb13fe991855f511a6e30c3d2=1708243467,1708325624,1708326536;Hm_lpvt_d8c8eecfb13fe991855f511a6e30c3d2;1708326536"
return headers
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let html = $.html()
let detailRootElement = $("[class=\"article-header\"]")
let detailElements = $(detailRootElement).find("p")
let content = ""
for (const detailElement of detailElements){
content = content + $(detailElement).text() + "\n"
}
vodDetail.type_name = $($($(detailRootElement).find("[class=\"post-meta\"]")).find("span")[0]).text()
vodDetail.vod_pic = $(detailRootElement).find("img")[0].attribs.src
vodDetail.vod_name = Utils.getStrByRegex(/名称:(.*?)\n/,content)
vodDetail.vod_actor = Utils.getStrByRegex(/主演:(.*?)\n/,content)
vodDetail.vod_director = Utils.getStrByRegex(/导演:(.*?)\n/,content)
vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?)\n/,content)
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?)\n/,content)
vodDetail.vod_remarks = Utils.getStrByRegex(/更新:(.*?)\n/,content)
let contentElement = $("[class=\"article-related info\"]").find("p")
vodDetail.vod_content = $(contentElement).text()
let downloadElements = $("[class=\"article-related download_url\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < downloadElements.length; i++) {
let playFormatElement = downloadElements[i]
let format_name = $($(playFormatElement).find("h2")).text().replaceAll(vodDetail.vod_name,"")
vod_play_from_list.push(format_name.replaceAll("下载","播放"))
let vodItems = []
for (const playUrlElement of $(downloadElements[i]).find("a")) {
let episodeName = $(playUrlElement).text().replaceAll("磁力链下载","").replaceAll(".mp4","")
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async parseVodShortListFromJson(obj) {
let vod_list = []
let $ = load(obj["ajaxtxt"])
let vodElements = $($("ul")).find("li");
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["data-original"]
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/,$(vodElement).find("img")[0].attribs.alt)
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_remarks = "评分:"+ $($(vodElement).find("[class=\"rate badge\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $($("[id=\"list_all\"]").find("ul")).find("li")
for (const vodElement of vodElements){
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs.href
vodShort.vod_name = Utils.getStrByRegex(/《(.*?)》/,$($($(vodElement).find("[class=\"text_info\"]")).find("a")[0]).text())
vodShort.vod_pic = $(vodElement).find("img")[0].attribs["data-original"]
vodShort.vod_remarks = $($(vodElement).find("[class=\"update_time\"]")).text()
vod_list.push(vodShort)
}
return vod_list
}
async setHomeVod() {
let $ = await this.getHtml();
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
return this.vodDetail
}
async setCategory(tid, pg, filter, extend) {
// let url = this.apiUrl + `/list-index-id-${tid}`
// let area = extend["地区"] ?? ""
// let year = extend["年代"] ?? ""
// let tag = extend["标签"] ?? ""
// if (parseInt(pg) > 1){
// url = url + `-p-${pg}`
// }
// if (!_.isEmpty(area) && area !== "0"){
// url = url + `-area-${area}`
// }
// if (!_.isEmpty(year) && year !== "0"){
// url = url + `-year-${year}`
// }
// if (!_.isEmpty(tag) && tag !== "0"){
// url = url + `-wd-${tag}`
// }
// let resp = await this.fetch(url + ".html",null,this.getHeader())
// this.vodList = await this.parseVodShortListFromJson(JSON.parse(resp))
let url = this.siteUrl + `/list/${tid}-${pg}.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + "/search/"
let params = {"wd":wd,"p":"1","t":"j/tNgwBS2e8O4x9TuIkYuQ=="}
let html = await this.post(url,params,this.getSearchHeader())
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
}
let spider = new DyttSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+429
View File
@@ -0,0 +1,429 @@
/*
* @File : mxanime.js
* @Author : jade
* @Date : 2024/3/30 14:13
* @Email : [email protected]
* @Software : Samples
* @Desc : MX动漫
*/
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_, load} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
class MxAnimeSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.mxdm4.com/"
}
getName() {
return "🍒┃MX动漫┃🍒"
}
getAppName() {
return "MX动漫"
}
getJSName() {
return "mxanime"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav-menu-items\"]")[0]).find("[class=\"nav-menu-item \"]")
for (const navElement of navElements) {
let element = $(navElement).find("a")[0]
let type_name = element.attribs.title
let type_id = element.attribs.href
if (type_name !== "萌图") {
this.classes.push(this.getTypeDic(type_name, Utils.getStrByRegex(/type\/(.*?).html/, type_id)))
}
}
}
async getFilter($) {
let elements = $("[class=\"library-box scroll-box\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + `/type/${type_id}.html`)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
parseVodShortFromElement($, vodElement) {
let vodShort = new VodShort()
let element = $($(vodElement).find("[class=\"module-item-titlebox\"]")).find("a")[0]
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $($(vodElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
vodShort.vod_remarks = $($(vodElement).find("[class=\"module-item-text\"]")).text()
return vodShort
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $("[class=\"module-list module-lines-list mxone-box\"]").find("[class=\"module-item\"]")
for (const vodElement of vodElements) {
let vodShort = await this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $("[class=\"module-item\"]")
for (const vodElement of vodElements) {
let vodShort = await this.parseVodShortFromElement($, vodElement)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"module-search-item\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
let element = $(vodElement).find("[class=\"video-serial\"]")[0]
vodShort.vod_id = element.attribs.href
vodShort.vod_name = element.attribs.title
vodShort.vod_pic = $($(vodElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
let remarkElements = $($(vodElement).find("[class=\"video-info-item video-info-actor\"]").slice(-1)[0]).find("a")
let remark_list = []
for (const remarkElement of remarkElements){
let remark = remarkElement.children[0].data
remark_list.push(remark)
}
vodShort.vod_remarks = remark_list.join("*")
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
let vodElement = $("[class=\"video-info\"]")
vodDetail.vod_pic = $("[class=\"module-item-pic\"]").find("img")[0].attribs["data-src"]
vodDetail.vod_name = $($(vodElement).find("[class=\"page-title\"]")).text()
let classElements = $(vodElement).find("[class=\"video-info-items\"]")
for (const classElement of classElements){
let text = $(classElement).text().replaceAll("\n","").replaceAll("\t","").replaceAll(" ","") + "end"
if (text.indexOf("年份") > -1){
vodDetail.vod_year = Utils.getStrByRegex(/年份:(.*?)end/,text).replaceAll("/","")
}
if(text.indexOf("备注") > -1){
let x = Utils.getStrByRegex(/备注:(.*?)end/,text)
vodDetail.vod_remarks = Utils.getStrByRegex(/备注:\/(.*?)end/,text)
}
if (text.indexOf("标签") > -1){
vodDetail.type_name = Utils.getStrByRegex(/标签:(.*?)end/,text)
}
if (text.indexOf("剧情") > -1){
vodDetail.vod_content = Utils.getStrByRegex(/剧情:(.*?)end/,text)
}
}
let playFormatElemets = $("[class=\"module-tab-item tab-item\"]")
let playUrlElements = $("[class=\"scroll-content\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push(playFormatElement.attribs["data-dropdown-value"])
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtendValue(extent, key) {
if (extent[key] === undefined) {
return ""
} else {
if (extent[key] === "0") {
return ""
} else {
return extent[key]
}
}
}
async setCategory(tid, pg, filter, extend) {
await this.jadeLog.debug(`extend:${JSON.stringify(extend)}`)
let type = this.getExtendValue(extend, "1")
let time = this.getExtendValue(extend, "2")
let word = this.getExtendValue(extend, "3")
let sort = this.getExtendValue(extend, "4")
let urlParams = [tid.toString(), "", sort, type, "", word, "", "", pg.toString(), "", "", time]
let url = this.siteUrl + "/show/" + urlParams.join("-") + ".html"
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async setSearch(wd, quick) {
let url = this.siteUrl + `/search/${wd}-------------.html`
let $ = await this.getHtml(url)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playerConfig = JSON.parse(Utils.getStrByRegex(/var player_aaaa=(.*?)<\/script>/,$.html()))
const m3mu8_url = "https://danmu.yhdmjx.com/m3u8.php?url=" + playerConfig["url"]
const m3u8_res = await (await this.fetch(m3mu8_url,null,this.getHeader()));
const m3u8_result = m3u8_res.match(/"url": getVideoInfo\("(.*?)"\),/)[1];
const bt_token = m3u8_res.match(/<script>var bt_token = "(.*?)"/)[1];
let m3u8_token_key = await (await this.fetch("https://danmu.yhdmjx.com/js/play.js",null,this.getHeader()));
m3u8_token_key = m3u8_token_key.match(/var _token_key=CryptoJS\['enc'\]\['Utf8'\]\[_0x17f1\('67','qETJ'\)\]\((.*?\))/)[1];
m3u8_token_key = this.decrypt_token_key(m3u8_token_key);
this.playUrl = await this.getVideoInfo(m3u8_result, m3u8_token_key, bt_token);
}
decrypt_token_key(toekn_key){
var _0xod4 = 'jsjiami.com.v6',
_0x175e = [_0xod4, 'JMOsw6omwoDCmw==', 'wp3DkSx5Eg==', 'HB7CscOJfS3DuUjDv2bDjsOmwr3Cm8KcwoI=', 'fR/Dqg==', 'ShRGTcKa', 'w5Y8VBs=', 'esKYKQ==', 'FgIdwrPDnMKOw7k=', 'HhXCmA==', 'woNrRsKSwpnDvcKfw4g=', 'ezBn', 'w43DkcK5w4MaJiE=', 'w44Ob8KjwrjCrMKtUA==', 'HwtswqI=', 'YsKnwrRawro=', 'Sm/CpQXCjz4RH8ORSXw=', 'IsO6w64=', 'T8OeAQ==', 'VcK4Hg==', 'csOmfBJ4', 'd8OAcA5L', 'Tn4RL2s=', 'w7goGizCmw==', 'w6XDlcOGwpoY', 'TsK7wpNPwrg=', 'w7J1CzLCnsO+HA==', 'w4XDkcK0w5YXPg==', 'S8KoCcKS', 'PcKWHcK/Eg==', 'Z2oMJ3rCiw==', 'YsKMG8KMwo0=', 'QsOecgRIwp4=', 'dFzDkUUxw48Qw7nCmX3CicODCMKnw74IOg==', 'acO2KU1B', 'wrAnw6DDrg==', 'w5MsScKwwoA=', 'wohZG8KhBg==', 'b8OieSpZ', 'w4ZmEsORw6I=', 'w7jDhxvCh8KY', 'w7wQa8KFwr0=', 'IMObw4E3wqU=', 'JsOjw5Erwrg=', 'w6MwcsKOwqU=', 'b8KIwqF0wrs=', 'XhXDvT52', 'wrDCmirChSE=', 'w5t1wpvDuwE=', 'XA7CtsKeEA==', 'wonCvVthw78=', 'U8KPP8KMwq4=', 'wp7DhCxjGTU=', 'woPDoBdiEQ==', 'HjzCrE/Dvg==', 'SsOQOWHCgg==', 'w6NdwoXCkMOx', 'w6shYWQ/', 'eE/Cgg==', 'XW/Csj7CmDoA', 'w680OynCgcK5BA8=', 'w4PDoMOTwrog', 'w5R7wqbCpMOPwrMxUcOiM8OuMVLCisKKFsOXAcOWY8O6w5hM', 'WwjDoht0', 'PzXCiHHDiA==', 'QMOFaMKcfQ==', 'bz9bVsK+', 'w7Npwp/DsB9ONw==', 'EcOPBQ3Cig==', 'woHDnzk=', 'DsKQLxtd', 'R8OCJmk=', 'wp55O8On', 'bkXCmhTCqg==', 'w7vDgx3Cg8KU', 'w6nDo8KdAn8=', 'O8KwP8KEDw==', 'wqzCtCHCtCg=', 'w5nDgmYhw5c=', 'wp0OZsK+w4A=', 'wrFxe8KFwp/DvcKew4EbN8K7BMORMx3DuxtOVELChsOEIQ==', 'BMKWRDc=', 'IS5dw6nDhQ==', 'w6geeG8t', 'SsK/wohywpc=', 'LBlnw7jDkA==', 'wodiLsOg', 'Ig5Ow7/Dlw==', 'TMOOewRZwoQ=', 'LjnClV7DvA==', 'woZsO8KcPQ==', 'eWvClMKeKQ==', 'wq1KWsKswr8=', 'w4p+AGFa', 'C8O7F8K2CQcKFxxgwo5sfh3DpAFV', 'w6XDqMKoCw==', 'w6Z8wqnCpMOe', 'w6x/CHRhXhV/w7I=', 'wrvClndGw5Y=', 'VsKcwo5RwoA=', 'ZcK2BMKmLQ==', 'BCcPwofDvQ==', 'eGEsF20=', 'eMOcUglq', 'w4U9XEAMw4/Dm3rCuzpxTg/DvyDDvMONH8OTwpTCtsKbw6k=', 'VwXDkTxG', 'CzHCrl3DkQ==', 'w7PDkVovw4o=', 'dsONYDdj', 'w79pwr3Duh4=', 'w55kwoLCpMOR', 'w6gbc8KGwpw=', 'bCnCtMKCCg==', 'Php5w64=', 'w7x8wpfDtiQ=', 'w4TDk2AB', 'w7lowoHDtgQ=', 'DB/CsnjDuQ==', 'woTDl8K3wp4S', 'wr0Ewq7Dq8Oh', 'GmHCpGxN', 'w5/Dm2XDpw==', 'w5bDpsOCwqoA', 'YMKowphwwqc=', 'ahFuVsK9', 'w57DtEsbw7k=', 'w6LDo8Kq', 'UsKzE8KO', 'w6xlBFl9', 'WMOgIXbCiw==', 'DBhjw5fDhQ==', 'w6pUwoHCnsOs', 'ZF7CtsKiHg==', 'wos4w7wCwr0c', 'JlXCjlpyw5pMw6s=', 'TcO1N8K4wqE=', 'SMOzTcKYRw==', 'w4HDosOzwrUc', 'wqxdwqE2wrY=', 'A8OPGQjChw==', 'wpkxasOxBQ==', 'wpIZSA==', 'VsOnEEvChg==', 'bMOSZy93', 'c8OwZsKnRQ==', 'SsK/wpBHwoQ=', 'ccOsHVFf', 'w6ZKYMO8w6rDr8OrCHxdwqtdwrDDksOMccKZwobDpQPDgsOrAMKXF8OMPcOySsKuL8KLwq8vwr/DkjbDqsOCbRrCkcOTTFfDlsKkw7PChCM1wqTDisKawpHDt8KCQRY3w6DDgMKVw6M=', 'w7hYwq3ClsOa', 'Fic5wqLDiw==', 'KcKqHCVV', 'wqvDucKSwrs/', 'YcOfQcKPSQ==', 'wpjClmNRw7U=', 'wpHClSnCizg=', 'w4PDh8Kw', 'JsOYGwnCpw==', 'w5vDksK8w6sl', 'U8ORCHt+Rw==', 'woVxO8OSJQ==', 'b37Chw/Clw==', 'w6ViBXZlQg==', 'UwPCucKQCgU=', 'UMOeZgs=', 'MTLCtW7Dq2o=', 'wqAQwr/DqcOi', 'DiLDtsOOZsKEbsOrGm03EcKEwr/CplQ=', 'dzPDnRhP', 'wplgT8KBwow=', 'XUzCg8KF', 'K8KTCcKrCQ==', 'w6ZKJMOw', 'LxTCmn/DsA==', 'wooObcKBw6g=', 'w5djwofDoTQ=', 'VMOHeAts', 'Kw96w7bDig==', 'wogpw6crwps=', 'PDzDn8OcWQ==', 'wrfCoWxfw4E=', 'wrrDv8KDwoI+', 'w7hnwrjCssOq', 'w4LDrMOwwpMp', 'S2vCvyjCjic=', 'w6DDoT7CtcKNwoo=', 'wp1Lw5zCpj4=', 'RsOEGcKVwps=', 'woxlwo0twoM=', 'MAZYw7TDmg==', 'w7ENEC7CgA==', 'wolVw4jCryEqVMOYdg==', 'wp45w6cCwqY=', 'w6UhVHs1', 'QBZFW8KH', 'Ozhvw7vDkQ==', 'E8O4DAXCnA==', 'AcOXR8OZ', 'w4NhwqbCk8O6', 'f8OyScKpRRJTBQd9w4t3PgzCtRMQwrjDrUZ9Z8Od', 'A8OHw7Inwoc=', 'wqlQE8KHDg==', 'wqYbZMOVMg==', 'w57DuVwAw60=', 'W8OyQMKtVAk=', 'w60PBwXCng==', 'w4h7w70gw55WbHfDuR0VQ8K+asOxwoJn', 'w5rDhMK2w5gX', 'N0HCklc=', 'w58TTsK4wrg=', 'w7dXNMOhw79pwqBMw70=', 'SsKQCcKf', 'KSXCumrDug==', 'woc1w7gUwrEEw7s=', 'wplowqIvwoFGMQ==', 'acO9DcK+', 'UMKBwpJNwp1ZfA==', 'wpV+NsKCLQ==', 'w5PDrMOrwo4iwrcU', 'XHjCoyPCkw==', 'w5kOUsKkwqXCqcKm', 'QMKRAcKDDMK+AA==', 'bMKoNcKgwrc=', 'w6k0HTPClw==', 'wpUYYcOcBA==', 'w6k6BjnCnMK9', 'w5HDnncPw60=', 'jEsjiamLiI.coRVzmBz.v6gWBKxrg=='];
(function (_0x2410c8, _0x4731c1, _0x21bfda) {
var _0x12d6b4 = function (_0x56792e, _0x26ff38, _0x14a967, _0x1f013c, _0x21c988) {
_0x26ff38 = _0x26ff38 >> 0x8,
_0x21c988 = 'po';
var _0x10be12 = 'shift',
_0x47704d = 'push';
if (_0x26ff38 < _0x56792e) {
while (--_0x56792e) {
_0x1f013c = _0x2410c8[_0x10be12]();
if (_0x26ff38 === _0x56792e) {
_0x26ff38 = _0x1f013c;
_0x14a967 = _0x2410c8[_0x21c988 + 'p']();
} else if (_0x26ff38 && _0x14a967['replace'](/[ELIRVzBzgWBKxrg=]/g, '') === _0x26ff38) {
_0x2410c8[_0x47704d](_0x1f013c);
}
}
_0x2410c8[_0x47704d](_0x2410c8[_0x10be12]());
}
return 0xa44cc;
};
return _0x12d6b4(++_0x4731c1, _0x21bfda) >> _0x4731c1 ^ _0x21bfda;
}(_0x175e, 0x15c, 0x15c00));
var _0x17f1 = function (_0x3abb24, _0x9f8a97) {
_0x3abb24 = ~~'0x' ['concat'](_0x3abb24);
var _0x411694 = _0x175e[_0x3abb24];
if (_0x17f1['nIHPps'] === undefined) {
(function () {
var _0x264909 = typeof window !== 'undefined' ? window : typeof process === 'object' && typeof require === 'function' && typeof global === 'object' ? global : this;
var _0x52b78f = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
// _0x264909['atob'] || (_0x264909['atob'] = function (_0x202c2d) {
// var _0x2e97e4 = String(_0x202c2d)['replace'](/=+$/, '');
// for (var _0x488147 = 0x0,
// _0x1702c1, _0x5d977a, _0x1a87f9 = 0x0,
// _0x2378be = ''; _0x5d977a = _0x2e97e4['charAt'](_0x1a87f9++); ~_0x5d977a && (_0x1702c1 = _0x488147 % 0x4 ? _0x1702c1 * 0x40 + _0x5d977a : _0x5d977a, _0x488147++ % 0x4) ? _0x2378be += String['fromCharCode'](0xff & _0x1702c1 >> (-0x2 * _0x488147 & 0x6)) : 0x0) {
// _0x5d977a = _0x52b78f['indexOf'](_0x5d977a);
// }
// return _0x2378be;
// });
}());
var _0x5cedb3 = function (_0x19b8a7, _0x9f8a97) {
var _0x2b0e6a = [],
_0x4f25fe = 0x0,
_0x29acd8,
_0x2643f2 = '',
_0x58e8bd = '';
_0x19b8a7 = atob(_0x19b8a7);
for (var _0x1ac59f = 0x0,
_0x3346bd = _0x19b8a7['length']; _0x1ac59f < _0x3346bd; _0x1ac59f++) {
_0x58e8bd += '%' + ('00' + _0x19b8a7['charCodeAt'](_0x1ac59f)['toString'](0x10))['slice'](-0x2);
}
_0x19b8a7 = decodeURIComponent(_0x58e8bd);
for (var _0xb0c930 = 0x0; _0xb0c930 < 0x100; _0xb0c930++) {
_0x2b0e6a[_0xb0c930] = _0xb0c930;
}
for (_0xb0c930 = 0x0; _0xb0c930 < 0x100; _0xb0c930++) {
_0x4f25fe = (_0x4f25fe + _0x2b0e6a[_0xb0c930] + _0x9f8a97['charCodeAt'](_0xb0c930 % _0x9f8a97['length'])) % 0x100;
_0x29acd8 = _0x2b0e6a[_0xb0c930];
_0x2b0e6a[_0xb0c930] = _0x2b0e6a[_0x4f25fe];
_0x2b0e6a[_0x4f25fe] = _0x29acd8;
}
_0xb0c930 = 0x0;
_0x4f25fe = 0x0;
for (var _0x4f50dd = 0x0; _0x4f50dd < _0x19b8a7['length']; _0x4f50dd++) {
_0xb0c930 = (_0xb0c930 + 0x1) % 0x100;
_0x4f25fe = (_0x4f25fe + _0x2b0e6a[_0xb0c930]) % 0x100;
_0x29acd8 = _0x2b0e6a[_0xb0c930];
_0x2b0e6a[_0xb0c930] = _0x2b0e6a[_0x4f25fe];
_0x2b0e6a[_0x4f25fe] = _0x29acd8;
_0x2643f2 += String['fromCharCode'](_0x19b8a7['charCodeAt'](_0x4f50dd) ^ _0x2b0e6a[(_0x2b0e6a[_0xb0c930] + _0x2b0e6a[_0x4f25fe]) % 0x100]);
}
return _0x2643f2;
};
_0x17f1['RtnfNa'] = _0x5cedb3;
_0x17f1['afYpDj'] = {};
_0x17f1['nIHPps'] = !![];
}
var _0x5dc739 = _0x17f1['afYpDj'][_0x3abb24];
if (_0x5dc739 === undefined) {
if (_0x17f1['OqAPEJ'] === undefined) {
_0x17f1['OqAPEJ'] = !![];
}
_0x411694 = _0x17f1['RtnfNa'](_0x411694, _0x9f8a97);
_0x17f1['afYpDj'][_0x3abb24] = _0x411694;
} else {
_0x411694 = _0x5dc739;
}
return _0x411694;
};
return eval(toekn_key)
}
async getVideoInfo(data,key,iv) {
/*
Crypto v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var Crypto=Crypto||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
(function(){var u=Crypto,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=Crypto,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
(function(){var u=Crypto,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
l)}})();
Crypto.lib.Cipher||function(u){var p=Crypto,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
(function(){for(var u=Crypto,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
iv = Crypto.enc.Utf8.parse(iv);
key = Crypto.enc.Utf8.parse(key);
let result = Crypto.AES.decrypt(data, key,
{
iv : iv,
mode : Crypto.mode.CBC,
})
return Crypto.enc.Utf8.stringify(result).toString();
}
}
let spider = new MxAnimeSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+389
View File
@@ -0,0 +1,389 @@
/*
* @File : nangua.js
* @Author : jade
* @Date : 2024/3/18 10:54
* @Email : [email protected]
* @Software : Samples
* @Desc : 南瓜影视
*/
import {Crypto, jinja2, _} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
function stripHtmlTag(src) {
return src
.replace(/<\/?[^>]+(>|$)/g, '')
.replace(/&.{1,5};/g, '')
.replace(/\s{2,}/g, ' ');
}
function formatPlayUrl(src, name) {
return name
.trim()
.replaceAll(src, '')
.replace(/<|>|《|》/g, '')
.replace(/\$|#/g, ' ')
.trim();
}
class NanGuaSpider extends Spider {
constructor() {
super();
this.siteUrl = 'http://ys.changmengyun.com';
}
getName() {
return "🎃┃南瓜影视┃🎃"
}
getAppName() {
return "南瓜影视"
}
getJSName() {
return "nangua"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
getHeader() {
let t = new Date().getTime().toString();
return {
'version_name': '1.0.6',
'version_code': '6',
'package_name': 'com.app.nanguatv',
'sign': Crypto.MD5('c431ea542cee9679#uBFszdEM0oL0JRn@' + t).toString().toLowerCase(),
'imei': 'c431ea542cee9679',
'timeMillis': t,
'User-Agent': 'okhttp/4.6.0'
}
}
async setClasses() {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/home_nav', null, this.getHeader()));
for (const key in data) {
if (data[key].name !== '精选') this.classes.push({
type_id: data[key].id, type_name: data[key].name,
});
}
}
async setFilterObj() {
this.filterObj = {
"2": [{
"key": "class",
"name": "类型",
"value": [{"n": "全部", "v": "类型"}, {"n": "国产剧", "v": "国产剧"}, {"n": "港台剧", "v": "港台剧"}]
}, {
"key": "area", "name": "地区", "value": [{"n": "全部", "v": "地区"}, {"n": "内地", "v": "内地"}, {
"n": "香港地区", "v": "香港地区"
}, {"n": "台湾地区", "v": "台湾地区"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}], "1": [{
"key": "class", "name": "类型", "value": [{"n": "全部", "v": "类型"}, {"n": "动作片", "v": "动作片"}, {
"n": "喜剧片", "v": "喜剧片"
}, {"n": "爱情片", "v": "爱情片"}, {"n": "科幻片", "v": "科幻片"}, {
"n": "恐怖片", "v": "恐怖片"
}, {"n": "剧情片", "v": "剧情片"}, {"n": "战争片", "v": "战争片"}, {"n": "惊悚片", "v": "惊悚片"}]
}, {
"key": "area", "name": "地区", "value": [{"n": "全部", "v": "地区"}, {"n": "华语", "v": "华语"}, {
"n": "香港地区", "v": "香港地区"
}, {"n": "美国", "v": "美国"}, {"n": "欧洲", "v": "欧洲"}, {"n": "韩国", "v": "韩国"}, {
"n": "日本", "v": "日本"
}, {"n": "台湾地区", "v": "台湾地区"}, {"n": "泰国", "v": "泰国"}, {
"n": "台湾地区", "v": "台湾地区"
}, {"n": "印度", "v": "印度"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}], "4": [{
"key": "class", "name": "类型", "value": [{"n": "全部", "v": "类型"}, {"n": "国产漫", "v": "国产漫"}, {
"n": "欧美漫", "v": "欧美漫"
}, {"n": "日韩漫", "v": "日韩漫"}, {"n": "港台漫", "v": "港台漫"}]
}, {
"key": "area",
"name": "地区",
"value": [{"n": "全部", "v": "地区"}, {"n": "中国大陆", "v": "中国大陆"}, {
"n": "日本", "v": "日本"
}, {"n": "韩国", "v": "韩国"}, {"n": "欧美", "v": "欧美"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "新上线", "v": "新上线"}]
}, {
"key": "total",
"name": "状态",
"value": [{"n": "全部", "v": "状态"}, {"n": "连载", "v": "连载"}, {"n": "完结", "v": "完结"}]
}], "3": [{
"key": "class",
"name": "类型",
"value": [{"n": "全部", "v": "类型"}, {"n": "大陆", "v": "大陆"}, {"n": "港台", "v": "港台"}, {
"n": "日韩", "v": "日韩"
}, {"n": "欧美", "v": "欧美"}]
}, {
"key": "area",
"name": "地区",
"value": [{"n": "全部", "v": "地区"}, {"n": "内地", "v": "内地"}, {"n": "港台", "v": "港台"}, {
"n": "日韩", "v": "日韩"
}, {"n": "欧美", "v": "欧美"}, {"n": "其它", "v": "其它"}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "新上线", "v": "新上线"}]
}], "46": [{
"key": "class", "name": "类型", "value": [{"n": "全部", "v": "类型"}, {"n": "日韩剧", "v": "日韩剧"}, {
"n": "欧美剧", "v": "欧美剧"
}, {"n": "海外剧", "v": "海外剧"}]
}, {
"key": "area",
"name": "地区",
"value": [{"n": "全部", "v": "地区"}, {"n": "韩国", "v": "韩国"}, {"n": "美剧", "v": "美剧"}, {
"n": "日本", "v": "日本"
}, {"n": "泰国", "v": "泰国"}, {"n": "英国", "v": "英国"}, {"n": "新加坡", "v": "新加坡"}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "year",
"name": "年份",
"value": [{"n": "全部", "v": "年份"}, {"n": "2024", "v": "2024"}, {
"n": "2023",
"v": "2023"
}, {"n": "2022", "v": "2022"}, {
"n": "2021", "v": "2021"
}, {"n": "2020", "v": "2020"}, {"n": "2019", "v": "2019"}, {"n": "2018", "v": "2018"}, {
"n": "2017", "v": "2017"
}, {"n": "2016", "v": "2016"}, {"n": "2015", "v": "2015"}, {"n": "10年代", "v": "10年代"}, {
"n": "00年代", "v": "00年代"
}, {"n": "90年代", "v": "90年代"}, {"n": "80年代", "v": "80年代"}]
}, {
"key": "by", "name": "排序", "value": [{"n": "热播榜", "v": "热播榜"}, {"n": "好评榜", "v": "好评榜"}, {
"n": "新上线", "v": "新上线"
}]
}]
};
}
async parseVodShortListFromJSONByHome(obj) {
let vod_list = []
for (const data of obj["video"]) {
let video_vod_list = await this.parseVodShortListFromJson(data["data"])
vod_list.push(...video_vod_list)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj) {
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["name"]
vodShort.vod_pic = data["img"]
vodShort.vod_remarks = data["remarks"]
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = data["msg"]
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJsonBySearch(obj) {
let videos = [];
for (const data of obj){
let vodShort = new VodShort()
vodShort.vod_id = data["id"]
vodShort.vod_name = data["video_name"]
vodShort.vod_remarks = data["qingxidu"]
vodShort.vod_pic = Utils.formatUrl(data["img"])
videos.push(vodShort)
}
return videos
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
vodDetail.vod_id = obj["id"]
vodDetail.vod_name = obj["name"]
vodDetail.vod_pic = obj["img"]
vodDetail.type_name = obj["type"]
vodDetail.vod_year = obj["year"]
vodDetail.vod_content = stripHtmlTag(obj["info"])
vodDetail.vod_remarks = '更新至: ' + obj["msg"] + ' / 评分: ' + obj["score"]
let episodes = obj["player_info"];
let playlist = {};
episodes.forEach(function (it) {
let playurls = it["video_info"];
playurls.forEach(function (playurl) {
let source = it.show;
let t = formatPlayUrl(vodDetail.vod_name, playurl.name);
if (t.length === 0) t = playurl.name.trim();
if (!playlist.hasOwnProperty(source)) {
playlist[source] = [];
}
playlist[source].push(t + '$' + playurl.url);
});
});
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
let urls = _.values(playlist);
let vod_play_url = [];
urls.forEach(function (it) {
vod_play_url.push(it.join('#'));
});
vodDetail.vod_play_url = vod_play_url.join('$$$');
return vodDetail
}
async setHomeVod() {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/home_data?app=ylys&devices=android&imei=c431ea542cee9679&deviceModel=Subsystem%20for%20Android(TM)&deviceVersion=33&appVersionName=1.0.9&deviceScreen=427*250&appVersionCode=9&deviceBrand=Windows', null, this.getHeader()));
this.homeVodList = await this.parseVodShortListFromJSONByHome(data)
}
async setCategory(tid, pg, filter, extend) {
if (pg <= 0 || typeof (pg) == 'undefined') pg = 1;
let reqUrl = this.siteUrl + '/api.php/provide/vod_list?app=ylys&id=' + tid + '&page=' + pg + '&imei=c431ea542cee9679&';
reqUrl += jinja2('area={{ext.area}}&year={{ext.year}}&type={{ext.class}}&total={{ext.total}}&order={{ext.by}}', {ext: extend});
let data = JSON.parse(await this.fetch(reqUrl, null, this.getHeader())).list;
this.vodList = await this.parseVodShortListFromJson(data)
let pgChk = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/vod_list?app=ylys&id=' + tid + '&page=' + (parseInt(pg) + 1) + '&imei=c431ea542cee9679&', null, this.getHeader())).msg;
this.count = (pgChk === 'ok') ? parseInt(pg) + 1 : parseInt(pg);
this.limit = 20
this.total = this.limit * this.count
}
async setDetail(id) {
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/vod_detail?app=ylys&imei=c431ea542cee9679&id=' + id, null, this.getHeader())).data;
this.vodDetail = await this.parseVodDetailfromJson(data)
}
async setSearch(wd, quick, pg) {
let page = parseInt(pg)
const limit = 20
let data = JSON.parse(await this.fetch(this.siteUrl + '/api.php/provide/search_result_more?app=ylys&video_name=' + wd + `&pageSize=${limit}&tid=0&imei=c431ea542cee9679&page=${pg}`, null, this.getHeader())).data;
this.vodList = await this.parseVodShortListFromJsonBySearch(data)
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
async setPlay(flag, id, flags) {
try {
if (id.indexOf('m3u8') !== -1) {
this.playUrl = id.split('url=')[1]
} else if (id.indexOf(',') !== -1) {
let mjurl = id.split(',')[1]
let jData = JSON.parse(await this.fetch(mjurl, null, this.getHeader()));
this.playUrl = jData["data"]["url"]
} else {
let jData = JSON.parse(await this.fetch(id, null, this.getHeader()));
this.playUrl = jData["data"]["url"]
}
} catch (e) {
await this.jadeLog.error("播放失败")
}
}
}
let spider = new NanGuaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+261
View File
@@ -0,0 +1,261 @@
/*
* @File : newvision.js
* @Author : jade
* @Date : 2024/2/20 14:14
* @Email : [email protected]
* @Software : Samples
* @Desc : 新视觉影院
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {Crypto} from "../lib/cat.js";
class NewVisionSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.6080yy3.com"
}
getAppName() {
return "新视觉影院"
}
getName() {
return "🐼┃新视觉影院┃🐼"
}
getJSName() {
return "newvision"
}
getType() {
return 3
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav-menu-items\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = Utils.getStrByRegex(/\/vodtype\/(.*?).html/, navElement.attribs.href)
let type_name = navElement.attribs.title
if (Utils.isNumeric(type_id)) {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
let type_key_list = [3, 1, 11, 2]
for (let i = 0; i < elements.length; i++) {
let name = $($(elements[i]).find("a")[0]).text()
let extend_dic = {"key": name, "name": name, "value": []}
extend_dic["name"] = name
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
let type_id_list = Utils.getStrByRegex(/\/vodshow\/(.*?).html/, ele.attribs.href).split("-")
extend_dic["value"].push({
"n": $(ele).text(), "v": decodeURIComponent(type_id_list[type_key_list[i]])
})
}
extend_list.push(extend_dic)
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `/vodshow/${type_id}-----------.html`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const result of obj["Data"]["result"]){
let vodShort = new VodShort()
vodShort.vod_id = result["vod_url"].replaceAll(this.siteUrl,"")
vodShort.vod_pic = result["vod_pic"]
vodShort.vod_name = result["vod_name"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let html = $.html()
let vodDetail = new VodDetail()
let vodDetailElement = $("[class=\"box view-heading\"]")
vodDetail.vod_name = $($(vodDetailElement).find("[class=\"page-title\"]")).text()
let typeElements = $($(vodDetailElement).find("[class=\"tag-link\"]").find("a"))
vodDetail.vod_area = $($(vodDetailElement).find("[class=\"tag-link\"]").slice(-1)[0]).text()
let type_list = []
for (const typeElement of typeElements) {
type_list.push($(typeElement).text())
}
vodDetail.type_name = type_list.join("/")
let itemElements = $(vodDetailElement).find("[class=\"video-info-items\"]")
vodDetail.vod_director = $($(itemElements[0]).find("a")).text()
let actor_list = []
for (const actorElement of $(itemElements[1]).find("a")) {
actor_list.push($(actorElement).text())
}
vodDetail.vod_pic = $($(vodDetailElement).find("[class=\"module-item-pic\"]")).find("img")[0].attribs["data-src"]
vodDetail.vod_actor = actor_list.join("/")
vodDetail.vod_year = $($(itemElements[2]).find("[class=\"video-info-item\"]")).text()
vodDetail.vod_remarks = $($(itemElements[3]).find("[class=\"video-info-item\"]")).text()
vodDetail.vod_content = $($(itemElements[5]).find("[class=\"video-info-item video-info-content vod_content\"]")).text().replaceAll("\n", "\t").replaceAll("\t收起", "")
let playerformatElements = $("[class=\"module-tab-item tab-item\"]")
let playUrlElements = $("[class=\"scroll-content\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playerformatElements.length; i++) {
let playFormatElement = playerformatElements[i]
let format_name = playFormatElement.attribs["data-dropdown-value"]
if (format_name.indexOf("夸克") === -1) {
vod_play_from_list.push(format_name)
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let type_key_list = [3, 11, 1, 2]
if (extend["全部剧情"] !== undefined && extend["全部剧情"] !== "0") {
urlParams[type_key_list[0]] = extend["全部剧情"]
}
if (extend["全部时间"] !== undefined && extend["全部时间"] !== "0") {
urlParams[type_key_list[1]] = extend["全部时间"]
}
if (extend["全部地区"] !== undefined && extend["全部地区"] !== "0") {
urlParams[type_key_list[2]] = extend["全部地区"]
}
if (extend["时间排序"] !== undefined && extend["时间排序"] !== "0") {
urlParams[type_key_list[3]] = extend["时间排序"]
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let $ = await this.getHtml(reqUrl)
this.vodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
uic(url,uid){
let ut = Crypto.enc.Utf8.parse('2890'+uid+'tB959C')
let mm = Crypto.enc.Utf8.parse("2F131BE91247866E")
let decrypted = Crypto.AES.decrypt(url, ut, {iv: mm, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7});
return Crypto.enc.Utf8.stringify(decrypted);
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playUrl = $("[id=\"bfurl\"]")[0].attribs.href
if (playUrl.indexOf("http") > -1){
this.playUrl = playUrl
}else{
//需要解析URL,支持弹幕
let newUrl = "https://jiexi.xn--1lq90i13mxk5bolhm8k.xn--fiqs8s/player/ec.php?code=ak&if=1&url=" + playUrl
let play$ = await this.getHtml(newUrl)
let playHtml = play$.html()
let playConfig = JSON.parse(Utils.getStrByRegex(/let ConFig = (.*?),box = /,playHtml))
this.playUrl = this.uic(playConfig["url"],playConfig["config"]["uid"])
}
}
async setSearch(wd, quick) {
let url = `http://123.207.150.253/zxapi/public/?service=App.F.Fetch&req_p=${wd}&type=6080`
let content = await this.fetch(url,null,this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
}
let spider = new NewVisionSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+243
View File
@@ -0,0 +1,243 @@
/*
* @File : nivod.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {getHeader, createSign, desDecrypt, ChannelResponse, getVod} from "../lib/nivid_object.js"
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class NivodSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.nivodz.com"
}
getName() {
return "👑‍┃泥视频┃墙👑"
}
getAppName() {
return "泥视频"
}
getJSName() {
return "nivod"
}
getType() {
return 3
}
async setClasses() {
this.Remove18ChannelCode = parseInt(this.cfgObj["code"])
let url = this.siteUrl + "/show/channel/list/WEB/3.2" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let channelResponse = new ChannelResponse()
channelResponse.fromJsonString(content, this.Remove18ChannelCode)
let filterUrl = this.siteUrl + "/show/filter/condition/WEB/3.2" + await createSign()
let filterContent = desDecrypt(await this.post(filterUrl, null, getHeader()))
if (filterContent !== null) {
channelResponse.setChannelFilters(filterContent)
this.classes = channelResponse.getClassList()
this.filterObj = channelResponse.getFilters()
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const cate_dic of obj) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodDetailfromJson(vod_dic) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_dic["showIdCode"]
vodDetail.vod_name = vod_dic["showTitle"]
vodDetail.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
vodDetail.vod_pic = vod_dic["showImg"]
vodDetail.vod_director = vod_dic["director"]
vodDetail.vod_actor = vod_dic["actors"]
vodDetail.vod_year = vod_dic["postYear"]
vodDetail.vod_content = vod_dic["showDesc"]
vodDetail.type_name = vod_dic["showTypeName"]
vodDetail.vod_area = vod_dic["regionName"]
return vodDetail
}
getVodRemarks(hot, playResolutions) {
let vod_remarks
if (this.catOpenStatus) {
vod_remarks = `清晰度:${playResolutions[0]}`
} else {
vod_remarks = `清晰度:${playResolutions[0]},热度:${(Math.floor(parseInt(hot) / 1000)).toString()}k`
}
return vod_remarks
}
getExtendDic(extend, params) {
if (extend["5"] === undefined) {
delete params.year_range
} else {
if (extend["5"] === "0") {
delete params.year_range
} else {
params.year_range = extend["5"]
}
}
if (extend["1"] !== undefined) {
params.sort_by = extend["1"]
}
if (extend["2"] !== undefined) {
params.show_type_id = extend["2"]
}
if (extend["3"] !== undefined) {
params.region_id = extend["3"]
}
if (extend["4"] !== undefined) {
params.lang_id = extend["4"]
}
return params
}
async setHomeVod() {
let url = this.siteUrl + "/index/mobile/WAP/3.0" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let content_json = JSON.parse(content)
let cate_list = content_json.list
for (const cate_dic of cate_list) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
this.homeVodList.push(vodShort)
}
}
}
}
}
async setCategory(tid, pg, filter, extend) {
let params = {
"sort_by": "0",
"channel_id": tid.toString(),
"show_type_id": "0",
"region_id": "0",
"lang_id": "0",
"year_range": "2023",
"start": ((parseInt(pg) - 1) * 20).toString()
}
this.limit = 20;
params = this.getExtendDic(extend, params)
let url = this.siteUrl + "/show/filter/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod_dic["showIdCode"]
vodShort.vod_name = vod_dic["showTitle"]
vodShort.vod_pic = vod_dic["showImg"]
vodShort.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
this.vodList.push(vodShort)
}
}
}
async setDetail(id) {
let params = {
"show_id_code": id.toString()
}
let url = this.siteUrl + "/show/detail/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
let vod_dic = content_json["entity"]
this.vodDetail = await this.parseVodDetailfromJson(vod_dic)
let niBaVodDetail = getVod(vod_dic["plays"], ["原画"], id.toString())
this.vodDetail.vod_play_from = niBaVodDetail.vod_play_from
this.vodDetail.vod_play_url = niBaVodDetail.vod_play_url
}
}
async setSearch(wd, quick) {
let params = {"cat_id": "1", "keyword": wd, "keyword_type": "0", "start": "0"}
let url = this.siteUrl + "/show/search/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vod_detail = await this.parseVodDetailfromJson(vod_dic)
this.vodList.push(vod_detail)
}
}
}
async setPlay(flag, id, flags) {
let playId = id.split("@")[0]
let showId = id.split("@")[1]
let params = {
"show_id_code": showId,
"play_id_code": playId
}
let url = this.siteUrl + "/show/play/info/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params,getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
this.playUrl = content_json["entity"]["playUrl"]
}
}
}
let spider = new NivodSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+242
View File
@@ -0,0 +1,242 @@
/*
* @File : nivod18.js
* @Author : jade
* @Date : 2023/12/19 14:23
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {getHeader, createSign, desDecrypt, ChannelResponse, getVod} from "../lib/nivid_object.js"
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class Nivod18Spider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.nivodz.com"
}
getName() {
return "🔞┃泥视频18+┃🔞"
}
getAppName() {
return "泥视频18+"
}
getJSName() {
return "nivod_18"
}
getType() {
return 3
}
async setClasses() {
let url = this.siteUrl + "/show/channel/list/WEB/3.2" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let channelResponse = new ChannelResponse()
channelResponse.fromJsonString(content, 2)
let filterUrl = this.siteUrl + "/show/filter/condition/WEB/3.2" + await createSign()
let filterContent = desDecrypt(await this.post(filterUrl, null, getHeader()))
if (filterContent !== null) {
channelResponse.setChannelFilters(filterContent)
this.classes = channelResponse.getClassList()
this.filterObj = channelResponse.getFilters()
}
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const cate_dic of obj) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodDetailfromJson(vod_dic) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_dic["showIdCode"]
vodDetail.vod_name = vod_dic["showTitle"]
vodDetail.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
vodDetail.vod_pic = vod_dic["showImg"]
vodDetail.vod_director = vod_dic["director"]
vodDetail.vod_actor = vod_dic["actors"]
vodDetail.vod_year = vod_dic["postYear"]
vodDetail.vod_content = vod_dic["showDesc"]
vodDetail.type_name = vod_dic["showTypeName"]
vodDetail.vod_area = vod_dic["regionName"]
return vodDetail
}
getVodRemarks(hot, playResolutions) {
let vod_remarks
if (this.catOpenStatus) {
vod_remarks = `清晰度:${playResolutions[0]}`
} else {
vod_remarks = `清晰度:${playResolutions[0]},热度:${(Math.floor(parseInt(hot) / 1000)).toString()}k`
}
return vod_remarks
}
getExtendDic(extend, params) {
if (extend["5"] === undefined) {
delete params.year_range
} else {
if (extend["5"] === "0") {
delete params.year_range
} else {
params.year_range = extend["5"]
}
}
if (extend["1"] !== undefined) {
params.sort_by = extend["1"]
}
if (extend["2"] !== undefined) {
params.show_type_id = extend["2"]
}
if (extend["3"] !== undefined) {
params.region_id = extend["3"]
}
if (extend["4"] !== undefined) {
params.lang_id = extend["4"]
}
return params
}
async setHomeVod() {
let url = this.siteUrl + "/index/mobile/WAP/3.0" + await createSign()
let content = desDecrypt(await this.post(url, null, getHeader()))
if (content !== null) {
let content_json = JSON.parse(content)
let cate_list = content_json.list
for (const cate_dic of cate_list) {
for (const row of cate_dic.rows) {
for (const cells of row.cells) {
let vodShort = new VodShort()
vodShort.vod_id = cells.show["showIdCode"]
vodShort.vod_pic = cells.img
vodShort.vod_name = cells.title
vodShort.vod_remarks = this.getVodRemarks(cells.show["hot"], cells.show["playResolutions"])
this.homeVodList.push(vodShort)
}
}
}
}
}
async setCategory(tid, pg, filter, extend) {
let params = {
"sort_by": "0",
"channel_id": tid.toString(),
"show_type_id": "0",
"region_id": "0",
"lang_id": "0",
"year_range": "2023",
"start": ((parseInt(pg) - 1) * 20).toString()
}
this.limit = 20;
params = this.getExtendDic(extend, params)
let url = this.siteUrl + "/show/filter/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vodShort = new VodShort()
vodShort.vod_id = vod_dic["showIdCode"]
vodShort.vod_name = vod_dic["showTitle"]
vodShort.vod_pic = vod_dic["showImg"]
vodShort.vod_remarks = this.getVodRemarks(vod_dic["hot"], vod_dic["playResolutions"])
this.vodList.push(vodShort)
}
}
}
async setDetail(id) {
let params = {
"show_id_code": id.toString()
}
let url = this.siteUrl + "/show/detail/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
let vod_dic = content_json["entity"]
this.vodDetail = await this.parseVodDetailfromJson(vod_dic)
let niBaVodDetail = getVod(vod_dic["plays"], ["原画"], id.toString())
this.vodDetail.vod_play_from = niBaVodDetail.vod_play_from
this.vodDetail.vod_play_url = niBaVodDetail.vod_play_url
}
}
async setSearch(wd, quick) {
let params = {"cat_id": "1", "keyword": wd, "keyword_type": "0", "start": "0"}
let url = this.siteUrl + "/show/search/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params, getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
for (const vod_dic of content_json["list"]) {
let vod_detail = await this.parseVodDetailfromJson(vod_dic)
this.vodList.push(vod_detail)
}
}
}
async setPlay(flag, id, flags) {
let playId = id.split("@")[0]
let showId = id.split("@")[1]
let params = {
"show_id_code": showId,
"play_id_code": playId
}
let url = this.siteUrl + "/show/play/info/WEB/3.2" + await createSign(params)
let content = desDecrypt(await this.post(url, params,getHeader()))
if (content != null) {
let content_json = JSON.parse(content)
this.playUrl = content_json["entity"]["playUrl"]
}
}
}
let spider = new Nivod18Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+149
View File
@@ -0,0 +1,149 @@
/*
* @File : pan_search.js
* @Author : jade
* @Date : 2023/12/25 17:18
* @Email : [email protected]
* @Software : Samples
* @Desc : 阿里盘搜(仅支持搜搜)
*/
import {_, load} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import { detailContent,initCloud,playContent,getHeaders } from "../lib/cloud.js";
class PanSearchSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.pansearch.me/"
}
getName() {
return "🗂️┃阿里盘搜┃🗂️"
}
getAppName() {
return "阿里盘搜"
}
getJSName() {
return "pan_search"
}
getType() {
return 3
}
getSearchHeader() {
let headers = this.getHeader();
headers["x-nextjs-data"] = "1";
return headers;
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj);
}
async parseVodDetailfromJson(obj) {
let item = JSON.parse(obj)
let vodDetail = new VodDetail();
let splitList = item["content"].split("\n");
vodDetail.vod_name = splitList[0].replaceAll(/<\\?[^>]+>/g, "").replace("名称:", "");
let date = new Date(item["time"])
vodDetail.vod_remarks = date.toLocaleDateString().replace(/\//g, "-") + " " + date.toTimeString().substr(0, 8)
vodDetail.vod_pic = item["image"]
let share_url = ""
for (const content of splitList) {
if (content.indexOf("描述") > -1) {
vodDetail.vod_content = content.replace("描述:", "").replaceAll(/<\\?[^>]+>/g, "")
}
if (content.indexOf("标签:") > -1) {
vodDetail.type_name = content.replace("🏷 标签:", "")
}
if (content.indexOf("链接:") > -1) {
share_url = content.replaceAll(/<\\?[^>]+>/g, "").replace("链接:", "");
}
}
let playVod = await detailContent([share_url])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($, wd) {
let vod_list = []
let buildId = JSON.parse($("script[id=__NEXT_DATA__]")[0].children[0].data)["buildId"]
let url = this.siteUrl + "_next/data/" + buildId + "/search.json?keyword=" + encodeURIComponent(wd) + "&pan=aliyundrive";
let aliContent = await this.fetch(url, null, this.getSearchHeader())
if (!_.isEmpty(aliContent)) {
let items = JSON.parse(aliContent)["pageProps"]["data"]["data"]
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = JSON.stringify(item)
let splitList = item["content"].split("\n");
vodShort.vod_name = splitList[0].replaceAll(/<\\?[^>]+>/g, "").replace("名称:", "");
let date = new Date(item["time"])
vodShort.vod_remarks = date.toLocaleDateString().replace(/\//g, "-") + " " + date.toTimeString().substr(0, 8)
vodShort.vod_pic = item["image"]
vod_list.push(vodShort)
}
return vod_list
} else {
await this.jadeLog.error("搜索页面解析失败", true)
}
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailfromJson(id)
}
async setSearch(wd, quick) {
let html = await this.fetch(this.siteUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($, wd)
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
let spider = new PanSearchSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+459
View File
@@ -0,0 +1,459 @@
/*
* @File : pipixia.js
* @Author : jade
* @Date : 2024/2/2 13:33
* @Email : [email protected]
* @Software : Samples
* @Desc : 完成所有的功能开发(已失效)
*/
import {_, Crypto, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {pipixiaMd5} from "../lib/pipiXiaObject.js"
class PiPiXiaSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://aikun.tv/"
this.pipixiaReconnectTimes = 0
}
getHeader() {
let headers = super.getHeader();
headers["Connection"] = "keep-alive"
headers["Host"] = "pipixia.vip"
return headers
}
getName() {
return `🦐┃皮皮虾影视┃🦐`
}
getAppName() {
return `皮皮虾影视`
}
getJSName() {
return "pipixia"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodElements = $($("[class=\"wow fadeInUp animated\"]")).find("[class=\"public-list-box public-pic-b\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort()
vodShort.vod_id = Utils.getStrByRegex(/v\/(.*?).html/, $(vodElement).find("a")[0].attribs.href)
vodShort.vod_name = $(vodElement).find("a")[0].attribs.title
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + $(vodElement).find("[class=\"lazy gen-movie-img mask-1\"]")[0].attribs["data-original"])
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocBySearch($) {
let vod_list = []
let vodElements = $("[class=\"row-right hide\"]").find("[class=\"search-box flex rel\"]")
for (const vodElement of vodElements) {
let vodShort = new VodShort();
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + Utils.getStrByRegex(/url\((.*?)\);/, $(vodElement).find("[class=\"cover\"]")[0].attribs.style))
vodShort.vod_remarks = $($(vodElement).find("[class=\"public-list-prb hide ft2\"]")).html()
vodShort.vod_name = $($(vodElement).find("[class=\"thumb-txt cor4 hide\"]")).html()
vodShort.vod_id = Utils.getStrByRegex(/v\/(.*?).html/, $(vodElement).find("[class=\"button\"]")[0].attribs.href)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const vod_json of obj["list"]) {
let vodShort = new VodShort();
vodShort.vod_name = vod_json["vod_name"]
vodShort.vod_id = vod_json["vod_id"]
vodShort.vod_pic = this.baseProxy + Utils.base64Encode(this.siteUrl + "/" + vod_json["vod_pic"])
vodShort.vod_remarks = vod_json["vod_remarks"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let detailElement = $("[class=\"vod-detail style-detail rel box cor1\"]")
vodDetail.vod_name = $($(detailElement).find("[class=\"slide-info-title hide\"]")).text()
vodDetail.vod_pic = this.siteUrl + $(detailElement).find("[class=\"detail-pic lazy mask-1\"]")[0].attribs["data-original"]
vodDetail.vod_remarks = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[0]).text()
vodDetail.vod_year = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[1]).text()
vodDetail.vod_area = $($($(detailElement).find("[class=\"slide-info hide\"]")[0]).find("[class=\"slide-info-remarks\"]")[2]).text()
vodDetail.vod_director = $($($(detailElement).find("[class=\"slide-info hide\"]")[1]).find("a")).text()
vodDetail.vod_actor = $($($(detailElement).find("[class=\"slide-info hide\"]")[2]).find("a")).text()
let type_list = []
for (const typeEle of $($(detailElement).find("[class=\"slide-info hide\"]")[3]).find("a")) {
type_list.push($(typeEle).text())
}
vodDetail.type_name = type_list.join("/")
vodDetail.vod_content = $($("[class=\"check text selected cor3\"]")).text()
let playElemet = $("[class=\"anthology wow fadeInUp animated\"]")
let playFormatElemets = $(playElemet).find("[class=\"swiper-slide\"]")
let playUrlElements = $(playElemet).find("[class=\"anthology-list-play size\"]")
let vod_play_from_list = []
let vod_play_list = []
for (let i = 0; i < playFormatElemets.length; i++) {
let playFormatElement = playFormatElemets[i]
vod_play_from_list.push(playFormatElement.children[1].data)
let vodItems = []
for (const playUrlElement of $(playUrlElements[i]).find("a")) {
let episodeName = $(playUrlElement).text()
let episodeUrl = playUrlElement.attribs.href
vodItems.push(episodeName + "$" + episodeUrl)
}
vod_play_list.push(vodItems.join("#"))
}
vodDetail.vod_play_from = vod_play_from_list.join("$$$")
vodDetail.vod_play_url = vod_play_list.join("$$$")
return vodDetail
}
async getHtml(url = this.siteUrl, headers = this.getHeader()) {
try {
let html = await this.fetch(url, null, headers)
if (!_.isEmpty(html) && html.indexOf("江苏反诈公益宣传") === -1) {
return load(html)
} else {
if (this.pipixiaReconnectTimes < this.maxReconnectTimes) {
Utils.sleep(2)
this.pipixiaReconnectTimes = this.pipixiaReconnectTimes + 1
return await this.getHtml(url, headers)
} else {
await this.jadeLog.error(`html获取失败`, true)
}
}
} catch (e) {
await this.jadeLog.error(`获取html出错,出错原因为${e}`)
}
}
async setClasses() {
let $ = await this.getHtml()
this.classes = [this.getTypeDic("首页", "最近更新")]
let $2 = await this.getHtml(this.siteUrl + "/s/1.html")
let classElemets = $2("[class=\"nav-swiper rel\"]")[0]
for (const classElement of $(classElemets).find("a")) {
let type_id = Utils.getStrByRegex(/\/s\/(.*?).html/, classElement.attribs.href)
let type_name = $(classElement).text()
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
async getFilter($) {
let elements = $("[class=\"nav-swiper rel\"]")
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
let name = $($($(element).find("[class=\"filter-text bj cor5\"]")).find("span")).html()
if (name !== "频道") {
let extend_dic = {"key": (i + 1).toString(), "name": name, "value": []}
for (const ele of $(element).find("a")) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (Utils.isNumeric(type_id)) {
let url = this.siteUrl + `/s/${type_id}.html`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml(this.siteUrl + "/map.html")
this.homeVodList = await this.parseVodShortListFromDoc($)
}
getExtend(extend, key) {
if (extend[key] !== undefined && extend[key] !== "全部") {
return extend[key]
} else {
return null
}
}
getExtendDic(params, extend) {
let class_value = this.getExtend(extend, "2")
if (class_value !== null) {
params["class"] = class_value
}
let area_value = this.getExtend(extend, "3")
if (area_value !== null) {
params["area"] = area_value
}
let year_value = this.getExtend(extend, "4")
if (year_value !== null) {
params["year"] = year_value
}
let lang_value = this.getExtend(extend, "5")
if (lang_value !== null) {
params["lang"] = lang_value
}
let letter_value = this.getExtend(extend, "6")
if (letter_value !== null) {
params["letter"] = letter_value
}
return params
}
async setCategory(tid, pg, filter, extend) {
if (Utils.isNumeric(tid)) {
let url = this.siteUrl + "/index.php/api/vod"
let time_1 = Math.floor(new Date().getTime() / 1000)
let key_1 = pipixiaMd5(time_1)
let params = {
"type": tid, "page": pg, "time": time_1.toString(), "key": key_1
}
params = this.getExtendDic(params, extend)
let content = await this.post(url, params, this.getHeader())
if (!_.isEmpty(content)) {
let content_json = JSON.parse(content)
if (content_json["code"] === 1) {
this.vodList = await this.parseVodShortListFromJson(content_json)
}
}
}
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + `/v/${id}.html`)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async getPlayConfig(element) {
// let playJSUrl = this.siteUrl + element.attribs.src
// let jsContent = await this.fetch(playJSUrl,null,null)
// let playListConfig = JSON.parse(Utils.getStrByRegex(/MacPlayerConfig.player_list=(.*?),MacPlayerConfig/,jsContent))
//
let playListConfig = {
"qq": {
"show": "QQ虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "qiyi": {
"show": "QY虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qiyi&if=1&url="
}, "youku": {
"show": "YK虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=youku&if=1&url="
}, "mgtv": {
"show": "MG虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=mgtv&if=1&url="
}, "NBY": {
"show": "极速线路",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SLNB": {
"show": "三路极速",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "FYNB": {
"show": "APP专享线路",
"des": "",
"ps": "0",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SPA": {
"show": "极速A",
"des": "",
"ps": "0",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "SPB": {
"show": "极速B",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "kyB": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "JMZN": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "ZNJSON": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "znkan": {
"show": "极速直连",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "bilibili": {
"show": "BLBL虾线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "pptv": {
"show": "PP虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "letv": {
"show": "LE虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "sohu": {
"show": "SH虾线", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "DJMP4": {
"show": "短剧专用",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "CLDJ": {
"show": "短剧①",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "ChenXi": {
"show": "短剧专用2",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "HT-": {
"show": "自营线",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}, "htys": {
"show": "解说线路", "des": "", "ps": "1", "parse": "http://play.shijie.chat/player/?url="
}, "sgdj": {
"show": "短剧③",
"des": "",
"ps": "1",
"parse": "http://play.shijie.chat/player/ec.php?code=qq&if=1&url="
}
}
return playListConfig
}
uic(url, uid) {
let ut = Crypto.enc.Utf8.parse('2890' + uid + 'tB959C');
let mm = Crypto.enc.Utf8.parse("2F131BE91247866E");
let decrypted = Crypto.AES.decrypt(url, ut, {iv: mm, mode: Crypto.mode.CBC, padding: Crypto.pad.Pkcs7});
return Crypto.enc.Utf8.stringify(decrypted);
}
async setVideoProxy(playUrl){
let urls = []
urls.push('proxy');
urls.push(playUrl);
const pUrls = urls
for (let index = 1; index < pUrls.length; index += 2) {
pUrls[index] = js2Proxy(false, this.siteType, this.siteKey, 'hls/' + encodeURIComponent(pUrls[index]), {});
}
pUrls.push('original');
pUrls.push(playUrl);
return pUrls
}
async setPlay(flag, id, flags) {
let $ = await this.getHtml(this.siteUrl + id)
let playElements = $("[class=\"player-left\"]")
let scriptElements = $(playElements).find("script")
await this.jadeLog.debug($(scriptElements[0]).html())
let playConfig = JSON.parse($(scriptElements[0]).html().replaceAll("var player_aaaa=", ""))
let playListConfig = await this.getPlayConfig(scriptElements[1])
let jiexiUrl = playListConfig[playConfig["from"]]["parse"] + playConfig["url"]
let jiexi$ = await this.getHtml(jiexiUrl, {"User-Agent": Utils.CHROME})
let ConFig = JSON.parse(Utils.getStrByRegex(/let ConFig = (.*?),box = /, jiexi$.html()))
let playUrl = this.uic(ConFig["url"], ConFig.config.uid)
await this.jadeLog.debug(`播放链接为:${playUrl}`)
if (flag.indexOf("极速") > -1) {
this.playUrl = playUrl
} else {
if (this.catOpenStatus) {
this.playUrl = await this.setVideoProxy(playUrl)
} else {
this.playUrl = playUrl
}
}
}
async setSearch(wd, quick) {
let $ = await this.getHtml(this.siteUrl + `/vodsearch.html?wd=${decodeURI(wd)}`)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
let spider = new PiPiXiaSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
proxy: proxy,
search: search,
};
}
export {spider}
+115
View File
@@ -0,0 +1,115 @@
/*
* @File : push_agent.js
* @Author : jade
* @Date : 2024/3/6 9:30
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_} from "../lib/cat.js";
import {Spider} from "./spider.js";
import {VodDetail} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
import { detailContent,initCloud,playContent,getHeaders} from "../lib/cloud.js";
class PushSpider extends Spider {
constructor() {
super();
}
getName() {
return "┃推送┃"
}
getAppName() {
return "推送"
}
getJSName() {
return "push"
}
getType() {
return 4
}
async init(cfg) {
try {
this.cfgObj = await this.SpiderInit(cfg)
this.catOpenStatus = this.cfgObj.CatOpenStatus
await initCloud(this.cfgObj);
} catch (e) {
await this.jadeLog.error(`初始化失败,失败原因为:${e}`)
}
}
async check(args){
// CatVodOpen目前支持http链接和https链接
await spider.jadeLog.debug(`剪切板输入内容为:${args}`)
if (this.catOpenStatus){
return !!args.startsWith("http");
}else{
// TV目前支持http链接和https链接和Ftp和magnet等格式
return !!(args.startsWith("http") || args.startsWith("ftp") || args.startsWith("magnet"));
}
}
async parseVodDetailfromJson(id) {
let vodDetail = new VodDetail()
vodDetail.vod_pic = Utils.RESOURCEURL + "/resources/push.jpg"
let mather = Utils.patternAli.exec(id)
let quarkMatcher = Utils.patternQuark.exec(id)
if (mather !== null && mather.length > 0) {
let playVod = await detailContent([id])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
} else if (quarkMatcher !== null && quarkMatcher.length > 0){
let playVod = await detailContent([id])
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
}else {
vodDetail.vod_play_from = '推送';
vodDetail.vod_play_url = '推送$' + id;
}
return vodDetail
}
async setDetail(id) {
this.vodDetail = await this.parseVodDetailfromJson(id)
}
async setPlay(flag, id, flags) {
if (flag === "推送"){
this.playUrl = id
}else{
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
}
}
let spider = new PushSpider()
async function check(args) {
return await spider.check(args)
}
async function init(cfg) {
await spider.init(cfg)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
export function __jsEvalReturn() {
return {
support: check, init: init, detail: detail, play: play,
};
}
export {spider}
+251
View File
@@ -0,0 +1,251 @@
/*
* @File : sehuatang
* @Author : jade
* @Date : 2024/1/24 16:47
* @Email : [email protected]
* @Software : Samples
* @Desc : 色花堂BT
*/
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {_} from "../lib/cat.js";
class SHTSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.sehuatang.net"
}
getAppName() {
return "色花堂BT"
}
getName() {
return "🔞┃色花堂BT┃🔞"
}
getJSName() {
return "sehuatang"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.jsBaseDetail = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', {});
}
getHeader() {
return {
"User-Agent": "PostmanRuntime/7.36.1",
"Host": "www.sehuatang.net",
"Cookie": "cPNj_2132_saltkey=Q4BKEOEC; cf_clearance=6Gz2tvOXPkkJP2UhLnSsN4s0RrnDUy0jBN0kUvC5FNQ-1706109144-1-AebvwBnAURwWWQhj0QRBrRPku2n8xI73PIeuZVj2ckqY9zjQ7zFzDviX7Gkex1P1bUw9SXHGEYnkBB9nmWe6Nhk=; _safe=vqd37pjm4p5uodq339yzk6b7jdt6oich",
}
}
async parseVodShortListFromDoc($) {
let vod_list = []
let vodShortElements = $("[id=\"portal_block_43_content\"]").find("li")
for (const vodShortElement of vodShortElements) {
let vodShort = new VodShort()
vodShort.vod_remarks = $($(vodShortElement).find("a")[1]).text()
vodShort.vod_id = $(vodShortElement).find("a")[2].attribs["href"]
vodShort.vod_name = $(vodShortElement).find("a")[2].attribs["title"]
vodShort.vod_pic = this.jsBaseDetail + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromDocByCategory($) {
let vod_list = []
let vodElements = $($("[class=\"bm_c\"]")[0]).find("tbody")
for (const vodElement of vodElements) {
let user_name = $($($(vodElement).find("cite")).find("a")[0]).text()
if (user_name !== "admin" && user_name !== undefined && !_.isEmpty(user_name)) {
let vodShort = new VodShort()
vodShort.vod_id = $(vodElement).find("a")[0].attribs["href"]
vodShort.vod_remarks = $($(vodElement).find("a")[2]).text()
vodShort.vod_name = $($(vodElement).find("a")[3]).text()
vodShort.vod_pic = this.jsBaseDetail + Utils.base64Encode(vodShort.vod_id)
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail();
let vodElement = $("[class=\"t_f\"]")[0]
let content = $(vodElement).text().replaceAll("", ":").replaceAll("【", "").replaceAll("】", "")
vodDetail.vod_pic = $(vodElement).find("img")[0].attribs["file"]
vodDetail.vod_name = Utils.getStrByRegex(/影片名称(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_actor = Utils.getStrByRegex(/出演女优(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_remarks = Utils.getStrByRegex(/是否有码(.*?)\n/, content).replaceAll(":", "").replaceAll("\n", "")
vodDetail.vod_play_from = "BT"
vodDetail.vod_play_url = vodDetail.vod_name + "$" + Utils.getStrByRegex(/磁力链接: (.*)复制代码/, content)
return vodDetail
}
async setClasses() {
let $ = await this.getHtml()
let tagElements = $("[id=\"category_1\"]").find("tr").slice(0, -1)
for (const tagElement of tagElements) {
let classElements = $($(tagElement).find("[class=\"fl_icn_g\"]")).find("a")
for (const classElement of classElements) {
let type_id = classElement.attribs["href"]
let type_name = $(classElement).find("img")[0].attribs["alt"]
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
async getFilter($) {
let extend_list = []
let extend_dic1 = {"key": 1, "name": "类型", "value": []}
let typeElements = $("[id=\"thread_types\"]").find("a")
for (const typeElement of typeElements){
let type_name = ""
if (typeElement.children.length > 1){
type_name = typeElement.children[0].data + ":" + $(typeElement.children[1]).text()
}else{
type_name = typeElement.children[0].data
}
extend_dic1["value"].push({"n":type_name,"v":typeElement.attribs["href"]})
}
extend_list.push(extend_dic1)
let extend_dic2 = {"key": 1, "name": "主题", "value": []}
let themeElements = $("[class=\"tf\"]").find("a")
for (const themeElement of themeElements){
let type_name = $(themeElement).text()
if (type_name !== "更多" && type_name !== "显示置顶"){
extend_dic2["value"].push({"n":$(themeElement).text(),"v":themeElement.attribs["href"]})
}
}
extend_list.push(extend_dic2)
return extend_list
}
async setFilterObj() {
for (const class_dic of this.classes){
let type_name = class_dic["type_name"]
let type_id = class_dic["type_id"]
if (type_name !== "最近更新"){
let $ = await this.getHtml(this.siteUrl + '/' + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setCategory(tid, pg, filter, extend) {
if (extend["1"]!==undefined && extend[1] ==="javascript:;"){
}else{
tid = extend["1"] ?? tid
}
let cateUrl
let tid_list = tid.split(".")[0].split("-")
if (tid_list.length > 2){
tid_list[2] = pg
cateUrl = this.siteUrl + "/" + tid_list.join("-") + ".html"
}else{
cateUrl = this.siteUrl + "/" + tid + "&page=" + pg
}
let $ = await this.getHtml(cateUrl)
this.vodList = await this.parseVodShortListFromDocByCategory($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + "/" + id)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
if (what === 'detail') {
await this.jadeLog.debug(`反向代理ID为:${url}`)
let $ = await this.getHtml(this.siteUrl + "/" + url)
let vodDetail = await this.parseVodDetailFromDoc($)
await this.jadeLog.debug(`图片地址为:${vodDetail.vod_pic}`)
let resp;
if (!_.isEmpty(headers)) {
resp = await req(vodDetail.vod_pic, {
buffer: 2, headers: headers
});
} else {
resp = await req(vodDetail.vod_pic, {
buffer: 2, headers: {
Referer: url, 'User-Agent': Utils.CHROME,
},
});
}
return JSON.stringify({
code: resp.code, buffer: 2, content: resp.content, headers: resp.headers,
});
}
return JSON.stringify({
code: 500, content: '',
});
}
}
let spider = new SHTSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+672
View File
@@ -0,0 +1,672 @@
/*
* @File : sp360.js
* @Author : jade
* @Date : 2024/3/21 11:18
* @Email : [email protected]
* @Software : Samples
* @Desc : SP360(需要用到解析)
*/
import {Spider} from "./spider.js";
import {_, Crypto, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import * as Utils from "../lib/utils.js";
class Sp360Spider extends Spider {
constructor() {
super();
this.siteUrl = "https://api.web.360kan.com"
}
getName() {
return "🥎┃360影视┃🥎"
}
getAppName() {
return "360"
}
getJSName() {
return "sp360"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
async setClasses() {
this.classes = [this.getTypeDic("最近更新", "最近更新"), this.getTypeDic("电影", "1"), this.getTypeDic("剧集", "2"), this.getTypeDic("综艺", "3"), this.getTypeDic("动漫", "4")]
}
async setFilterObj() {
this.filterObj = {
"1": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "爱情", "v": "爱情"
}, {
"n": "动作", "v": "动作"
}, {
"n": "恐怖", "v": "恐怖"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "剧情", "v": "剧情"
}, {
"n": "犯罪", "v": "犯罪"
}, {
"n": "奇幻", "v": "奇幻"
}, {
"n": "战争", "v": "战争"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "动画", "v": "动画"
}, {
"n": "文艺", "v": "文艺"
}, {
"n": "纪录", "v": "纪录"
}, {
"n": "传记", "v": "传记"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "古装", "v": "古装"
}, {
"n": "历史", "v": "历史"
}, {
"n": "惊悚", "v": "惊悚"
}, {
"n": "伦理", "v": "伦理"
}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "更早", "v": "lt_year"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "美国", "v": "美国"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "法国", "v": "法国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "德国", "v": "德国"
}, {
"n": "印度", "v": "印度"
}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}, {
"n": "最受好评", "v": "rankpoint"
}]
}], "2": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "言情", "v": "言情"
}, {
"n": "剧情", "v": "剧情"
}, {
"n": "伦理", "v": "伦理"
}, {
"n": "喜剧", "v": "喜剧"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "都市", "v": "都市"
}, {
"n": "偶像", "v": "偶像"
}, {
"n": "古装", "v": "古装"
}, {
"n": "军事", "v": "军事"
}, {
"n": "警匪", "v": "警匪"
}, {
"n": "历史", "v": "历史"
}, {
"n": "励志", "v": "励志"
}, {
"n": "神话", "v": "神话"
}, {
"n": "谍战", "v": "谍战"
}, {
"n": "青春", "v": "青春剧"
}, {
"n": "家庭", "v": "家庭剧"
}, {
"n": "动作", "v": "动作"
}, {
"n": "情景", "v": "情景"
}, {
"n": "武侠", "v": "武侠"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "其他", "v": "其他"
}, {
"n": "全部", "v": ""
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "更早", "v": "lt_year"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "内地"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "泰国", "v": "泰国"
}, {
"n": "日本", "v": "日本"
}, {
"n": "韩国", "v": "韩国"
}, {
"n": "美国", "v": "美国"
}, {
"n": "英国", "v": "英国"
}, {
"n": "新加坡", "v": "新加坡"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}, {
"n": "最受好评", "v": "rankpoint"
}]
}], "3": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "脱口秀", "v": "脱口秀"
}, {
"n": "真人秀", "v": "真人秀"
}, {
"n": "搞笑", "v": "搞笑"
}, {
"n": "选秀", "v": "选秀"
}, {
"n": "八卦", "v": "八卦"
}, {
"n": "访谈", "v": "访谈"
}, {
"n": "情感", "v": "情感"
}, {
"n": "生活", "v": "生活"
}, {
"n": "晚会", "v": "晚会"
}, {
"n": "音乐", "v": "音乐"
}, {
"n": "职场", "v": "职场"
}, {
"n": "美食", "v": "美食"
}, {
"n": "时尚", "v": "时尚"
}, {
"n": "游戏", "v": "游戏"
}, {
"n": "少儿", "v": "少儿"
}, {
"n": "体育", "v": "体育"
}, {
"n": "纪实", "v": "纪实"
}, {
"n": "科教", "v": "科教"
}, {
"n": "曲艺", "v": "曲艺"
}, {
"n": "歌舞", "v": "歌舞"
}, {
"n": "财经", "v": "财经"
}, {
"n": "汽车", "v": "汽车"
}, {
"n": "播报", "v": "播报"
}, {
"n": "其他", "v": "其他"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "中国香港", "v": "香港"
}, {
"n": "中国台湾", "v": "台湾"
}, {
"n": "日本", "v": "日本"
}, {
"n": "欧美", "v": "欧美"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}]
}], "4": [{
"key": "cat", "name": "类型", "value": [{
"n": "全部", "v": ""
}, {
"n": "热血", "v": "热血"
}, {
"n": "科幻", "v": "科幻"
}, {
"n": "美少女", "v": "美少女"
}, {
"n": "魔幻", "v": "魔幻"
}, {
"n": "经典", "v": "经典"
}, {
"n": "励志", "v": "励志"
}, {
"n": "少儿", "v": "少儿"
}, {
"n": "冒险", "v": "冒险"
}, {
"n": "搞笑", "v": "搞笑"
}, {
"n": "推理", "v": "推理"
}, {
"n": "恋爱", "v": "恋爱"
}, {
"n": "治愈", "v": "治愈"
}, {
"n": "幻想", "v": "幻想"
}, {
"n": "校园", "v": "校园"
}, {
"n": "动物", "v": "动物"
}, {
"n": "机战", "v": "机战"
}, {
"n": "亲子", "v": "亲子"
}, {
"n": "儿歌", "v": "儿歌"
}, {
"n": "运动", "v": "运动"
}, {
"n": "悬疑", "v": "悬疑"
}, {
"n": "怪物", "v": "怪物"
}, {
"n": "战争", "v": "战争"
}, {
"n": "益智", "v": "益智"
}, {
"n": "青春", "v": "青春"
}, {
"n": "童话", "v": "童话"
}, {
"n": "竞技", "v": "竞技"
}, {
"n": "动作", "v": "动作"
}, {
"n": "社会", "v": "社会"
}, {
"n": "友情", "v": "友情"
}, {
"n": "真人版", "v": "真人版"
}, {
"n": "电影版", "v": "电影版"
}, {
"n": "OVA版", "v": "OVA版"
}, {
"n": "TV版", "v": "TV版"
}, {
"n": "新番动画", "v": "新番动画"
}, {
"n": "完结动画", "v": "完结动画"
}]
}, {
"key": "year", "name": "年代", "value": [{
"n": "全部", "v": ""
}, {
"n": "2024", "v": "2024"
}, {
"n": "2023", "v": "2023"
}, {
"n": "2022", "v": "2022"
}, {
"n": "2021", "v": "2021"
}, {
"n": "2020", "v": "2020"
}, {
"n": "2019", "v": "2019"
}, {
"n": "2018", "v": "2018"
}, {
"n": "2017", "v": "2017"
}, {
"n": "2016", "v": "2016"
}, {
"n": "2015", "v": "2015"
}, {
"n": "2014", "v": "2014"
}, {
"n": "2013", "v": "2013"
}, {
"n": "2012", "v": "2012"
}, {
"n": "2011", "v": "2011"
}, {
"n": "2010", "v": "2010"
}, {
"n": "2009", "v": "2009"
}, {
"n": "2008", "v": "2008"
}, {
"n": "2007", "v": "2007"
}, {
"n": "2006", "v": "2006"
}, {
"n": "2005", "v": "2005"
}, {
"n": "2004", "v": "2004"
}, {
"n": "更早", "v": "更早"
}]
}, {
"key": "area", "name": "地区", "value": [{
"n": "全部", "v": ""
}, {
"n": "内地", "v": "大陆"
}, {
"n": "日本", "v": "日本"
}, {
"n": "美国", "v": "美国"
}]
}, {
"key": "rank", "name": "排序", "value": [{
"n": "最近热映", "v": "rankhot"
}, {
"n": "最近上映", "v": "ranklatest"
}]
}]
}
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const data of obj["data"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["ent_id"] + "+" + data["cat"]
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["title"]
vodShort.vod_remarks = data["upinfo"]
vod_list.push(vodShort)
}
return vod_list
}
async parseVodShortListFromJsonByCategory(obj, tid) {
let vod_list = []
for (const data of obj["data"]["movies"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["id"] + "+" + tid
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["title"]
vodShort.vod_remarks = data["tag"]
if (!_.isEmpty(data["doubanscore"])) {
vodShort.vod_remarks = "豆瓣评分:" + data["doubanscore"]
} else {
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = data["pubdate"]
}
}
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailfromJson(obj) {
let vodDetail = new VodDetail()
let data = obj["data"]
vodDetail.vod_name = data["title"]
vodDetail.vod_pic = data["cdncover"]
vodDetail.vod_remarks = data["pubdate"]
vodDetail.vod_actor = data["actor"].join("*")
vodDetail.vod_director = data["director"].join("*")
vodDetail.type_name = data["moviecategory"].join("*")
vodDetail.vod_year = data["pubdate"]
vodDetail.vod_area = data["area"].join("*")
vodDetail.vod_content = data["description"]
let playlist = {}
for (const playFormat of data["playlink_sites"]) {
let vodItems = []
if (!_.isEmpty(data["allepidetail"])) {
if (data["allepidetail"][playFormat] !== undefined) {
for (const items of data["allepidetail"][playFormat]) {
let episodeUrl = items["url"]
let episodeName = items["playlink_num"]
vodItems.push(episodeName + "$" + episodeUrl);
}
}
} else {
let items = data["playlinksdetail"][playFormat]
let episodeUrl = items["default_url"]
let episodeName = items["quality"]
vodItems.push(episodeName + "$" + episodeUrl);
}
if (vodItems.length > 0){
playlist[playFormat] = vodItems.join("#")
}
}
vodDetail.vod_play_url = _.values(playlist).join('$$$');
vodDetail.vod_play_from = _.keys(playlist).join('$$$');
return vodDetail
}
async parseVodShortListFromJsonBySearch(obj) {
let vod_list = []
for (const data of obj["data"]["longData"]["rows"]) {
let vodShort = new VodShort();
vodShort.vod_id = data["en_id"] + "+" + data["cat_id"]
if (!data["cover"].startsWith("http")) {
vodShort.vod_pic = "https:" + data["cover"]
} else {
vodShort.vod_pic = data["cover"]
}
vodShort.vod_name = data["titleTxt"]
vodShort.vod_remarks = data["coverInfo"]["txt"]
vod_list.push(vodShort)
}
return vod_list
}
async setHomeVod() {
let response = await this.fetch(this.siteUrl + "/v1/rank?cat=1", null, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(response))
}
async setCategory(tid, pg, filter, extend) {
let rank = extend["by"] ?? "rankhot"
let year = extend["year"] ?? ""
let cat = extend["cat"] ?? ""
let area = extend["area"] ?? ""
let url = this.siteUrl + `/v1/filter/list?catid=${tid}&rank=${rank}&cat=${cat}&year=${year}&area=${area}&act=&size=35&pageno=${pg}&callback=`
let response = await this.fetch(url, null, this.getHeader())
this.vodList = await this.parseVodShortListFromJsonByCategory(JSON.parse(response), tid)
}
async setDetail(id) {
let tid_list = id.split("+")
let url = this.siteUrl + `/v1/detail?cat=${tid_list[1]}&id=${tid_list[0]}`
let response = await this.fetch(url, null, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(response))
}
async setSearch(wd, quick) {
let url = `https://api.so.360kan.com/index?force_v=1&kw=${wd}&from=&pageno=1&v_ap=1&tab=all`
let response = await this.fetch(url, null, this.getHeader())
this.vodList = await this.parseVodShortListFromJsonBySearch(JSON.parse(response))
}
async setPlay(flag, id, flags) {
if (this.danmuStaus && ! this.catOpenStatus) {
this.danmuUrl = await this.danmuSpider.getVideoUrl(id, 0)
}
this.result.parse = 1 //启用自动解析
this.result.jx = 1
this.playUrl = id
}
}
let spider = new Sp360Spider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+901
View File
@@ -0,0 +1,901 @@
/*
* @File : spider.js
* @Author : jade
* @Date : 2023/12/25 17:19
* @Email : [email protected]
* @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}
+290
View File
@@ -0,0 +1,290 @@
/*
* @File : star.js
* @Author : jade
* @Date : 2024/2/21 10:36
* @Email : [email protected]
* @Software : Samples
* @Desc : 星视界 需要翻墙
*/
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
class StarSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.histar.tv"
this.apiUrl = "https://aws.ulivetv.net"
}
getAppName() {
return "星视界"
}
getName() {
return "☄️┃星视界┃墙☄️"
}
getJSName() {
return "star"
}
getType() {
return 3
}
getApiHeader() {
return {'User-Agent': Utils.MOBILEUA, "Content-Type": 'application/json'}
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $($("[class=\"nav_nav__zgz60\"]")[0]).find("a")
for (const navElement of navElements) {
let type_id = navElement.attribs.href
let type_name = $(navElement).text()
if (type_id !== "/" && type_name !== "电视直播") {
this.classes.push(this.getTypeDic(type_name, type_id))
}
}
}
convertTypeData(typeData, key, name) {
if (!typeData || !typeData[key] || typeData[key].length <= 2) {
return null;
}
let valueList = typeData[key];
if (key === 'time') {
valueList = valueList.sort((a, b) => {
return b - a;
});
valueList.pop();
}
const values = _.map(valueList, (item) => {
let name;
let value;
if (item instanceof Array) {
name = item[0];
value = item[0];
} else {
name = item.toString();
value = item.toString();
}
return {
n: name, v: value,
};
});
values.unshift({
n: '全部', v: '',
});
return {
key: key, name: name, init: '', value: values,
};
}
async getFilter($) {
const json = $('#__NEXT_DATA__')[0].children[0].data;
const obj = JSON.parse(json).props["pageProps"]["filterCondition"];
const label = this.convertTypeData(obj, 'label', '类型');
const country = this.convertTypeData(obj, 'country', '地区');
const time = this.convertTypeData(obj, 'time', '年份');
return [label, country, time];
}
async setFilterObj() {
for (const type_dic of this.classes.slice(0, 4)) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let url = this.siteUrl + `${type_id}/all/all/all`
let $ = await this.getHtml(url)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
parseVodShortFromtJson(obj) {
let vodShort = new VodShort()
vodShort.vod_id = obj["id"]
vodShort.vod_name = obj["name"]
vodShort.vod_pic = obj["img"]
if (_.isEmpty(vodShort.vod_pic)) {
vodShort.vod_pic = obj["picurl"] ?? ""
}
vodShort.vod_remarks = obj["countStr"]
if (_.isEmpty(vodShort.vod_remarks)) {
vodShort.vod_remarks = obj["time"]
}
return vodShort
}
async parseVodShortListFromJson(obj) {
let vod_list = []
for (const results of obj) {
let name = results["name"]
if (name !== "电视直播") {
let cards = results["cards"]
for (const result of cards) {
let vodShort = this.parseVodShortFromtJson(result)
vod_list.push(vodShort)
}
}
}
return vod_list
}
async parseVodShortListFromJsonByCategory(obj) {
let vod_list = []
for (const result of obj.list) {
let vodShort = this.parseVodShortFromtJson(result)
vod_list.push(vodShort)
}
return vod_list
}
getObjectValues(objList,key){
let value_list = []
for (const result of objList){
value_list.push(result[key])
}
return value_list
}
async parseVodDetailfromJson(obj) {
const vObj = obj["collectionInfo"];
let vodDetail = new VodDetail();
vodDetail.vod_name = vObj["name"]
vodDetail.type_name = vObj["chname"]
vodDetail.vod_pic = vObj["picurl"]
vodDetail.vod_area = vObj["country"]
vodDetail.vod_remarks = vObj["countStr"]
vodDetail.vod_actor = this.getObjectValues(vObj["actor"],"name").join("/")
vodDetail.vod_director = this.getObjectValues(vObj["director"],"name").join("/")
vodDetail.vod_content = vObj["desc"]
const playInfo = vObj["videosGroup"];
const playVod = {};
_.each(playInfo, (info) => {
const sourceName = info.name;
let playList = '';
const videoInfo = info["videos"];
const vodItems = _.map(videoInfo, (epObj) => {
const epName = "第" + epObj["eporder"] + "集";
const playUrl = epObj["purl"]
return epName + '$' + playUrl;
});
if (_.isEmpty(vodItems)) return;
playList = vodItems.join('#');
playVod[sourceName] = playList;
});
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setHomeVod() {
let json = await this.fetch(this.apiUrl + "/v3/web/api/home?chName=首页", null, this.getApiHeader())
const obj = JSON.parse(json)["data"]["cardsGroup"];
this.homeVodList = await this.parseVodShortListFromJson(obj)
}
getClassChName(tid) {
for (const class_dic of this.classes) {
if (tid === class_dic["type_id"]) {
return class_dic["type_name"]
}
}
}
async setCategory(tid, pg, filter, extend) {
this.limit = 16;
const param = {
chName: this.getClassChName(tid), page: parseInt(pg), pageSize: this.limit
};
if (extend["label"] !== undefined) {
param["label"] = extend["label"]
}
if (extend["country"] !== undefined) {
param["country"] = extend["country"]
}
if (extend["time"] !== undefined) {
const year = parseInt(extend["time"]);
param["startTime"] = year;
param["endTime"] = year;
}
const json = await this.post(this.apiUrl + '/v3/web/api/filter', JSON.stringify(param), {
'User-Agent': Utils.MOBILEUA, "Content-Type": 'application/json'
}, "")
const data = JSON.parse(json).data;
this.vodList = await this.parseVodShortListFromJsonByCategory(data)
this.count = Math.floor(data["total"] / this.limit);
this.total = data.total
}
async setDetail(id) {
const $ = await this.getHtml(this.siteUrl + '/vod/detail/' + id);
const json = $('#__NEXT_DATA__')[0].children[0].data;
const obj = JSON.parse(json).props["pageProps"];
this.vodDetail = await this.parseVodDetailfromJson(obj)
}
async setSearch(wd, quick) {
const limit = 20;
const param = {
word: wd, page: 1, pageSize: limit,
};
const json = await this.post(this.apiUrl + '/v3/web/api/search', JSON.stringify(param), this.getApiHeader(), "");
const data = JSON.parse(json).data;
this.vodList = await this.parseVodShortListFromJsonByCategory(data)
}
}
let spider = new StarSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+128
View File
@@ -0,0 +1,128 @@
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};
+286
View File
@@ -0,0 +1,286 @@
/*
* @File : tiantian.js
* @Author : jade
* @Date : 2024/04/15 10:48
* @Email : [email protected]
* @Software : Samples
* @Desc : 天天影视
*/
import {Spider} from "./spider.js";
import {_} from "../lib/cat.js";
import * as Utils from "../lib/utils.js";
import {VodDetail, VodShort} from "../lib/vod.js";
class TianTianSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://op.ysdqjs.cn"
this.cookie = ""
this.extendObj = {"extend": "类型", "area": "地区", "year": "年代"}
this.parseMap = {};
}
async request(reqUrl, method, data) {
const headers = {
'User-Agent': Utils.CHROME,
};
if (!_.isEmpty(this.cookie)) {
headers['Cookie'] = this.cookie;
}
const postType = method === 'post' ? 'form-data' : '';
let res = await req(reqUrl, {
method: method || 'get', headers: headers, data: data, postType: postType,
});
if (res.code === 403) {
const path = res.data.match(/window\.location\.href ="(.*?)"/)[1];
this.cookie = _.isArray(res.headers['set-cookie']) ? res.headers['set-cookie'].join(';') : res.headers['set-cookie'];
headers['Cookie'] = this.cookie;
res = await req(this.siteUrl + path, {
method: method || 'get', headers: headers, data: data, postType: postType,
});
}
return res.content;
}
async postData(url, data) {
const timestamp = Math.floor(new Date().getTime() / 1000);
const key = 'kj5649ertj84ks89r4jh8s45hf84hjfds04k';
const sign = md5X(key + timestamp).toString();
let defaultData = {
sign: sign, timestamp: timestamp,
};
const reqData = data ? _.merge(defaultData, data) : defaultData;
return await this.request(url, 'post', reqData);
}
getName() {
return "⛄┃天天影视┃⛄"
}
getAppName() {
return "天天影视"
}
getJSName() {
return "tiantian"
}
getType() {
return 3
}
async init(cfg) {
await super.init(cfg);
this.danmuStaus = true
}
generateParam(tid, pg, extend, limit) {
const param = {
type_id: tid, page: pg, limit: limit,
};
if (extend["extend"] !== undefined && extend["extend"] !== "全部") {
param.class = extend["extend"];
}
if (extend["area"] !== undefined && extend["area"] !== "全部") {
param.area = extend.area;
}
if (extend["lang"] !== undefined && extend["lang"] !== "全部") {
param.lang = extend.lang;
}
if (extend["year"] !== undefined && extend["year"] !== "全部") {
param.year = extend.year;
}
return param;
}
async getFilter(data) {
let extend_list = []
Object.keys(data).forEach(key => {
if (Array.isArray(data[key])) {
if (!_.isEmpty(this.extendObj[key])) {
let extend_dic = {"key": key, "name": this.extendObj[key], "value": []}
let add_year_status = false
for (const extend_data of data[key]) {
if (key === "year") {
if (!data[key].includes("2024") && extend_data !== "全部" && !add_year_status) {
extend_dic["value"].push({"n": "2024", "v": "2024"})
add_year_status = true
}
}
if (!_.isEmpty(extend_data)) {
extend_dic["value"].push({"n": extend_data, "v": extend_data})
}
}
if (extend_dic["value"].length > 1) {
extend_list.push(extend_dic)
}
}
}
})
return extend_list
}
async setClasses() {
let resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/type/top_type'))
for (const data of resJson["data"]["list"]) {
let type_name = data["type_name"]
let type_id = data["type_id"].toString()
this.classes.push(this.getTypeDic(type_name, type_id))
this.filterObj[type_id] = await this.getFilter(data)
}
}
async parseVodShortListFromJson(vodList) {
let vod_list = []
for (const vodData of vodList) {
let vodShort = new VodShort()
vodShort.load_data(vodData)
if (_.isEmpty(vodShort.vod_pic) && vodData["vod_pic_thumb"] !== undefined) {
vodShort.vod_pic = vodData["vod_pic_thumb"]
}
if (vodShort.vod_name !== "首页轮播") {
vod_list.push(vodShort)
}
}
return vod_list
}
async parseVodDetailfromJson(detailObj) {
let vodDetail = new VodDetail()
vodDetail.load_data(detailObj)
vodDetail.vod_content = Utils.formatContent(vodDetail.vod_content)
const playInfo = detailObj["vod_play_list"];
const playVod = {};
_.each(playInfo, (obj) => {
const sourceName = obj.name;
let playList = '';
const videoInfo = obj.urls;
const parse = obj["parse_urls"];
if (!_.isEmpty(parse)) this.parseMap[sourceName] = parse;
const vodItems = _.map(videoInfo, (epObj) => {
const epName = epObj.name;
const playUrl = epObj.url;
return epName + '$' + playUrl;
});
if (_.isEmpty(vodItems)) return;
playList = vodItems.join('#');
playVod[sourceName] = playList;
});
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async setHomeVod() {
let resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/type/tj_vod'))
let vod_list = []
for (const data of resJson["data"]["type_vod"]) {
if (data["type_name"] !== "广告") {
vod_list = await this.parseVodShortListFromJson(data["vod"])
this.homeVodList = [...this.homeVodList, ...vod_list]
}
}
vod_list = await this.parseVodShortListFromJson(resJson["data"]["loop"])
this.homeVodList = [...this.homeVodList, ...vod_list]
vod_list = await this.parseVodShortListFromJson(resJson["data"]["cai"])
this.homeVodList = [...this.homeVodList, ...vod_list]
}
async setCategory(tid, pg, filter, extend) {
const limit = 12;
const param = this.generateParam(tid, pg, extend, limit);
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/type_search', param));
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
}
async setDetail(id) {
const param = {
vod_id: id,
}
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/vod_details', param));
this.vodDetail = await this.parseVodDetailfromJson(resJson["data"])
}
async setPlay(flag, id, flags) {
const parsers = this.parseMap[flag];
if (flag.indexOf("芒果") > -1 || flag.indexOf("腾讯") > -1 || flag.indexOf("爱奇艺") > -1) {
if (!this.catOpenStatus) {
this.danmuUrl = await this.danmuSpider.downloadDanmu("https://dmku.thefilehosting.com/?ac=dm&url=" + id)
}
}
if (!_.isEmpty(parsers)) {
for (const parser of parsers) {
if (_.isEmpty(parser)) continue;
try {
const resp = await this.request(parser + id);
const json = JSON.parse(resp);
if (!_.isEmpty(json.url)) {
this.playUrl = json.url;
break;
}
} catch (e) {
}
}
}
}
async setSearch(wd, quick, pg) {
const limit = 12;
const param = {
keyword: wd, page: pg, limit: limit,
};
const resJson = JSON.parse(await this.postData(this.siteUrl + '/v2/home/search', param));
this.vodList = await this.parseVodShortListFromJson(resJson["data"]["list"])
const page = parseInt(pg);
let pageCount = page;
if (this.vodList.length === limit) {
pageCount = page + 1;
}
this.result.setPage(page, pageCount, limit, pageCount)
}
}
let spider = new TianTianSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider, TianTianSpider}
+343
View File
@@ -0,0 +1,343 @@
/*
* @File : ttkan.js
* @Author : jade
* @Date : 2024/5/10 9:59
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
import {BookDetail, BookShort} from "../lib/book.js";
class TTKanSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://cn.ttkan.co"
this.apiUrl = "https://cn.ttkan.co/api"
}
getAppName() {
return "天天看小说"
}
getJSName() {
return "ttkan"
}
getType() {
return 10
}
getName() {
return "📚︎┃天天看小说┃📚︎"
}
async spiderInit(inReq = null) {
if (inReq !== null) {
this.jsBase = await js2Proxy(inReq, "img", this.getHeader());
} else {
this.jsBase = await js2Proxy(true, this.siteType, this.siteKey, 'img/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
parseVodShortFromElement($, element) {
let bookShort = new BookShort()
let bookShortElements = $(element).find("a")
bookShort.book_name = bookShortElements[0].attribs["aria-label"]
bookShort.book_id = bookShortElements[0].attribs.href
if ($(element).find("amp-img").length > 0) {
bookShort.book_pic = $(element).find("amp-img")[0].attribs["src"].split("?")[0]
}
bookShort.book_remarks = $($(element).find("p")[0]).text()
return bookShort
}
async parseVodShortListFromDoc($) {
let books = []
let bookElements = $("[class=\"frame_body\"]").find("[class=\"pure-g\"]").slice(-1)[0]
for (const bookElement of bookElements.children) {
let bookShort = this.parseVodShortFromElement($, $(bookElement).find("li")[0])
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocByCategory($) {
let bookImgElements = $("[class=\"pure-u-xl-1-5 pure-u-lg-1-4 pure-u-md-1-3 pure-u-sm-1-3 pure-u-13-24\"]")
let bookMsgElements = $("[class=\"pure-u-xl-4-5 pure-u-lg-3-4 pure-u-md-2-3 pure-u-sm-2-3 pure-u-11-24\"]")
let books = [];
for (let i = 0; i < bookImgElements.length; i++) {
let bookShort = new BookShort()
let imgElement = bookImgElements[i]
let msgElement = bookMsgElements[i]
let element = $(imgElement).find('a')[0]
bookShort.book_id = element.attribs.href;
const img = $(imgElement).find('amp-img')[0];
bookShort.book_name = $(element).text()
bookShort.book_pic = img.attribs["src"].split("?")[0]
bookShort.book_name = img.attribs["alt"]
bookShort.book_remarks = $($(msgElement).find('li').slice(-1)).text().replaceAll("状态:","");
books.push(bookShort)
}
return books
}
async parseVodShortListFromJson(obj) {
let books = [];
for (const data of obj) {
let bookShort = new BookShort()
bookShort.book_id = "/novel/chapters/" + data["novel_id"]
bookShort.book_name = data["name"]
bookShort.book_remarks = "作者:" + data.author
bookShort.book_pic = "https://static.ttkan.co/cover/" + data["topic_img"]
books.push(bookShort)
}
return books
}
async parseVodShortListFromDocBySearch($) {
let books = []
let bookElements = $("[class=\"frame_body\"]").find("[class=\"pure-g\"]").slice(-1)[0]
for (const bookElement of bookElements.children) {
let bookShort = new BookShort()
bookShort.book_id = $(bookElement).find("a")[0].attribs.href
bookShort.book_name = $($(bookElement).find("li")[0]).text()
bookShort.book_remarks = $($(bookElement).find("li")[1]).text()
bookShort.book_pic = $(bookElement).find("amp-img")[0].attribs.src.split("?")[0]
books.push(bookShort)
}
return books
}
async parseVodDetailFromDoc($, id) {
let html = $.html()
let bookDetail = new BookDetail()
let infoElement = $("[class=\"pure-g novel_info\"]")
bookDetail.book_pic = $(infoElement).find("amp-img")[0].attribs.src.split("?")[0]
let elements = $(infoElement).find("[class=\"pure-u-xl-5-6 pure-u-lg-5-6 pure-u-md-2-3 pure-u-1-2\"]").find("li")
bookDetail.book_name = $(elements[0]).text()
bookDetail.book_director = $(elements[1]).text().replaceAll("作者:","")
bookDetail.book_remarks = $(elements[3]).text().replaceAll("状态:","")
bookDetail.book_year= $("[class=\"near_chapter\"]").find("time")[0].attribs.datetime.replaceAll("T"," ").split(".")[0]
bookDetail.book_content = $($('[class="description"]')).text().trim()
bookDetail.book_id = id
const playBook = {};
const nearElement = $('[class="near_chapter"]').find("a")[0]
let nearVodItems = []
const epName = $(nearElement).text();
const page = nearElement.attribs.href.split("&page=").slice(-1)[0]
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${page}.html` ;
nearVodItems.push(epName + '$' + playUrl)
const lastestElements = $('[class="chapters_frame"]').find("a")
for (const lastestElement of lastestElements){
const epName = $(lastestElement).text();
const page = lastestElement.attribs.href.split("&page=").slice(-1)[0]
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${page}.html` ;
nearVodItems.push(epName + '$' + playUrl)
}
playBook["最近章节"] = nearVodItems.reverse().join("#")
let params = {"language":"cn","novel_id":id.replaceAll("/novel/chapters/",""),"__amp_source_origin":encodeURIComponent(this.siteUrl)}
let resJSon = JSON.parse(await this.fetch(this.apiUrl + "/nq/amp_novel_chapters" ,params,this.getHeader()))
let allVodItems = []
for (const data of resJSon["items"]){
const epName = data.chapter_name;
const playUrl = epName + "+" + `${id.replaceAll("/novel/chapters/","")}_${data.chapter_id}.html` ;
allVodItems.push(epName + '$' + playUrl)
}
playBook["目录"] = allVodItems.join("#")
bookDetail.volumes = _.keys(playBook).join('$$$');
bookDetail.urls = _.values(playBook).join('$$$');
return bookDetail
}
async setClasses() {
let $ = await this.getHtml()
let navElements = $('div.novel_class_nav > a')
for (const element of navElements) {
let type_id = element.attribs.href
let type_name = $(element).text()
this.classes.push(this.getTypeDic(type_name, type_id));
}
}
async getFilter($) {
let extend_list = []
let extend_dic = {"name": "排序", "key": "sort", "value": []}
let elements = $('div.rank_nav > a')
let sortList = []
let isNewSort = false
if (elements.length === 0) {
elements = $('div.nav_filter_inner > a')
isNewSort = true
}
for (const element of elements) {
let type_name = $(element).text()
let type_id = element.attribs.href
sortList.push(this.getFliterDic(type_name, type_id))
}
if (isNewSort) {
const lastItem = sortList.splice(-1, 1);
sortList = lastItem.concat(sortList);
}
extend_dic["value"] = sortList
extend_list.push(extend_dic)
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "最近更新") {
let $ = await this.getHtml(this.siteUrl + type_id)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
async setHomeVod() {
let $ = await this.getHtml()
this.homeVodList = await this.parseVodShortListFromDoc($)
}
async setDetail(id) {
let $ = await this.getHtml(this.siteUrl + id)
this.vodDetail = await this.parseVodDetailFromDoc($, id)
}
getExtend(extend) {
if (extend["sort"] === undefined) {
return "*"
}
if (extend["sort"] === "全部") {
return "*"
} else {
let value = extend["sort"].replaceAll("/novel/", "").replaceAll("class/", "")
if (value.indexOf("_") > -1){
return value.split("_").slice(-1)[0]
}else{
return value
}
}
}
async setCategory(tid, pg, filter, extend) {
if (tid === "/novel/rank") {
tid = extend["sort"] ?? tid
let $ = await this.getHtml(this.siteUrl + tid)
this.vodList = await this.parseVodShortListFromDocByCategory($)
let x = 0
} else {
let extendFilter = this.getExtend(extend)
let limit = 18
let params = {
"language": "cn",
"limit": limit,
"type": tid.replaceAll("/novel/", "").replaceAll("class/", ""),
"filter": extendFilter,
"page": parseInt(pg),
"__amp_source_origin": encodeURIComponent(this.siteUrl)
}
let resJson = JSON.parse(await this.fetch(this.apiUrl + "/nq/amp_novel_list", params, this.getHeader()))
this.vodList = await this.parseVodShortListFromJson(resJson["items"])
}
}
async setPlay(flag, id, flags) {
let id_list = id.split("-")
id = id_list[1]
let content = id_list[0] + "\n\n"
while (true) {
let $ = await this.getHtml(this.siteUrl + id)
content += Utils.formatContent($("[class=\"content\"]").html().trim().replaceAll("<p>", " ").replaceAll("</p>", "\n"));
id = $("[id=\"next_url\"]")[0].attribs.href;
if (id.indexOf('_') < 0) break;
}
this.playUrl = {"content": content}
}
async setSearch(wd, quick) {
let params = {"q":encodeURIComponent(wd)}
let content = await this.fetch(this.siteUrl + "/novel/search", params, this.getHeader())
let $ = load(content)
this.vodList = await this.parseVodShortListFromDocBySearch($)
let x = 0
}
async setPlay(flag, id, flags) {
let id_list = id.split("+")
id = id_list[1]
let content = id_list[0] + "\n\n"
let $ = await this.getHtml(this.siteUrl + "/novel/pagea/" + id)
let bookContentList = $('[class="content"]').text().trim().replaceAll("章节报错 分享给朋友:","").replaceAll(" ","").split("\n")
let newBookContentList = []
for (const bookContent of bookContentList){
if (!_.isEmpty(bookContent.replaceAll(" ",""))){
newBookContentList.push(bookContent.replaceAll(" "," "))
}
}
content = content + " " + newBookContentList.join("\n\n")
this.playUrl = {"content": content}
}
}
let spider = new TTKanSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
async function proxy(segments, headers) {
return await spider.proxy(segments, headers)
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy
};
}
export {spider}
+192
View File
@@ -0,0 +1,192 @@
/*
* @File : vodSpider.js
* @Author : jade
* @Date : 2024/2/6 16:53
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class VodSpider extends Spider {
constructor() {
super();
this.siteUrl = "http://cj.ffzyapi.com"
this.remove18 = false
this.type_id_18 = 34
}
async spiderInit(inReq) {
if (inReq !== null) {
this.detailProxy = await js2Proxy(inReq, "detail", this.getHeader());
} else {
this.detailProxy = await js2Proxy(true, this.siteType, this.siteKey, 'detail/', this.getHeader());
}
}
async init(cfg) {
await super.init(cfg);
await this.spiderInit(null)
}
async parseVodShortListFromJson(obj, isSearch = false) {
let vod_list = []
let vodShort;
for (const vod_data of obj["list"]) {
if (!isSearch) {
vodShort = this.parseVodDetail(vod_data)
} else {
vodShort = new VodShort();
vodShort.vod_pic = this.detailProxy + Utils.base64Encode(vod_data["vod_id"])
vodShort.vod_id = vod_data["vod_id"]
vodShort.vod_name = vod_data["vod_name"]
vodShort.vod_remarks = vod_data["vod_remarks"]
}
if (this.remove18 && vod_data["type_id"] !== this.type_id_18) {
vod_list.push(vodShort)
}
if (!this.remove18 && vod_data["type_id"] === this.type_id_18) {
vod_list.push(vodShort)
}
}
return vod_list
}
parseVodDetail(vod_data) {
let vodDetail = new VodDetail()
vodDetail.vod_id = vod_data["vod_id"]
vodDetail.vod_name = vod_data["vod_name"]
vodDetail.vod_pic = vod_data["vod_pic"]
vodDetail.vod_remarks = vod_data["vod_remarks"]
vodDetail.vod_area = vod_data["vod_area"]
vodDetail.vod_year = vod_data["vod_year"]
vodDetail.vod_actor = vod_data["vod_actor"]
vodDetail.vod_director = vod_data["vod_director"]
let $ = load(vod_data['vod_content'])
vodDetail.vod_content = $.text()
if (vod_data["vod_down_url"] !== undefined) {
if (vod_data["vod_down_url"].length > 0) {
vodDetail.vod_play_from = "直链播放$$$"
vodDetail.vod_play_url = vod_data["vod_down_url"] + "$$$"
}
}
vodDetail.vod_play_from = vodDetail.vod_play_from + vod_data["vod_play_from"]
vodDetail.vod_play_url = vodDetail.vod_play_url + vod_data["vod_play_url"]
vodDetail.type_name = vod_data["type_name"]
return vodDetail
}
async parseVodDetailfromJson(obj) {
let vodDetail;
let vod_data_list = obj["list"]
if (vod_data_list.length > 0) {
let vod_data = vod_data_list[0]
vodDetail = this.parseVodDetail(vod_data)
}
return vodDetail
}
async setClasses() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const class_dic of content_json["class"]) {
if (class_dic["type_pid"] !== 0) {
this.classes.push(this.getTypeDic(class_dic["type_name"], class_dic["type_id"]))
}
}
}
async setFilterObj() {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/from", {"ac": "list"}, this.getHeader())
let content_json = JSON.parse(content)
for (const root_class_dic of this.classes) {
let type_id = root_class_dic["type_id"].toString()
if (type_id !== "最近更新") {
let extend_dic = {"key": "1", "name": "分类", "value": [{"n": "全部", "v": type_id}]}
for (const class_dic of content_json["class"]) {
let type_name = class_dic["type_name"]
if (type_name === this.type_name_18) {
this.type_id_18 = class_dic["type_id"].toString()
}
if (this.remove18) {
if (class_dic["type_pid"] === root_class_dic["type_id"] && type_name !== this.type_name_18) {
extend_dic["value"].push({"n": type_name, "v": class_dic["type_id"].toString()})
}
} else {
if (class_dic["type_pid"] === root_class_dic["type_id"] && type_name === this.type_name_18) {
extend_dic["value"].push({"n": type_name, "v": class_dic["type_id"].toString()})
}
}
}
if (!this.remove18) {
this.classes = [this.getTypeDic("最近更新", "最近更新"), this.getTypeDic(this.type_name_18, this.type_id_18)]
} else {
this.filterObj[type_id] = [extend_dic]
}
}
}
}
async setHomeVod() {
let content = await this.fetch(this.siteUrl + "/index.php/ajax/data", {
"mid": "1"
}, this.getHeader())
this.homeVodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setDetail(id) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": id
}, this.getHeader())
this.vodDetail = await this.parseVodDetailfromJson(JSON.parse(content))
}
async setCategory(tid, pg, filter, extend) {
tid = extend["1"] ?? tid
let url = this.siteUrl + `/index.php/ajax/data?mid=1&tid=${tid}&page=${pg}&limit=20`
await this.jadeLog.debug(`分类URL:${url}`)
let content = await this.fetch(url, null, this.getHeader())
await this.jadeLog.debug(`分类内容为:${content}`)
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content))
}
async setSearch(wd, quick) {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod/", {"wd": wd}, this.getHeader())
this.vodList = await this.parseVodShortListFromJson(JSON.parse(content), true)
}
async proxy(segments, headers) {
await this.jadeLog.debug(`正在设置反向代理 segments = ${segments.join(",")},headers = ${JSON.stringify(headers)}`)
let what = segments[0];
let url = Utils.base64Decode(segments[1]);
await this.jadeLog.debug(`反向代理参数为:${url}`)
if (what === 'detail') {
let content = await this.fetch(this.siteUrl + "/api.php/provide/vod", {
"ac": "detail", "ids": url
}, this.getHeader())
let vod_detail = await this.parseVodDetailfromJson(JSON.parse(content))
let pic_content = await this.fetch(vod_detail.vod_pic, null, this.getHeader(), false, false, 2)
if (!_.isEmpty(pic_content)) {
return JSON.stringify({
code: 200, buffer: 2, content: pic_content, headers: {},
});
} else {
return JSON.stringify({
code: 500, buffer: 2, content: "", headers: {},
});
}
}
}
}
export {VodSpider}
+322
View File
@@ -0,0 +1,322 @@
/*
* @Author: samples [email protected]
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples [email protected]
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/weixine.js
* @Description: 阿里影视(已失效)
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {detailContent, initAli, playContent} from "../lib/ali.js";
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class WeiXineSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.weixine.link';
}
async init(cfg) {
await super.init(cfg);
await initAli(this.cfgObj["token"]);
}
getName() {
return `💂‍┃阿里影视┃💂`
}
getAppName() {
return "阿里影视"
}
getJSName() {
return "weixine"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($(".mobile-play")).find(".lazyload")[0].attribs["data-src"]
let video_info_aux_list = $($(".video-info-aux")).find(".tag-link")[1].children
for (const video_info_aux of video_info_aux_list) {
try {
vodDetail.type_name = vodDetail.type_name + video_info_aux.children[0].data
} catch {
}
}
let video_items = $('.video-info-items')
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const video_info_actor of vidoe_info_actor_list) {
if (video_info_actor.children.length > 0) {
actor_list.push(video_info_actor.children[0].data)
}
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = $(video_items[2]).find("a")[0].children[0].data
vodDetail.vod_remarks = `清晰度:${$(video_items[3]).find("div")[0].children[0].data}, 制作人:Jade`
vodDetail.vod_content = $(video_items[4]).find("p")[0].children[0].data
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "")
const share_url_list = [];
let items = $('.module-row-info')
for (const item of items) {
let aliUrl = $(item).find("p")[0].children[0].data
let matches = aliUrl.match(Utils.patternAli);
if (!_.isEmpty(matches)) share_url_list.push(matches[1])
}
if (share_url_list.length > 0) {
let aliVodDetail = await detailContent(share_url_list)
vodDetail.vod_play_url = aliVodDetail.vod_play_url
vodDetail.vod_play_from = aliVodDetail.vod_play_from
} else {
await this.jadeLog.warning(`获取详情界面失败,失败原因为:没有分享链接`)
}
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src'];
vodShort.vod_remarks = '';
vod_list.push(vodShort);
}
return vod_list
}
get_extend_sort_dic(tid) {
/***
tid为1,2,3的时候,电影,剧情,动漫
urlParams#0表示类别,1表示全部地区,2表示人气评分,3表示全部剧情,4表示全部语言,5表示字母查找,6表示页数,11表示时间
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部语言
#key为4,代表全部时间
#key为5,字幕查找
#key为6,时间排序
https://www.wogg.xyz/index.php/vodshow/1-全部地区-时间排序-全部剧情-全部语言-字幕查找------全部时间.html
tid为4,综艺
#key为1,代表全部地区
#key为2,代表全部时间
#key为3,字幕查找
#key为4,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/4-全部地区-时间排序---字母查找------全部时间.html
tid为5:音乐
#key为1,字幕查找
#key为2,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/5--时间排序---字幕查找------.html
tid为6,短剧
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部时间
#key为4,字幕查找
#key为5,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/6-全部地区-时间排序-全部剧情--字母查找------全部时间.html
*/
let extend_dic = {}
if (tid < 4) {
extend_dic = {
"1": 3, "2": 1, "3": 4, "4": 11, "5": 5, "6": 2
}
} else if (tid === 4) {
extend_dic = {
"1": 1, "2": 11, "3": 5, "4": 2,
}
} else if (tid === 6) {
extend_dic = {
"1": 3, "2": 1, "3": 11, "4": 5, "5": 2,
}
} else if (tid === 5) {
extend_dic = {
"1": 5, "2": 2,
}
}
return extend_dic
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $('.nav-link')
for (const element of elements) {
let type_id = parseInt(element.attribs.href.split("/").slice(-1)[0].split(".html")[0])
let type_name = element.children.slice(-1)[0].data.replaceAll("\n", "").replaceAll(" ", "").replaceAll("玩偶", "").replaceAll("\t", "")
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(), "v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/index.php/vodshow/${type_id}--------1---.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
urlParams[extend_dic[key]] = extend[key]
}
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async play(flag, id, flags) {
return await playContent(flag, id, flags);
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + '/index.php/vodsearch/-------------.html?wd=' + wd;
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new WeiXineSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+314
View File
@@ -0,0 +1,314 @@
/*
* @Author: samples [email protected]
* @Date: 2023-12-14 11:03:04
* @LastEditors: samples [email protected]
* @LastEditTime: 2023-12-14 11:03:04
* @FilePath: js/wogg.js
* @Description: 玩偶哥哥爬虫类
*/
import {_, load} from '../lib/cat.js';
import {VodDetail, VodShort} from "../lib/vod.js"
import {initCloud, detailContent,playContent,getHeaders} from '../lib/cloud.js';
import * as Utils from "../lib/utils.js";
import {Spider} from "./spider.js";
class WoggSpider extends Spider {
constructor() {
super();
this.siteUrl = 'https://www.wogg.net';
this.woggTypeObj = {"玩偶电影":"电影","玩偶剧集":"电视剧"}
}
async init(cfg) {
await super.init(cfg);
await initCloud(this.cfgObj)
this.danmuStaus = true
}
getName() {
return "💂‍┃阿里玩偶┃💂"
}
getAppName() {
return "阿里玩偶"
}
getJSName() {
return "wogg"
}
getType() {
return 3
}
async parseVodShortListFromDoc($) {
let items = $('.module-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
let oneA = $(item).find('.module-item-cover .module-item-pic a').first();
vodShort.vod_id = oneA.attr('href');
vodShort.vod_name = oneA.attr('title');
vodShort.vod_pic = $(item).find('.module-item-cover .module-item-pic img').first().attr('data-src');
if (vodShort.vod_pic.indexOf("img.php?url=") > 0) {
vodShort.vod_pic = vodShort.vod_pic.split("img.php?url=")[1]
}
vodShort.vod_remarks = $(item).find('.module-item-text').first().text();
vod_list.push(vodShort)
}
return vod_list
}
async parseVodDetailFromDoc($) {
let vodDetail = new VodDetail()
vodDetail.vod_name = $('.page-title')[0].children[0].data
vodDetail.vod_pic = $($(".mobile-play")).find(".lazyload")[0].attribs["data-src"]
vodDetail.type_name = this.woggTypeObj[$("[class=\"video-info-aux\"]").find("a")[0].attribs.title]
let video_items = $('.video-info-items')
vodDetail.vod_director = $(video_items[0]).find("a")[0].children[0].data
let vidoe_info_actor_list = $(video_items[1]).find("a")
let actor_list = []
for (const video_info_actor of vidoe_info_actor_list) {
if (video_info_actor.children.length > 0){
actor_list.push(video_info_actor.children[0].data)
}
}
vodDetail.vod_actor = actor_list.join(" * ")
vodDetail.vod_year = $(video_items[2]).find("a")[0].children[0].data
vodDetail.vod_remarks = `${$(video_items[3]).find("div")[0].children[0].data}, 制作人:Jade`
vodDetail.vod_content = $(video_items[4]).find("p")[0].children[0].data
vodDetail.vod_content = vodDetail.vod_content.replace("[收起部分]", "").replace("[展开全部]", "")
const share_url_list = []
let items = $('.module-row-info')
for (const item of items) {
let shareUrl = $(item).find("p")[0].children[0].data
share_url_list.push(shareUrl)
}
let playVod = await detailContent(share_url_list,vodDetail.type_name)
vodDetail.vod_play_from = _.keys(playVod).join('$$$');
vodDetail.vod_play_url = _.values(playVod).join('$$$');
return vodDetail
}
async parseVodShortListFromDocBySearch($) {
let items = $('.module-search-item');
let vod_list = [];
for (const item of items) {
let vodShort = new VodShort()
vodShort.vod_id = $(item).find(".video-serial")[0].attribs.href;
vodShort.vod_name = $(item).find(".video-serial")[0].attribs.title;
vodShort.vod_pic = $(item).find(".module-item-pic > img")[0].attribs['data-src'];
vodShort.vod_remarks = $($(item).find(".video-serial")[0]).text();
vod_list.push(vodShort);
}
return vod_list
}
get_extend_sort_dic(tid) {
/***
tid为1,2,3的时候,电影,剧情,动漫
urlParams#0表示类别,1表示全部地区,2表示人气评分,3表示全部剧情,4表示全部语言,5表示字母查找,6表示页数,11表示时间
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部语言
#key为4,代表全部时间
#key为5,字幕查找
#key为6,时间排序
https://www.wogg.xyz/index.php/vodshow/1-全部地区-时间排序-全部剧情-全部语言-字幕查找------全部时间.html
tid为4,综艺
#key为1,代表全部地区
#key为2,代表全部时间
#key为3,字幕查找
#key为4,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/4-全部地区-时间排序---字母查找------全部时间.html
tid为5:音乐
#key为1,字幕查找
#key为2,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/5--时间排序---字幕查找------.html
tid为6,短剧
#key为1,代表全部剧情
#key为2,代表全部地区
#key为3,代表全部时间
#key为4,字幕查找
#key为5,时间排序
https://tvfan.xxooo.cf/index.php/vodshow/6-全部地区-时间排序-全部剧情--字母查找------全部时间.html
*/
let extend_dic = {}
if (tid < 4) {
extend_dic = {
"1": 3, "2": 1, "3": 4, "4": 11, "5": 5, "6": 2
}
} else if (tid === 4) {
extend_dic = {
"1": 1, "2": 11, "3": 5, "4": 2,
}
} else if (tid === 6) {
extend_dic = {
"1": 3, "2": 1, "3": 11, "4": 5, "5": 2,
}
} else if (tid === 5) {
extend_dic = {
"1": 5, "2": 2,
}
}
return extend_dic
}
async setClasses() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
let elements = $('.nav-link')
for (const element of elements) {
let type_id = parseInt(element.attribs.href.split("/").slice(-1)[0].split(".html")[0])
let type_name = element.children.slice(-1)[0].data.replace("\n", "").replace(" ", "").replace("玩偶", "")
let type_dic = {"type_id": type_id, "type_name": type_name}
this.classes.push(type_dic)
}
}
}
async getFilter($) {
let elements = $("[class='scroll-content']").slice(1)
let extend_list = []
for (let i = 0; i < elements.length; i++) {
let extend_dic = {"key": (i + 1).toString(), "name": "", "value": []}
if (i < elements.length - 1) {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"].push({"n": "全部", "v": "0"})
for (const ele of $(elements[i]).find("a").slice(1)) {
extend_dic["value"].push({"n": $(ele).text(), "v": $(ele).text()})
}
extend_list.push(extend_dic)
} else {
extend_dic["name"] = $($(elements[i]).find("a")[0]).text()
extend_dic["value"] = [{"n": "全部", "v": "0"}, {
"n": $($(elements[i]).find("a")[1]).text(),
"v": "hits"
}, {"n": $($(elements[i]).find("a")[2]).text(), "v": "score"}]
extend_list.push(extend_dic)
}
}
return extend_list
}
async setFilterObj() {
for (const type_dic of this.classes) {
let type_id = type_dic["type_id"]
if (type_id !== "/" && type_id !== "最近更新") {
let url = this.siteUrl + `/index.php/vodshow/${type_id}--------1---.html`
let html = await this.fetch(url, null, this.getHeader())
if (html != null) {
let $ = load(html)
this.filterObj[type_id] = await this.getFilter($)
}
}
}
}
async setHomeVod() {
let con = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(con)) {
const $ = load(con);
this.homeVodList = await this.parseVodShortListFromDoc($)
}
}
async setCategory(tid, pg, filter, extend) {
let urlParams = [tid.toString(), "", "", "", "", "", "", "", pg.toString(), "", "", ""]
let extend_dic = this.get_extend_sort_dic(parseInt(tid))
for (const key of Object.keys(extend_dic)) {
if (extend[key] === "0") {
urlParams[extend_dic[key]] = ""
} else {
urlParams[extend_dic[key]] = extend[key]
}
}
let reqUrl = this.siteUrl + '/index.php/vodshow/' + urlParams.join("-") + '.html';
let html = await this.fetch(reqUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
let total = Utils.getStrByRegex(/\$\("\.mac_total"\)\.text\('(\d+)'\)/, html)
this.limit = 72;
if (total.length > 0) {
this.total = parseInt(total)
}
if (this.total <= this.limit) {
this.count = 1
} else {
this.count = Math.ceil(this.total / this.limit)
}
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
this.playUrl = await playContent(flag, id, flags);
this.result.setHeader(getHeaders(flag))
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + '/index.php/vodsearch/-------------.html?wd=' + wd;
let html = await this.fetch(searchUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDocBySearch($)
}
}
}
let spider = new WoggSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+304
View File
@@ -0,0 +1,304 @@
/*
* @File : xb6v.js
* @Author : jade
* @Date : 2023/12/26 10:13
* @Email : [email protected]
* @Software : Samples
* @Desc :
*/
import * as Utils from "../lib/utils.js";
import {_, load} from "../lib/cat.js";
import {VodDetail, VodShort} from "../lib/vod.js";
import {Spider} from "./spider.js";
class Xb6vSpider extends Spider {
constructor() {
super();
this.siteUrl = "https://www.xb6v.com";
}
getName() {
return "🧲┃磁力新6V┃🧲"
}
getAppName() {
return "磁力新6V"
}
getJSName() {
return "xb6v"
}
getType() {
return 3
}
async redirect(response) {
await this.jadeLog.debug(`重定向回复值为:${response.content}`)
let matcher = /<a HREF=(.*?)>/.exec(response.content)
if (matcher.length > 1) {
let new_url = this.siteUrl + "/e/search/" + matcher[1].replaceAll("\\", "").replaceAll("\"", "")
await this.jadeLog.info(`重定向url为:${new_url}`)
return await this.fetch(new_url, null, this.getHeader())
}
}
getActorOrDirector(pattern, str) {
return Utils.getStrByRegex(pattern, str)
.replace(/<br>/g, "")
.replace(/&nbsp;./g, "")
.replace(/&amp;/g, "")
.replace(/middot;/g, "・")
.replace(/     /g, ",")
.replace(/      /g, ",")
.replace(/ /g, "");
}
getDescription(pattern, str) {
return Utils.getStrByRegex(pattern, str)
.replace(/<\/?[^>]+>/g, "")
.replace(/\n/g, "")
.replace(/&amp;/g, "")
.replace(/middot;/g, "・")
.replace(/ldquo;/g, "【")
.replace(/rdquo;/g, "】")
.replace(/ /g, "");
}
async parseVodShortListFromDoc($) {
let items = $("#post_container .post_hover");
let vod_list = []
for (const item of items) {
let element = $(item).find("[class=zoom]")[0];
let vodShort = new VodShort()
vodShort.vod_id = element.attribs["href"];
vodShort.vod_name = element.attribs["title"].replaceAll(/<\\?[^>]+>/g, "");
vodShort.vod_pic = $(element).find("img")[0].attribs["src"];
vodShort.vod_remarks = $(item).find("[rel=\"category tag\"]").text().replaceAll("\n", "").replaceAll(" ", "");
vod_list.push(vodShort)
}
return vod_list;
}
async parseVodDetailFromDoc($) {
let sourceList = $("#post_content");
let play_form_list = []
let play_url_list = []
if (!this.catOpenStatus) {
let i = 0
let circuitName = "磁力线路";
for (const source of sourceList) {
let aList = $(source).find("table a")
let vodItems = []
for (const a of aList) {
let episodeUrl = a.attribs["href"]
let episodeName = a.children[0].data
if (!episodeUrl.toLowerCase().startsWith("magnet")) continue;
vodItems.push(episodeName + "$" + episodeUrl);
}
if (vodItems.length > 0) {
i++;
play_form_list.push(circuitName + i)
play_url_list.push(vodItems.join("#"))
}
}
}
let playSourceList = $($(".mainleft")).find("[class=\"widget box row\"]")
for (const source of playSourceList) {
let play_format = $(source).find("h3").text()
let vodItems = []
if (!_.isEmpty(play_format)) {
let urlSourceList = $(source).find("a")
for (const url_source of urlSourceList) {
vodItems.push(url_source.attribs["title"] + "$" + url_source.attribs["href"])
}
play_form_list.push(play_format)
play_url_list.push(vodItems.join("#"))
}
}
let partHTML = $(".context").html();
let vodDetail = new VodDetail();
vodDetail.vod_name = $(".article_container > h1").text();
vodDetail.vod_pic = $("#post_content img").attr("src");
vodDetail.type_name = Utils.getStrByRegex(/◎类  别 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.type_name)) vodDetail.type_name = $("[rel=\"category tag\"]").text();
vodDetail.vod_year = Utils.getStrByRegex(/◎年  代 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_year)) vodDetail.vod_year = Utils.getStrByRegex(/首播:(.*?)<br>"/, partHTML);
vodDetail.vod_area = Utils.getStrByRegex(/◎产  地 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_year)) vodDetail.vod_area = Utils.getStrByRegex(/地区:(.*?)<br>"/, partHTML);
vodDetail.vod_remarks = Utils.getStrByRegex(/◎上映日期 (.*?)<br>/, partHTML);
vodDetail.vod_actor = this.getActorOrDirector(/◎演  员 (.*?)<\/p>/, partHTML);
if (_.isEmpty(vodDetail.vod_actor)) vodDetail.vod_actor = this.getActorOrDirector(/◎主  演 (.*?)<\/p>/, partHTML);
if (_.isEmpty(vodDetail.vod_actor)) vodDetail.vod_actor = this.getActorOrDirector(/主演:(.*?)<br>/, partHTML);
vodDetail.vod_director = this.getActorOrDirector(/◎导  演 (.*?)<br>/, partHTML);
if (_.isEmpty(vodDetail.vod_director)) vodDetail.vod_director = this.getActorOrDirector(/导演:(.*?)<br>/, partHTML);
vodDetail.vod_content = this.getDescription(/◎简  介(.*?)<hr>/gi, partHTML);
if (_.isEmpty(vodDetail.vod_content)) vodDetail.vod_content = this.getDescription(/简介(.*?)<\/p>/gi, partHTML);
if (_.isEmpty(vodDetail.vod_content)) vodDetail.vod_content = this.getDescription(/◎简  介(.*?)<br>/gi, partHTML);
vodDetail.vod_play_from = play_form_list.join("$$$")
vodDetail.vod_play_url = play_url_list.join("$$$")
return vodDetail
}
async parseVodPlayFromDoc(flag, $) {
let play_url = ""
let html = $.html()
switch (flag) {
case "播放地址(无插件 极速播放)":
case "播放地址三":
play_url = $($(".video")).find("iframe")[0].attribs["src"] + "/index.m3u8"
break
case "播放地址(无需安装插件)":
let matchers2 = /url: '(.*?)',/gs.exec(html)
if (matchers2.length > 1) {
play_url = matchers2[1]
}
break
case "播放地址四":
let matchers4 = /source: "(.*?)",/gs.exec(html)
if (matchers4.length > 1) {
play_url = matchers4[1]
}
break
default:
await this.jadeLog.warning(`暂不支持当前格式,当前格式为:${flag}`)
break
}
return play_url
}
async setClasses() {
let html = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html);
let elements = $('#menus > li > a');
for (let i = 0; i < elements.length; i++) {
let element = elements[i]
if (i < 2 || i === elements.length - 1) continue;
let typeName = element.children[0].data;
let typeId = element.attribs["href"];
this.classes.push({"type_name": typeName, "type_id": typeId})
if (typeName === "电视剧") {
let values = [{"n": "不限", "v": ""}]
for (const a of $(element.next).find("a")) {
values.push({"n": a.children[0].data, "v": a.attribs["href"].replaceAll(typeId, "")})
}
this.filterObj[typeId] = [{
"key": "cateId", "name": "类型", "value": values
}]
}
}
}
}
async setHomeVod() {
let html = await this.fetch(this.siteUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html);
this.homeVodList = await this.parseVodShortListFromDoc($)
} else {
await this.jadeLog.info("首页类别解析失败", true)
}
}
async setCategory(tid, pg, filter, extend) {
let cateId = extend["cateId"] ?? "";
let cateUrl = this.siteUrl + tid + cateId;
this.page = parseInt(pg)
this.count = 0
this.limit = 18;
this.total = 0;
if (this.page !== 1) {
cateUrl += "index_" + pg + ".html";
}
let html = await this.fetch(cateUrl, null, this.getHeader());
if (!_.isEmpty(html)) {
let $ = load(html)
let href_elements = $(".pagination > a")
if (href_elements.length > 0) {
let href = href_elements.slice(-1)[0].attribs["href"];
let patternPageCount = /index_(.*?).html/
let matches = patternPageCount.exec(href)
this.count = parseInt(matches[1])
let items = $("#post_container .post_hover");
this.total = this.page === this.count ? (this.page - 1) * this.limit + items.length : this.count * this.limit;
}
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setSearch(wd, quick) {
let searchUrl = this.siteUrl + "/e/search/index.php";
let params = {
"show": "title", "tempid": "1", "tbname": "article", "mid": "1", "dopost": "search", "keyboard": wd,
}
let html = await this.post(searchUrl, params, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html)
this.vodList = await this.parseVodShortListFromDoc($)
}
}
async setDetail(id) {
let detailUrl = this.siteUrl + id;
let html = await this.fetch(detailUrl, null, this.getHeader())
if (!_.isEmpty(html)) {
let $ = load(html);
this.vodDetail = await this.parseVodDetailFromDoc($)
}
}
async setPlay(flag, id, flags) {
if (id.toLowerCase().startsWith("magnet")) {
this.playUrl = id
} else {
let playUrl = this.siteUrl + id
let html = await this.fetch(playUrl, null, this.getHeader())
let $ = load(html)
this.playUrl = await this.parseVodPlayFromDoc(flag, $)
}
}
}
let spider = new Xb6vSpider()
async function init(cfg) {
await spider.init(cfg)
}
async function home(filter) {
return await spider.home(filter)
}
async function homeVod() {
return await spider.homeVod()
}
async function category(tid, pg, filter, extend) {
return await spider.category(tid, pg, filter, extend)
}
async function detail(id) {
return await spider.detail(id)
}
async function play(flag, id, flags) {
return await spider.play(flag, id, flags)
}
async function search(wd, quick) {
return await spider.search(wd, quick)
}
export function __jsEvalReturn() {
return {
init: init, home: home, homeVod: homeVod, category: category, detail: detail, play: play, search: search,
};
}
export {spider}
+268
View File
@@ -0,0 +1,268 @@
/*
* @File : yiqikan.js
* @Author : jade
* @Date : 2024/3/19 18:45
* @Email : [email protected]
* @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}