Sync all projects

This commit is contained in:
github-actions[bot]
2026-07-14 18:13:10 +00:00
parent fd64acd0eb
commit cba35ac921
108 changed files with 5435 additions and 25904 deletions
+1 -10
View File
@@ -16,7 +16,7 @@
},
{
"key": "Doubana",
"name": "🐮【更新日期:20260712】🐮",
"name": "🐮【更新日期:20260714】🐮",
"type": 3,
"api": "csp_NewDouBanGuard",
"indexs": 1,
@@ -334,15 +334,6 @@
"searchable": 1,
"changeable": 0
},
{
"key": "DuanJuHeMa",
"name": "🍉短剧┃小马🍉",
"type": 3,
"类型": "短剧",
"api": "csp_DuanJuHeMaGuard",
"searchable": 1,
"changeable": 0
},
{
"key": "DuanJuXingYa",
"name": "🍉短剧┃星星🍉",
Binary file not shown.
-6
View File
@@ -1,6 +0,0 @@
{
"线路数组": "<a data-toggle=\"tab\"&&/a>",
"线路标题": ">&&<",
"分类url": "http://dyxz.tv/list/{cateId}_{catePg}.html",
"分类": "电影$1#电视剧$2#动漫$3#综艺$4"
}
-7
View File
@@ -1,7 +0,0 @@
{
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类": "电影$1#电视剧$2#综艺$3#动漫$4",
"类型": "动作片$6#喜剧片$7#爱情片$8#科幻片$9#奇幻片$10#恐怖片$11#剧情片$12#战争片$20#动画片$26#悬疑片$22#冒险片$23#犯罪片$24#惊悚片$45#歌舞片$46#灾难片$47#网络片$48||国产剧$13#港台剧$14#日剧$15#韩剧$33#欧美剧$16#泰剧$34#新马剧$35#其他剧$25||内地综艺$27#港台综艺$28#日本综艺$29#韩国综艺$36#欧美综艺$30#新马泰综艺$37#其他综艺$38||国产动漫$31#日本动漫$32#韩国动漫$39#港台动漫$40#新马泰动漫$41#欧美动漫$42#其他动漫$43",
"分类url": "https://www.ylys.tv/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html"
}
-7
View File
@@ -1,7 +0,0 @@
{
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类url": "https://v.aiwule.com/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html",
"分类": "电影$20#电视剧$21#动漫$23#综艺$22#短剧$47",
"简介": "简介:&&"
}
+37 -29
View File
@@ -242,26 +242,6 @@
"decrypt": "0"
}
},
{
"key": "久久",
"name": "久久 • APP",
"type": 3,
"api": "csp_AppYsV2",
"searchable": 1,
"quickSearch": 1,
"filterable": 1,
"ext": "http://99cms.jj99.icu:8199/api.php/app/"
},
{
"key": "闪影",
"name": "闪影 • APP",
"type": 3,
"api": "csp_AppYsV2",
"searchable": 1,
"quickSearch": 1,
"filterable": 1,
"ext": "http://38.47.213.61:41271/mogai_api.php/v1.vod"
},
{
"key": "飞飞",
"name": "飞飞 • APP",
@@ -726,12 +706,6 @@
"type": 3,
"api": "csp_Gz360"
},
{
"key": "云播影视",
"name": "云播 • 影视",
"type": 3,
"api": "csp_Tvyb"
},
{
"key": "骚火影视",
"name": "骚火 • 影视",
@@ -755,26 +729,60 @@
"quickSearch": 1,
"filterable": 1
},
{
"key": "枫叶影视",
"name": "枫叶 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": {
"请求头": "手机",
"简介": "text cor3\">[*],&&</div>",
"图片": "data-src=\"&&\"[替换:amp;>>空]",
"主页url": "https://www.cd-zj.com/label/qq.html",
"副标题": "ft2\">&&</i>",
"线路数组": "<i class=\"fa ds-dianying\">&&</span>",
"播放数组": "anthology-list-play size\">&&</ul>",
"分类url": "https://www.cd-zj.com/cupfox-list/{cateId}-{area}--{class}-----{catePg}---{year}.html",
"分类": "电影$1#电视剧$2#综艺$3#动漫$4#短剧$5"
}
},
{
"key": "小镇影视",
"name": "小镇 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": "./XBPQ/小镇影视.json"
"ext": {
"线路数组": "<a data-toggle=\"tab\"&&/a>",
"线路标题": ">&&<",
"分类url": "http://dyxz.tv/list/{cateId}_{catePg}.html",
"分类": "电影$1#电视剧$2#动漫$3#综艺$4"
}
},
{
"key": "面包影视",
"name": "面包 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": "./XBPQ/面包影视.json"
"ext": {
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类url": "https://v.aiwule.com/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html",
"分类": "电影$20#电视剧$21#动漫$23#综艺$22#短剧$47",
"简介": "简介:&&"
}
},
{
"key": "永乐影视",
"name": "永乐 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": "./XBPQ/永乐影视.json"
"ext": {
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类": "电影$1#电视剧$2#综艺$3#动漫$4",
"类型": "动作片$6#喜剧片$7#爱情片$8#科幻片$9#奇幻片$10#恐怖片$11#剧情片$12#战争片$20#动画片$26#悬疑片$22#冒险片$23#犯罪片$24#惊悚片$45#歌舞片$46#灾难片$47#网络片$48||国产剧$13#港台剧$14#日剧$15#韩剧$33#欧美剧$16#泰剧$34#新马剧$35#其他剧$25||内地综艺$27#港台综艺$28#日本综艺$29#韩国综艺$36#欧美综艺$30#新马泰综艺$37#其他综艺$38||国产动漫$31#日本动漫$32#韩国动漫$39#港台动漫$40#新马泰动漫$41#欧美动漫$42#其他动漫$43",
"分类url": "https://www.ylys.tv/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html"
}
},
{
"key": "剧圈影视",
Binary file not shown.
Binary file not shown.
-459
View File
@@ -1,459 +0,0 @@
var rule = {
author: '小可乐/240526/第一版',
title: '动漫巴士[漫]',
host: 'http://dm84.site',
hostJs: 'print(HOST);let html=request(HOST,{headers:{"User-Agent":MOBILE_UA}});let src= jsp.pdfh(html,"ul&&a:eq(0)&&href");print(src);HOST=src',
headers: {
'User-Agent': 'MOBILE_UA'
},
编码: 'utf-8',
timeout: 5000,
homeUrl: '/',
url: '/show-fyclass--fyfilter-fypage.html',
filter_url: '{{fl.by}}-{{fl.class}}--{{fl.year}}',
detailUrl: '',
searchUrl: '/s-**---------fypage.html',
searchable: 1,
quickSearch: 1,
filterable: 1,
class_name: '国产动漫&日本动漫&欧美动漫&电影',
class_url: '1&2&3&4',
filter_def: {},
proxy_rule: '',
sniffer: 0,
isVideo: '',
play_parse: true,
parse_url: '',
lazy: `js:
let html = request(input);
let kurl = pdfh(html,'body&&iframe').match(/src="(.*?)"/)[1];
input= kurl
`,
limit: 9,
double: false,
推荐: '*',
//列表;标题;图片;描述;链接;详情(可不写)
一级: '.v_list li;a&&title;a&&data-bg;.desc&&Text;a&&href',
二级: {
//名称;类型
"title": "h1&&Text;meta[name*=class]&&content",
//图片
"img": "img&&src",
//主要描述;年份;地区;演员;导演
"desc": "meta[name*=update_date]&&content;meta[name*=release_date]&&content;meta[name*=area]&&content;meta[name*=actor]&&content;meta[name*=director]&&content",
//简介
"content": "p:eq(-2)&&Text",
//线路数组
"tabs": ".tab_control&&li",
//线路标题
"tab_text": "body&&Text",
//播放数组 选集列表
"lists": ".play_list:eq(#id)&&a",
//选集标题
"list_text": "body&&Text",
//选集链接
"list_url": "a&&href"
},
搜索: '*',
filter: {
"1": [{
"key": "class",
"name": "类型",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "奇幻",
"v": "奇幻"
}, {
"n": "战斗",
"v": "战斗"
}, {
"n": "玄幻",
"v": "玄幻"
}, {
"n": "穿越",
"v": "穿越"
}, {
"n": "科幻",
"v": "科幻"
}, {
"n": "武侠",
"v": "武侠"
}, {
"n": "热血",
"v": "热血"
}, {
"n": "耽美",
"v": "耽美"
}, {
"n": "搞笑",
"v": "搞笑"
}, {
"n": "动态漫画",
"v": "动态漫画"
}]
},
{
"key": "year",
"name": "时间",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "2026",
"v": "2026"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}]
},
{
"key": "by",
"name": "排序",
"value": [{
"n": "时间",
"v": "time"
}, {
"n": "人气",
"v": "hits"
}, {
"n": "评分",
"v": "score"
}]
}
],
"2": [{
"key": "class",
"name": "类型",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "冒险",
"v": "冒险"
}, {
"n": "战斗",
"v": "战斗"
}, {
"n": "奇幻",
"v": "奇幻"
}, {
"n": "后宫",
"v": "后宫"
}, {
"n": "励志",
"v": "励志"
}, {
"n": "校园",
"v": "校园"
}, {
"n": "热血",
"v": "热血"
}, {
"n": "机战",
"v": "机战"
}, {
"n": "搞笑",
"v": "搞笑"
}, {
"n": "悬疑",
"v": "悬疑"
}, {
"n": "治愈",
"v": "治愈"
}, {
"n": "百合",
"v": "百合"
}, {
"n": "恐怖",
"v": "恐怖"
}, {
"n": "推理",
"v": "推理"
}, {
"n": "恋爱",
"v": "恋爱"
}, {
"n": "泡面番",
"v": "泡面番"
}]
},
{
"key": "year",
"name": "时间",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "2026",
"v": "2026"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}]
},
{
"key": "by",
"name": "排序",
"value": [{
"n": "时间",
"v": "time"
}, {
"n": "人气",
"v": "hits"
}, {
"n": "评分",
"v": "score"
}]
}
],
"3": [{
"key": "class",
"name": "类型",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "冒险",
"v": "冒险"
}, {
"n": "战斗",
"v": "战斗"
}, {
"n": "奇幻",
"v": "奇幻"
}, {
"n": "科幻",
"v": "科幻"
}, {
"n": "奇幻",
"v": "奇幻"
}, {
"n": "热血",
"v": "热血"
}, {
"n": "搞笑",
"v": "搞笑"
}, {
"n": "百合",
"v": "百合"
}]
},
{
"key": "year",
"name": "时间",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "2026",
"v": "2026"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}]
},
{
"key": "by",
"name": "排序",
"value": [{
"n": "时间",
"v": "time"
}, {
"n": "人气",
"v": "hits"
}, {
"n": "评分",
"v": "score"
}]
}
],
"4": [{
"key": "class",
"name": "类型",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "冒险",
"v": "冒险"
}, {
"n": "动作",
"v": "动作"
}, {
"n": "奇幻",
"v": "奇幻"
}, {
"n": "科幻",
"v": "科幻"
}, {
"n": "喜剧",
"v": "喜剧"
}, {
"n": "治愈",
"v": "治愈"
}, {
"n": "搞笑",
"v": "搞笑"
}, {
"n": "爱情",
"v": "爱情"
}]
},
{
"key": "year",
"name": "时间",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "2026",
"v": "2026"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}]
},
{
"key": "by",
"name": "排序",
"value": [{
"n": "时间",
"v": "time"
}, {
"n": "人气",
"v": "hits"
}, {
"n": "评分",
"v": "score"
}]
}
]
}
}
Binary file not shown.
@@ -1,6 +0,0 @@
{
"线路数组": "<a data-toggle=\"tab\"&&/a>",
"线路标题": ">&&<",
"分类url": "http://dyxz.tv/list/{cateId}_{catePg}.html",
"分类": "电影$1#电视剧$2#动漫$3#综艺$4"
}
@@ -1,7 +0,0 @@
{
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类": "电影$1#电视剧$2#综艺$3#动漫$4",
"类型": "动作片$6#喜剧片$7#爱情片$8#科幻片$9#奇幻片$10#恐怖片$11#剧情片$12#战争片$20#动画片$26#悬疑片$22#冒险片$23#犯罪片$24#惊悚片$45#歌舞片$46#灾难片$47#网络片$48||国产剧$13#港台剧$14#日剧$15#韩剧$33#欧美剧$16#泰剧$34#新马剧$35#其他剧$25||内地综艺$27#港台综艺$28#日本综艺$29#韩国综艺$36#欧美综艺$30#新马泰综艺$37#其他综艺$38||国产动漫$31#日本动漫$32#韩国动漫$39#港台动漫$40#新马泰动漫$41#欧美动漫$42#其他动漫$43",
"分类url": "https://www.ylys.tv/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html"
}
@@ -1,7 +0,0 @@
{
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类url": "https://v.aiwule.com/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html",
"分类": "电影$20#电视剧$21#动漫$23#综艺$22#短剧$47",
"简介": "简介:&&"
}
+37 -29
View File
@@ -242,26 +242,6 @@
"decrypt": "0"
}
},
{
"key": "久久",
"name": "久久 • APP",
"type": 3,
"api": "csp_AppYsV2",
"searchable": 1,
"quickSearch": 1,
"filterable": 1,
"ext": "http://99cms.jj99.icu:8199/api.php/app/"
},
{
"key": "闪影",
"name": "闪影 • APP",
"type": 3,
"api": "csp_AppYsV2",
"searchable": 1,
"quickSearch": 1,
"filterable": 1,
"ext": "http://38.47.213.61:41271/mogai_api.php/v1.vod"
},
{
"key": "飞飞",
"name": "飞飞 • APP",
@@ -478,12 +458,6 @@
"type": 3,
"api": "csp_Gz360"
},
{
"key": "云播影视",
"name": "云播 • 影视",
"type": 3,
"api": "csp_Tvyb"
},
{
"key": "骚火影视",
"name": "骚火 • 影视",
@@ -507,26 +481,60 @@
"quickSearch": 1,
"filterable": 1
},
{
"key": "枫叶影视",
"name": "枫叶 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": {
"请求头": "手机",
"简介": "text cor3\">[*],&&</div>",
"图片": "data-src=\"&&\"[替换:amp;>>空]",
"主页url": "https://www.cd-zj.com/label/qq.html",
"副标题": "ft2\">&&</i>",
"线路数组": "<i class=\"fa ds-dianying\">&&</span>",
"播放数组": "anthology-list-play size\">&&</ul>",
"分类url": "https://www.cd-zj.com/cupfox-list/{cateId}-{area}--{class}-----{catePg}---{year}.html",
"分类": "电影$1#电视剧$2#综艺$3#动漫$4#短剧$5"
}
},
{
"key": "小镇影视",
"name": "小镇 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": "./XBPQ/小镇影视.json"
"ext": {
"线路数组": "<a data-toggle=\"tab\"&&/a>",
"线路标题": ">&&<",
"分类url": "http://dyxz.tv/list/{cateId}_{catePg}.html",
"分类": "电影$1#电视剧$2#动漫$3#综艺$4"
}
},
{
"key": "面包影视",
"name": "面包 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": "./XBPQ/面包影视.json"
"ext": {
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类url": "https://v.aiwule.com/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html",
"分类": "电影$20#电视剧$21#动漫$23#综艺$22#短剧$47",
"简介": "简介:&&"
}
},
{
"key": "永乐影视",
"name": "永乐 • 影视",
"type": 3,
"api": "csp_XBPQ",
"ext": "./XBPQ/永乐影视.json"
"ext": {
"请求头": "User-Agent$MOBILE_UA",
"编码": "UTF-8",
"分类": "电影$1#电视剧$2#综艺$3#动漫$4",
"类型": "动作片$6#喜剧片$7#爱情片$8#科幻片$9#奇幻片$10#恐怖片$11#剧情片$12#战争片$20#动画片$26#悬疑片$22#冒险片$23#犯罪片$24#惊悚片$45#歌舞片$46#灾难片$47#网络片$48||国产剧$13#港台剧$14#日剧$15#韩剧$33#欧美剧$16#泰剧$34#新马剧$35#其他剧$25||内地综艺$27#港台综艺$28#日本综艺$29#韩国综艺$36#欧美综艺$30#新马泰综艺$37#其他综艺$38||国产动漫$31#日本动漫$32#韩国动漫$39#港台动漫$40#新马泰动漫$41#欧美动漫$42#其他动漫$43",
"分类url": "https://www.ylys.tv/vodshow/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html"
}
},
{
"key": "剧圈影视",
-680
View File
@@ -1,680 +0,0 @@
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
from base.spider import Spider
from Crypto.Util.Padding import unpad, pad
from Crypto.Random import get_random_bytes
import re, os, sys, uuid, time, json, zlib, base64, urllib3, hashlib
from urllib.parse import urlparse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
sys.path.append('..')
class Spider(Spider):
# 规范化类属性定义,避免单行过长和作用域混乱
def_headers2 = {
'User-Agent': '',
'Accept': 'application/json',
'Accept-Encoding': 'gzip',
'Content-Type': 'application/json',
'uuid': '',
'client_type': 'android',
'timestamp': '',
'sign': '',
'nonce': '',
'version': '',
'appkey': '',
'api_version': 'v1'
}
config = {}
host = ''
token = ''
req_uuid = str(uuid.uuid4())
ua = ''
enable_referer = 0
api_prefix = ''
parse_config = {}
# ========== 新增:NSYS/YYNB解析相关配置 ==========
nsys_host = ''
nsys_port = ''
nsys_handshake_key = ''
nsys_enabled = False
nsys_api_type = 'v2' # 默认v2接口
app_version = '' # 保存App版本号,供detail等接口使用
def init(self, extend=''):
try:
if not extend:
return
ext = json.loads(extend) if isinstance(extend, str) else extend
host = ext.get('host', '')
app_key = ext.get('appkey', '')
app_name = ext.get('name', '')
build_signature = ext.get('buildSignature', '')
build_number = ext.get('buildNumber', '')
version_name = ext.get('versionName', '')
package = ext.get('package', '')
self.ua = ext.get('ua', 'Mozilla/5.0 (Linux; Android 13; PGP110 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.196 Mobile Safari/537.36')
self.def_headers2['User-Agent'] = self.ua
self.enable_referer = int(ext.get('referer', 0))
self.api_prefix = ext.get('api_prefix', '').strip()
if self.api_prefix:
prefix = self.api_prefix.strip('/')
if prefix:
self.host = f"{host.rstrip('/')}/{prefix}"
else:
self.host = host.rstrip('/')
else:
parsed = urlparse(host)
if parsed.path and parsed.path != '/' and parsed.path != '':
self.host = host.rstrip('/')
else:
self.host = f"{host.rstrip('/')}/api"
self.parse_config = ext.get('parse', {})
login_path = ext.get('LoginPath', '/app/userInfo')
if not login_path.startswith('/'):
login_path = '/' + login_path
# ========== 新增:NSYS/YYNB解析配置初始化 ==========
nsys_config = ext.get('nsys', {})
if nsys_config:
self.nsys_enabled = True
self.nsys_host = nsys_config.get('host', '')
self.nsys_port = str(nsys_config.get('port', '3737'))
self.nsys_handshake_key = nsys_config.get('handshake_key', '')
self.nsys_api_type = nsys_config.get('api_type', 'v2')
if not (host and app_key and app_name and build_signature and build_number and version_name and package):
self.host = ''
return
self.def_headers2['appkey'] = app_key
self.def_headers2['version'] = ext.get('version', version_name)
self.app_version = self.def_headers2['version']
self.req_uuid = ext.get('uuid') or str(uuid.uuid4())
self.def_headers2['api_version'] = ext.get('api_version', 'v1')
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
init_data = f'{{"v":"{version_name}","n":"{app_name}","s":"{build_signature}","pl":"1","apiVersion":"v2","token":"","timestamp":"{timestamp}","nonce":"{nonce}"}}'
payload = self.encrypt(init_data)
headers = self.headers2(nonce, timestamp, payload)
system_init_url = f'{self.host}/app/systemInit'
response = self.post(system_init_url, data=payload, headers=headers, verify=False, timeout=30)
if response.status_code != 200:
self.host = ''
return
try:
decrypted_data = self.decrypt(response.text, self.req_uuid)
data = json.loads(decrypted_data)
if 'player' in data:
self.config['player'] = data['player']
if 'parser_api' in data:
self.config['parses'] = data['parser_api']
if 'categorys' in data and 'data' in data['categorys']:
self.config['categories'] = data['categorys']['data']
except Exception:
self.host = ''
return
if not self.token:
device_info_cache_key = f'99app_device_info_{app_key}_mPjOv6fHcE'
device_info = self.getCache(device_info_cache_key)
if not device_info:
device_info = {
'did': str(uuid.uuid4()),
'install_time': int(time.time() * 1000)
}
self.setCache(device_info_cache_key, device_info)
install_time = device_info.get('install_time', int(time.time() * 1000))
did = device_info.get('did', str(uuid.uuid4()))
update_time = install_time
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
login_data = f'{{"os":"android","name":"xiaomi","version":"15","sdkInt":32,"device":"xiaomi","brand":"xiaomi","manufacturer":"xiaomi","product":"b0q","hardware":"xiaomi","isPhysicalDevice":true,"androidId":"V417IR","bootloader":"unknown","display":"V417IR release-keys","host":"a11-gz01-test","tags":"release-keys","type":"user","finger":"xiaomi/b0q/b0q:15/V619IR/613:user/release-keys","app":{{"version":"{version_name}","name":"{app_name}","package":"{package}","buildNumber":"{build_number}","buildSignature":"{build_signature}","install":{install_time},"update":{update_time}}},"did":"{did}","apiVersion":"v2","channel":"","token":"","timestamp":"{timestamp}","nonce":"{nonce}"}}'
payload = self.encrypt(login_data)
headers = self.headers2(nonce, timestamp, payload)
login_url = f"{host.rstrip('/')}{login_path}"
response2 = self.post(login_url, data=payload, headers=headers, verify=False).text
try:
device_data = json.loads(self.decrypt(response2, self.req_uuid))
if 'userInfo' in device_data and 'user_token' in device_data['userInfo']:
self.token = device_data['userInfo']['user_token']
except Exception:
pass
except Exception:
self.host = ''
def homeContent(self, filter):
if not self.host:
return None
classes = []
filters = {}
if 'categories' in self.config:
for i in self.config['categories']:
if isinstance(i, dict):
classes.append({'type_id': i['id'], 'type_name': i['name']})
type_id = i['id']
type_extend = i['type_extend']
if not type_extend:
continue
try:
ext = json.loads(type_extend)
except Exception:
continue
# ----- 所有可能出现的筛选字段 -----
# 字段键 -> 展示名称
filter_fields = [
('class', '类型'),
('area', '地区'),
('year', '年份'),
('lang', '语言')
]
f_list = []
for field_key, field_name in filter_fields:
raw_value = ext.get(field_key, '')
if not raw_value or not raw_value.strip():
continue # 字段不存在或为空(如动漫无演员)则跳过
# 构造 “全部 + 具体选项” 数组
values = [{'n': '全部', 'v': ''}]
for v in raw_value.split(','):
v = v.strip()
if v:
values.append({'n': v, 'v': v})
f_list.append({
'key': field_key,
'name': field_name,
'value': values
})
filters[type_id] = f_list
return {'class': classes,'filters': filters}
def homeVideoContent(self):
if not self.host:
return None
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
payload_data = f'{{"kw":"","page":"1","limit":21,"pid":"1","orderBy":"time","isCategory":1,"token":"","timestamp":"{timestamp}","nonce":"{nonce}"}}'
payload = self.encrypt(payload_data)
try:
response = self.post(f'{self.host}/vod/search', data=payload, headers=self.headers2(nonce, timestamp, payload), verify=False).text
data = json.loads(self.decrypt(response, self.req_uuid))
if 'data' in data:
videos = self.arr2vods(data['data'])
return {'list': videos}
return {'list': []}
except Exception:
return {'list': []}
def categoryContent(self, tid, pg, filter, extend):
if not self.host:
return {'list': [], 'pagecount': 1, 'page': pg}
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
# 基础参数
payload_data = {
"kw": "",
"page": str(pg),
"limit": "21",
"pid": tid,
"orderBy": "time",
"isCategory": 1,
"token": self.token,
"timestamp": timestamp,
"nonce": nonce
}
# 整合 extend 筛选条件,仅添加非空值
if filter and extend:
# 字段映射:extend中的key -> payload中的key
field_map = {
"area": "area",
"year": "year",
"lang": "lang",
"class": "class"
}
for ext_key, payload_key in field_map.items():
value = extend.get(ext_key)
# 只有当值存在且不为空字符串时,才添加到payload
if value is not None and value != "":
payload_data[payload_key] = value
# 加密 payload
payload_str = json.dumps(payload_data)
payload = self.encrypt(payload_str)
try:
response = self.post(f'{self.host}/vod/search', data=payload, headers=self.headers2(nonce,timestamp,payload), verify=False).text
data = json.loads(self.decrypt(response))
if 'data' in data:
videos = self.arr2vods(data['data'])
pagecount = data.get('page_count', 1)
return {'list': videos, 'pagecount': pagecount, 'page': pg}
else:
return {'list': [], 'pagecount': 1, 'page': pg}
except Exception as e:
return {'list': [], 'pagecount': 1, 'page': pg}
def searchContent(self, key, quick, pg='1'):
if not self.host:
return {'list': [], 'pagecount': 1, 'page': pg}
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
payload_data = f'{{"kw":"{key}","page":{int(pg)},"limit":21,"orderBy":"vod_hits_month","sort":"desc","token":"{self.token}","timestamp":"{timestamp}","nonce":"{nonce}"}}'
payload = self.encrypt(payload_data)
try:
response = self.post(f'{self.host}/vod/search', data=payload, headers=self.headers2(nonce, timestamp, payload), verify=False).text
data = json.loads(self.decrypt(response, self.req_uuid))
if 'data' in data:
videos = self.arr2vods(data['data'])
pagecount = data.get('page_count', 1)
return {'list': videos, 'pagecount': pagecount, 'page': pg}
return {'list': [], 'pagecount': 1, 'page': pg}
except Exception:
return {'list': [], 'pagecount': 1, 'page': pg}
def detailContent(self, ids):
if not self.host or not ids:
return None
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
payload_data = f'{{"id":"{ids[0]}","eps":"1","v":"{self.app_version}","pl":1,"token":"{self.token}","timestamp":"{timestamp}","nonce":"{nonce}"}}'
payload = self.encrypt(payload_data)
try:
response = self.post(f'{self.host}/vod/detail', data=payload, headers=self.headers2(nonce, timestamp, payload), verify=False).text
response_data = json.loads(self.decrypt(response))
if 'data' in response_data:
data = response_data['data']
players = self.config.get('player', {})
print(players)
play_from_list = data.get('play_from', '').split('$$$')
play_url_list = data.get('play_url', '').split('$$$')
resources = dict(zip(play_from_list, play_url_list))
player_sequence = sorted(
players.keys(),
key=lambda k: (
'4K' in players[k].get('code', ''), # 包含4K则为True1),否则False0
players[k].get('code', '') # 同组内按code字符串排序
),
reverse=True
)
show2 = []
play_urls2 = []
for key in player_sequence:
if key in resources:
player = players[key]
if player.get('name', key) != key:
show2.append(f"{player.get('name', key)}\u2005({key})")
else:
show2.append(key)
urls = resources[key].split('#')
urls2 = []
for url_part in urls:
if '$' in url_part:
parts = url_part.split('$', 1)
if len(parts) > 1:
urls2.append(f"{parts[0]}${key}@{parts[1]}")
play_urls2.append('#'.join(urls2))
video = {
'vod_id': data.get('id', ''),
'vod_name': data.get('name', ''),
'vod_pic': data.get('pic', ''),
'vod_remarks': data.get('remarks', ''),
'vod_year': data.get('year', ''),
'vod_area': data.get('area', ''),
'vod_actor': data.get('actor', ''),
'vod_director': data.get('director', ''),
'vod_content': data.get('content', ''),
'vod_play_from': '$$$'.join(show2),
'vod_play_url': '$$$'.join(play_urls2),
'type_name': data.get('class', '')
}
return {'list': [video]}
return {'list': []}
except Exception:
return {'list': []}
def playerContent(self, flag, vid, vip_flags):
jx, sniff, url, play_headers = 0, 0, '', {'User-Agent': self.ua}
webview_headers = {
'User-Agent': self.ua,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7'
}
try:
if '@' in vid:
# 限制分割次数为1,防止真实URL内部带有@符号导致解包错误
play_from, raw_url = vid.split('@', 1)
else:
return {'jx': 0, 'parse': 0, 'url': vid, 'header': play_headers}
except Exception:
return {'jx': 0, 'parse': 0, 'url': vid, 'header': play_headers}
players = self.config.get('player', {})
parses = self.config.get('parses', [])
def add_referer(target_url):
if self.enable_referer == 1:
try:
parsed = urlparse(target_url)
if parsed.netloc:
play_headers['Referer'] = f"{parsed.scheme}://{parsed.netloc}/"
except Exception:
pass
def try_all_parsers(raw_url_to_parse):
for parser in parses:
if parser.get('api_type') == 'json' and parser.get('is_server_parser') == 1:
parse_id = parser.get('id')
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
payload_data = json.dumps({
"id": parse_id,
"url": raw_url_to_parse,
"token": self.token,
"timestamp": timestamp,
"nonce": nonce
})
payload = self.encrypt(payload_data)
headers = self.headers2(nonce, timestamp, payload)
try:
response = self.post(f'{self.host}/app/vodParser', data=payload, headers=headers, verify=False)
if response.status_code == 200:
decrypted = self.decrypt(response.text, self.req_uuid)
data = json.loads(decrypted)
if 'data' in data and data['data']:
parsed_url = data['data']
if isinstance(parsed_url, str) and parsed_url.startswith('http'):
return parsed_url
except Exception:
continue
return None
# ========== 修改:兼容NSYS与YYNB解析逻辑 ==========
# 如果raw_url是NSYS或YYNB格式,调用解析接口
if (raw_url.startswith('NSYS-') or raw_url.startswith('YYNB-')) and self.nsys_enabled and self.nsys_host:
nsys_result = self.nsys_parse(raw_url)
if nsys_result:
add_referer(nsys_result)
return {'jx': 0, 'parse': 0, 'url': nsys_result, 'header': play_headers}
if re.search(r'(?:mgtv\.com|v\.qq\.com|iqiyi\.com|youku\.com|bilibili\.com|le\.com|sohu\.com|pptv\.com|1905\.com|cntv\.cn|cctv\.com|miguvideo\.com)', raw_url):
parsed_url = try_all_parsers(raw_url)
if parsed_url:
add_referer(parsed_url)
return {'jx': 0, 'parse': 0, 'url': parsed_url, 'header': play_headers}
jx = 1
return {'jx': jx, 'parse': 0, 'url': raw_url, 'header': webview_headers}
if '.m3u8' in raw_url or '.mp4' in raw_url:
url = raw_url
add_referer(url)
if play_from in players:
try:
server_headers = json.loads(players[play_from].get('headers', '{}'))
if isinstance(server_headers, dict):
play_headers.update(server_headers)
except Exception:
pass
return {'jx': 0, 'parse': 0, 'url': url, 'header': play_headers}
if play_from in players:
player = players[play_from]
player_type = player.get('type', 0)
parse_rule = []
if player.get('parseUrl'):
parse_rule = player['parseUrl'].split(',')
if parse_rule and parses:
for parse_id_str in parse_rule:
try:
parse_id = int(parse_id_str.strip())
for parser in parses:
if str(parser.get('id')) == str(parse_id) and parser.get('is_server_parser') == 1:
nonce, timestamp = self.nonce(), str(int(time.time() * 1000))
payload_data = json.dumps({
"id": parse_id,
"url": raw_url,
"token": self.token,
"timestamp": timestamp,
"nonce": nonce
})
payload = self.encrypt(payload_data)
headers = self.headers2(nonce, timestamp, payload)
try:
response = self.post(f'{self.host}/app/vodParser', data=payload, headers=headers, verify=False)
if response.status_code == 200:
decrypted = self.decrypt(response.text, self.req_uuid)
data = json.loads(decrypted)
if 'data' in data and data['data']:
parsed_url = data['data']
if isinstance(parsed_url, str) and parsed_url.startswith('http'):
url = parsed_url
add_referer(url)
return {'jx': 0, 'parse': 0, 'url': url, 'header': play_headers}
except Exception:
continue
except Exception:
continue
if not url:
parsed_url = try_all_parsers(raw_url)
if parsed_url:
url = parsed_url
add_referer(url)
return {'jx': 0, 'parse': 0, 'url': url, 'header': play_headers}
if player_type == 2:
sniff = 1
play_headers = webview_headers
return {'jx': 0, 'parse': 1, 'url': raw_url, 'header': play_headers}
if self.parse_config:
for parse_keys, parse_urls in self.parse_config.items():
if isinstance(parse_keys, str):
play_from_list = [k.strip() for k in parse_keys.split(',')]
if play_from in play_from_list:
if isinstance(parse_urls, list):
for parse_url in parse_urls:
try:
full_url = f"{parse_url}{raw_url}"
response = self.fetch(full_url, headers=play_headers, verify=False)
if response and response.status_code == 200:
try:
data = response.json()
play_url = data.get('url') or data.get('play_url') or data.get('data')
if play_url and isinstance(play_url, str) and play_url.startswith('http'):
return {'jx': 0, 'parse': 0, 'url': play_url, 'header': play_headers}
except Exception:
pass
except Exception:
continue
if url:
return {'jx': 0, 'parse': 0, 'url': url, 'header': play_headers}
url = raw_url
add_referer(url)
return {'jx': jx, 'parse': sniff, 'url': url, 'header': play_headers}
# ========== 修改:兼容NSYS与YYNB解析方法 ==========
def nsys_parse(self, raw_url):
"""
NSYS/YYNB解析接口适配
根据抓包数据:
- 请求: GET http://{host}:{port}?url={加密后的URL}
- 响应: JSON {"code": 200, "type": "单线程", "msg": "解析成功", "url": "真实m3u8地址"}
"""
try:
if not self.nsys_host or not self.nsys_port:
return None
# 构造解析请求URL
# 抓包显示格式: http://114.66.41.137:3737?url=NSYS-xxx 或 YYNB-xxx
nsys_api_url = f"http://{self.nsys_host}:{self.nsys_port}"
# 对原始URL进行格式编码
encoded_url = self.nsys_encode_url(raw_url)
params = {'url': encoded_url}
headers = {
'User-Agent': self.ua,
'Accept-Encoding': 'gzip'
}
response = self.fetch(nsys_api_url, params=params, headers=headers, verify=False, timeout=15)
if response and response.status_code == 200:
try:
data = response.json()
if data.get('code') == 200 and data.get('url'):
parsed_url = data['url']
if isinstance(parsed_url, str) and parsed_url.startswith('http'):
return parsed_url
except Exception:
pass
return None
except Exception:
return None
def nsys_encode_url(self, raw_url):
"""
NSYS/YYNB URL编码方法
根据抓包数据格式: NSYS-xxx 或 YYNB-xxx
由于编码是App内部加密算法生成,此处无法实现完全相同的编码,
因此采用透传策略:如果raw_url已经是指定格式则直接透传,否则返回None让上层处理
"""
try:
# 如果raw_url已经是支持的格式,直接透传
if raw_url.startswith('NSYS-') or raw_url.startswith('YYNB-'):
return raw_url
# 非支持格式的URL无法编码,返回None
return None
except Exception:
return None
def decrypt(self, data, key=''):
try:
if not key:
key = self.req_uuid
encrypted_bytes = base64.b64decode(data)
if len(encrypted_bytes) < 16:
raise ValueError("数据太短")
iv = encrypted_bytes[:16]
ciphertext = encrypted_bytes[16:]
key_bytes = key.replace('-', '').encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
decrypted_padded = cipher.decrypt(ciphertext)
decrypted_raw = unpad(decrypted_padded, AES.block_size)
try:
deflated_data = zlib.decompress(decrypted_raw)
return deflated_data.decode('utf-8')
except zlib.error:
try:
return decrypted_raw.decode('utf-8')
except Exception:
raise ValueError("解密失败")
except Exception:
raise ValueError
def encrypt(self, data, key=''):
try:
if not key:
key = self.req_uuid
data_bytes = data.encode('utf-8')
padded_data = pad(data_bytes, AES.block_size)
iv = get_random_bytes(AES.block_size)
key_bytes = key.replace('-', '').encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
encrypted_bytes = cipher.encrypt(padded_data)
result_bytes = iv + encrypted_bytes
return base64.b64encode(result_bytes).decode('utf-8')
except Exception:
raise ValueError
def arr2vods(self, arr):
videos = []
if not isinstance(arr, list):
return videos
for i in arr:
if isinstance(i, dict):
videos.append({
'vod_id': i.get('id', ''),
'vod_name': i.get('name', ''),
'vod_pic': i.get('pic', ''),
'vod_remarks': i.get('remarks', ''),
'vod_year': i.get('year', ''),
'vod_content': i.get('blurb', ''),
'type_name': i.get('class', ''),
'vod_area': i.get('area', ''),
'vod_actor': i.get('actor', ''),
'vod_director': i.get('director', '')
})
return videos
def headers2(self, nonce, timestamp, payload=''):
sign = self.sign(payload, timestamp, nonce, self.token, self.def_headers2.get('appkey', ''))
headers = {
**self.def_headers2,
'uuid': self.req_uuid,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce
}
return headers
def sign(self, body, timestamp, nonce, token, app_key):
combined = f'{body}:{timestamp}:{nonce}:{token}:{app_key}'
return hashlib.sha256(combined.encode('utf-8')).hexdigest()
def nonce(self):
random_bytes = os.urandom(16)
return base64.b64encode(random_bytes).decode('utf-8')
def getName(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
def localProxy(self, param):
pass
-329
View File
@@ -1,329 +0,0 @@
# coding=utf-8
# !/usr/bin/python
"""
作者 丢丢喵推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================Diudiumiao====================
"""
from Crypto.Util.Padding import unpad
from Crypto.Util.Padding import pad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from urllib.parse import quote
from base.spider import Spider
from Crypto.Cipher import AES
from datetime import datetime
from bs4 import BeautifulSoup
from base64 import b64decode
import urllib.request
import urllib.parse
import datetime
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://djw1.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {"class": []}
detail = requests.get(url=xurl + "/all/", headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('section', class_="container items")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
id = vod.find('a')['href']
name = vod.text.strip()
result["class"].append({"type_id": id, "type_name": "" + name})
return result
def homeVideoContent(self):
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{cid}page/{str(page)}/'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('section', class_="container items")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="image-line")
id = ids['href']
pic = vod.find('img')['src']
remark = self.extract_middle_text(str(vod), 'class="remarks light">', '<', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '▶️' + remark
}
videos.append(video)
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
result = {}
videos = []
xianlu = ''
bofang = ''
if 'http' not in did:
did = xurl + did
res = requests.get(url=did, headers=headerx)
res.encoding = "utf-8"
res = res.text
doc = BeautifulSoup(res, "lxml")
url = 'https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1732707176882/jiduo.txt'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = self.extract_middle_text(res,'class="info-detail">','<', 0)
remarks = self.extract_middle_text(res, 'class="info-mark">', '<', 0)
year = self.extract_middle_text(res, 'class="info-addtime">', '<', 0)
if name not in content:
bofang = Jumps
xianlu = '1'
else:
soups = doc.find('div', class_="ep-list-items")
soup = soups.find_all('a')
for sou in soup:
id = sou['href']
name = sou.text.strip()
bofang = bofang + name + '$' + id + '#'
bofang = bofang[:-1]
xianlu = '专线'
videos.append({
"vod_id": did,
"vod_remarks": remarks,
"vod_year": year,
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
res = requests.get(url=id, headers=headerx)
res.encoding = "utf-8"
res = res.text
url = self.extract_middle_text(res, '"wwm3u8":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, pg):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
url = f'{xurl}/search/{key}/page/{str(page)}/'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('section', class_="container items")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="image-line")
id = ids['href']
pic = vod.find('img')['src']
remark = self.extract_middle_text(str(vod), 'class="remarks light">', '<', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick, pg="1"):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.