Sync all projects

This commit is contained in:
github-actions[bot]
2026-07-17 09:35:49 +00:00
orang tua 04d0462a9d
melakukan b0139c0a3e
150 mengubah file dengan 43293 tambahan dan 8238 penghapusan
Melihat File
-3
Melihat File
@@ -1,3 +0,0 @@
//本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
//严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
let e={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",Connection:"Keep-Alive","Accept-Language":"zh-CN,zh;q=0.8","Cache-Control":"no-cache"},t=5e3,i=2,a=0,s=1,r={},l={},n={},o={},p=[],c="",f="",h="",d="",u="";async function g(l){let p=l.ext||"";if("string"==typeof p&&p.startsWith("http"))c=p;else if("object"==typeof p)try{c=p.host,d=p.key||"",u=p.sign||"",i=p.ver||2,h=(p.cms||"").replace(/\/$/,""),/^https?:\/\/.*\/vod/.test(h)&&(h+=h.includes("?")?"&":"?"),f=p.from||"",o=p.parse||{},a=p.custom_first||0,s=void 0!==p.category?p.category:1;let l=p.ua;l&&("string"==typeof l?e["User-Agent"]=l:"object"==typeof l&&(r={host:l.host,config:l.config,home:l.home,category:l.category,search:l.search,parse:l.parse,player:l.player})),t=1e3*(p.timeout||5)}catch(e){}if(!/^https?:\/\/[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?(\/)?$/.test(c)){let i=Object.assign({},e);r.host&&(i["User-Agent"]=r.host);let a=await req(c,{headers:i,timeout:t});try{let e=JSON.parse(a.content);e.apiDomain&&(c=e.apiDomain)}catch(e){let t=(a.content||"").trim();t.startsWith("http")&&(c=t)}}c=c.replace(/\/$/,"");let g=d&&u;if(3!==i||g)g&&(i=3);else{let e=O();r.config&&(e["User-Agent"]=r.config);let i=(await S(`${c}/api.php/Appfox/config`,{headers:e,timeout:t})).data||{};i.app_key&&i.app_sign&&(d=i.app_key,u=i.app_sign);let a=i.playerList||[],s=i.jiexiDataList||[];a.length>0&&(n={playerList:a,jiexiDataList:s})}}async function y(i){if(!c||0===s)return JSON.stringify({class:[]});let a=Object.assign({},e);r.home&&(a["User-Agent"]=r.home);let l=[],n={},o={class:l,filters:n};if(h&&2!==s){let e=h.replace(/&$/,"");e=e.replace(/&ac=videolist/g,"").replace(/ac=videolist&/g,"").replace(/ac=videolist/g,""),e=e.replace("ac=detail","ac=list");let i=await S(e,{headers:a,timeout:t});i&&i.class&&(l=i.class),o=await S(h.replace(/&$/,""),{headers:a,timeout:t})||{},o.class=l,2===s&&o.list&&o.list.forEach((e=>e.vod_id=`msearch:${e.vod_id}`))}else{let e=await S(`${c}/api.php/Appfox/init`,{headers:a,timeout:t});e&&e.data&&e.data.type_list&&e.data.type_list.forEach((e=>{let t=String(e.type_id);if(l.push({type_id:t,type_name:e.type_name}),i&&e.filter_type_list&&e.filter_type_list.length>0){let i=[];e.filter_type_list.forEach((e=>{let t=e.name;switch(e.name){case"class":t="类型";break;case"area":t="地区";break;case"lang":t="语言";break;case"year":t="年份";break;case"sort":t="排序"}let a=[],s="";e.list.forEach((e=>{e&&a.push({n:e,v:e})})),a.length>0&&(s="sort"===e.name&&e.list.includes("最新")?"最新":e.list.includes("全部")?"全部":a[0].v,i.push({key:e.name,name:t,init:s,value:a}))})),i.length>0&&(n[t]=i)}})),o.class=l,o.filters=n}return JSON.stringify(o)}async function m(){if(!c||0===s)return JSON.stringify({list:[]});if(h&&2!==s)return JSON.stringify({list:[]});let a=Object.assign({},e);(r.homeVideo||r.home)&&(a["User-Agent"]=r.homeVideo||r.home);let l="index";if(2===i||3===i){let e=await S(`${c}/api.php/appfox/nav`,{headers:a,timeout:t}),i="";if(e&&e.data)for(let t of e.data)if("object"==typeof t){i=t.navigationId;break}if(!i)return JSON.stringify({list:[]});l=`nav_video?id=${i}`}let n=await S(`${c}/api.php/Appfox/${l}`,{headers:a,timeout:t}),o=[];return n&&n.data&&n.data.forEach((e=>{e.banner&&o.push(...e.banner),e.categories&&e.categories.forEach((e=>{e.videos&&o.push(...e.videos)}))})),o.length>0&&2===s&&o.forEach((e=>e.vod_id=`msearch:${e.vod_id}`)),JSON.stringify({list:o})}async function $(i,a,l,n){if(!c)return JSON.stringify({list:[]});let o=Object.assign({},e);r.category&&(o["User-Agent"]=r.category);let p={list:[]};if(h&&2!==s)p=await S(`${h}pg=${a}&t=${i}`,{headers:o,timeout:t})||{list:[]};else{let e=n.class||"全部",s=n.area||"全部",r=n.lang||"全部",l=n.year||"全部",f=n.sort||"最新",h=`${c}/api.php/Appfox/vodList?type_id=${i}&class=${encodeURIComponent(e)}&area=${encodeURIComponent(s)}&lang=${encodeURIComponent(r)}&year=${encodeURIComponent(l)}&sort=${encodeURIComponent(f)}&page=${a}`,d=await S(h,{headers:o,timeout:t});d&&d.data&&d.data.recommend_list&&(p.list=d.data.recommend_list)}return 2===s&&p.list&&p.list.forEach((e=>e.vod_id=`msearch:${e.vod_id}`)),JSON.stringify({...p,page:parseInt(a)})}async function _(a,s,l=1){if(!c)return JSON.stringify({list:[]});let n=Object.assign({},e);r.search&&(n["User-Agent"]=r.search);let o={list:[]};if(h){let e=h.includes("?")?h.split("?")[0]+"?":h;o=await S(`${e}ac=detail&wd=${encodeURIComponent(a)}`,{headers:n,timeout:t})||{list:[]},p=o.list||[]}else{if(3===i){let e={ac:"detail",wd:a,pg:String(l)},i=O(JSON.stringify(e));r.search&&(i["User-Agent"]=r.search),o=b((await req(`${c}/api.php/appfoxs/vod`,{method:"post",data:e,headers:i,postType:"",timeout:t})).content)}else{let e=`${c}/api.php/Appfox/vod?ac=detail&wd=${encodeURIComponent(a)}`;f&&(e+=`&from=${f}`),o=await S(e,{headers:n,timeout:t})||{list:[]}}p=o.list||[]}return JSON.stringify(o)}async function v(a){let s=Object.assign({},e),o=r.detail||r.search;o&&(s["User-Agent"]=o);let f=p.find((e=>String(e.vod_id)===String(a)));if(!f)if(h){let e=h.includes("?")?h.split("?")[0]+"?":h,i=await S(`${e}ac=detail&ids=${a}`,{headers:s,timeout:t});i&&i.list&&i.list.length>0&&(f=i.list[0])}else if(3===i){let e={ac:"detail",ids:String(a)},i=O(JSON.stringify(e));o&&(i["User-Agent"]=o);let s=b((await req(`${c}/api.php/appfoxs/vod`,{method:"post",data:e,headers:i,postType:"",timeout:t})).content);s&&s.list&&(f=s.list[0])}else{let e=await S(`${c}/api.php/Appfox/vod?ac=detail&ids=${a}`,{headers:s,timeout:t});e&&e.list&&(f=e.list[0])}if(!f)return JSON.stringify({list:[]});let d=(f.vod_play_from||"").split("$$$"),u=(f.vod_play_url||"").split("$$$");try{let a=3===i?O():Object.assign({},e);if(r.config&&(a["User-Agent"]=r.config),!n||!n.playerList)if(3===i){let e=b((await req(`${c}/api.php/appfoxs/config`,{headers:a,timeout:t})).content);n={playerList:e?.data?.playerList||[],jiexiDataList:e?.data?.jiexiDataList||[]}}else{let e=await S(`${c}/api.php/Appfox/config`,{headers:a,timeout:t});n={playerList:e?.data?.playerList||[],jiexiDataList:e?.data?.jiexiDataList||[]}}let s=n.playerList||[],o=n.jiexiDataList||[],p={};s.forEach((e=>p[e.playerCode]=e));let h=[];for(let e=0;e<d.length;e++){let t=d[e];if(p[t]){let i=p[t];i.playerCode!==i.playerName&&(d[e]=`${i.playerName}(${t})`)}if(e<u.length){let i=u[e].split("#"),a=[];for(let e of i){let i=e.split("$");i.length>=2?a.push(i[0]+"$"+t+"@"+i[1]):a.push(e)}h.push(a.join("#"))}}f.vod_play_from=d.join("$$$"),f.vod_play_url=h.join("$$$"),l={},o.forEach((e=>{(e.url||"").startsWith("http")&&(l[e.playerCode]=e.url)}))}catch(e){}return JSON.stringify({list:[f]})}async function A(i,s,n){let p=s.indexOf("@"),c=p>-1?s.substring(0,p):"",f=p>-1?s.substring(p+1):s,h=0,d=0,u=0,g={...e};r.parse&&(g["User-Agent"]=r.parse);let y=r.player||"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",m=f,$=1===a?[o,l]:[l,o];for(let e of $){if(!u&&!/^https?:\/\/.*\.(m3u8|mp4|flv|mkv)/.test(m))for(let i in e){if(!i.includes(c))continue;let a=e[i];if(Array.isArray(a))for(let e of a){if(e.startsWith("parse:")){m=e.split("parse:")[1]+f,h=0,d=1,u=1;break}try{let i=await S(`${e}${f}`,{headers:g,timeout:t});if(i&&i.url&&i.url.startsWith("http")){m=i.url,u=1;break}}catch(e){}}else if("string"==typeof a){if(a.startsWith("parse:")){m=a.split("parse:")[1]+f,h=0,d=1,u=1;break}try{let e=await S(`${a}${f}`,{headers:g,timeout:t});if(e&&e.url&&e.url.startsWith("http")){m=e.url,u=1;break}}catch(e){}}if(u||d)break}if(u||d)break}return/^https?:\/\/.*\.(m3u8|mp4|flv|mkv)/.test(m)||1===u||(h=1),JSON.stringify({jx:h,parse:d,url:m,header:{"User-Agent":y}})}function b(e){if(!e)return{};try{return JSON.parse(e)}catch(t){try{return JSON.parse(function(e){try{let t=md5X(d).substring(0,16),i=t.split("").reverse().join("");return aesX("AES/CBC/PKCS7",!1,e,!0,t,i,!1)}catch(t){return e}}(e))}catch(t){return e}}}async function S(e,t={}){try{return b((await req(e,t)).content)}catch(e){return{}}}function O(t=""){let i=(new Date).getTime(),a=Math.floor(9e5*Math.random())+1e5,s=md5X(`${u}${d}${i}${a}${t}`);return{"User-Agent":e["User-Agent"],"x-security-auth":`${i}|${a}|${s}`,"content-type":"application/json; charset=utf-8"}}export function __jsEvalReturn(){return{init:g,home:y,homeVod:m,category:$,search:_,detail:v,play:A}}
-412
Melihat File
@@ -1,412 +0,0 @@
# coding = utf-8
# !/usr/bin/python
# 新时代青年 2025.06.25 getApp第三版
# 基于原作者修改版本,仅限个人学习爬虫技术,严禁用于任何盈利用途
from Crypto.Cipher import AES
from base.spider import Spider
from Crypto.Util.Padding import pad, unpad
from concurrent.futures import ThreadPoolExecutor, as_completed
import re, sys, time, uuid, json, base64, urllib3, random, hashlib, os, urllib.parse
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
sys.path.append('..')
TARGET_DOMAIN = 'app.lkdyw.cn'
class Spider(Spider):
xurl, key, iv, init_data, search_verify = '', '', '', '', ''
username, password, device_id, version, get_type = '', '', '', '', '0'
def_headers, auto_vip, line_block, search_timeout = {'User-Agent': 'okhttp/3.14.9'}, 0, [], 10
vip_purchased, retry_count, sort_keywords, token_cache_file = False, 0, [], ''
auto_vip_triggered, search_mode, auto_vip_enabled = False, False, False
base_host, cache_dir = '', ''
search_index_suffix = 'searchList'
verify_code = ''
is_api3 = False
def _set_cache_filename(self, host):
try:
parsed = urllib.parse.urlparse(host)
domain = parsed.netloc or os.path.basename(parsed.path)
safe_domain = re.sub(r'[^a-zA-Z0-9_.-]', '_', domain)
self.cache_dir = '/storage/emulated/0/Download/cache'
os.makedirs(self.cache_dir, exist_ok=True)
current_date = time.strftime("%Y%m%d")
if parsed.netloc == TARGET_DOMAIN:
self.token_cache_file = os.path.join(self.cache_dir, f"{safe_domain}_token{current_date}.json")
else:
self.token_cache_file = os.path.join(self.cache_dir, f"{safe_domain}_token.json")
except:
self.cache_dir = '/storage/emulated/0/Download/cache'
os.makedirs(self.cache_dir, exist_ok=True)
self.token_cache_file = os.path.join(self.cache_dir, "default_token.json")
def init(self, extend=''):
ext = json.loads(extend.strip()) if extend.strip() else {}
api_map = {
'2': '/api.php/qijiappapi',
'qiji': '/api.php/qijiappapi',
'flutter': '/api.php/getappapi',
'get': '/api.php/getappapi',
'3': '/api/vod/'
}
api = api_map.get(str(ext.get('api')), '/api.php/getappapi')
self.get_type = str(ext.get('api')) if str(ext.get('api')) in api_map else 'default'
self.is_api3 = self.get_type == '3'
host = ext['host']
self.search_index_suffix = ext.get('index', 'searchList').strip()
self.verify_code = ext.get('verify_code', '').strip()
if not re.match(r'^https?://', host):
host = 'http://' + host
parsed_host = urllib.parse.urlparse(host)
self.base_host = f"{parsed_host.scheme}://{parsed_host.netloc}".rstrip('/')
domain_set = set()
if re.match(r'^https?:\/\/[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?(\/)?$', host):
domain_set.add(host)
else:
host_data = self.fetch(host, headers=self.get_headers(1), timeout=10, verify=False).text
domain_set.update([d.strip() for d in host_data.split('\n') if d.strip()])
self.def_headers['User-Agent'] = ext.get('ua', self.def_headers['User-Agent'])
self.key = ext.get('key', ext.get('datakey'))
if not self.key: return
self.iv = ext.get('iv', ext.get('dataiv')) or self.key
self.device_id = ext.get('devideid') or ext.get('deviceid', '')
if not self.device_id:
self.device_id = ''.join(random.choices('0123456789abcdef', k=33))
self.version, self.username, self.password = str(ext.get('version', '')), ext.get('username'), ext.get('password')
self.auto_vip = int(ext.get('auto_vip', 0))
self.auto_vip_enabled = self.auto_vip in (1, 2)
self.search_mode = ext.get('search', False) in (1, '1', 'true', 'TRUE')
line_block_conf = ext.get('line_block', '')
self.line_block = [kw.strip() for kw in (line_block_conf.split(',') if isinstance(line_block_conf, str) else line_block_conf) if kw.strip()]
from_config = ext.get('from', '').strip()
if from_config:
self.sort_keywords = [kw.strip() for kw in from_config.split('>') if kw.strip()]
self.search_timeout = int(ext.get('time', 10))
self.search_timeout = 10 if not (0 < self.search_timeout <= 60) else self.search_timeout
self._set_cache_filename(self.base_host)
self.load_token_cache()
if not self.def_headers.get('app-user-token') and ext.get('token'):
self.def_headers['app-user-token'] = ext.get('token')
if self.device_id:
self.def_headers['app-user-device-id'] = self.device_id
# ==================== 新增:初始化POST请求参数 ====================
init_post_data = {
"device_id": self.device_id,
"version": self.version,
"timestamp": str(int(time.time()))
}
# ===============================================================
for domain in domain_set:
try:
self.xurl = f"{domain}{api}"
init_api = 'init' if self.is_api3 else 'initV119'
init_url = f'{self.xurl}{init_api}' if self.is_api3 else f'{self.xurl}.index/{init_api}'
headers = self.get_headers()
# ==================== 核心:init改用POST请求 ====================
res = self.post(
url=init_url,
data=init_post_data,
headers=headers,
timeout=(5, 5),
verify=False
).json()
# ===============================================================
self.init_data = json.loads(self.decrypt(res['data']))
self.search_verify = self.init_data['config'].get('system_search_verify_status', False)
break
except Exception as e:
continue
if self.auto_vip_enabled and not self.def_headers.get('app-user-token') and not self.vip_purchased:
self.silent_register_and_buy_vip()
self.vip_purchased = True
def fuzzy_sort_lines(self, lines):
if not lines or not self.sort_keywords: return lines
def get_sort_weight(line):
line_name = line['player_show'].lower()
for idx, kw in enumerate(self.sort_keywords):
if kw.lower() in line_name: return idx
return len(self.sort_keywords)
return sorted(lines, key=lambda x: get_sort_weight(x))
def load_token_cache(self):
try:
parsed_host = urllib.parse.urlparse(self.base_host)
if parsed_host.netloc == TARGET_DOMAIN:
current_date = time.strftime("%Y%m%d")
for file in os.listdir(self.cache_dir):
if file.startswith(f"{re.sub(r'[^a-zA-Z0-9_.-]', '_', parsed_host.netloc)}_token") and file.endswith('.json'):
if current_date not in file:
os.remove(os.path.join(self.cache_dir, file))
if os.path.exists(self.token_cache_file):
with open(self.token_cache_file, 'r') as f:
cache = json.load(f)
if cache.get('host') != self.base_host:
return
if cache.get('token'):
self.def_headers['app-user-token'] = cache['token']
if cache.get('device_id'):
self.device_id = cache['device_id']
self.def_headers['app-user-device-id'] = cache['device_id']
except:
pass
def save_token_cache(self, token, device_id):
try:
os.makedirs(self.cache_dir, exist_ok=True)
cache_data = {'token': token, 'device_id': device_id, 'timestamp': int(time.time()), 'host': self.base_host}
with open(self.token_cache_file, 'w') as f:
json.dump(cache_data, f)
except:
pass
def get_headers(self, main=0):
base_headers = {'Accept-Encoding': 'gzip'}
if self.get_type == 'qiji': return {**base_headers, 'User-Agent': 'okhttp/3.10.0', 'Connection': 'Keep-Alive', **self.def_headers}
elif self.get_type == 'flutter':
flutter_headers = {'User-Agent': 'Dart/3.5 (dart:io)'} if main == 1 else {'User-Agent': '', 'app-version-code': self.version, 'app-os': 'android', 'app-ui-mode': 'light'}
return {**base_headers, **flutter_headers, **self.def_headers}
elif self.get_type == 'get':
timestamp = str(int(time.time()))
get_headers = {'User-Agent': 'okhttp/3.14.9'} if main == 1 else {'User-Agent': '', 'Connection': 'Keep-Alive', 'app-version-code': self.version, 'app-ui-mode': 'light', 'app-user-device-id': self.device_id, 'app-api-verify-time': timestamp, 'app-api-verify-sign': self.encrypt(timestamp), 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
return {**base_headers, **get_headers, **self.def_headers}
elif self.is_api3:
return {**base_headers, **self.def_headers}
return {**base_headers, **self.def_headers}
def login(self):
if self.username and self.password and self.device_id:
timestamp = str(int(time.time()))
headers = self.get_headers().copy()
headers.update({'app-version-code': "", 'app-ui-mode': 'light', 'app-api-verify-time': timestamp, 'app-api-verify-sign': self.generate_signature(timestamp)})
login_url = f'{self.xurl}appLogin' if self.is_api3 else f'{self.xurl}.index/appLogin'
res = self.post(login_url, data={'password': self.password, 'code': "", 'device_id': self.device_id, 'user_name': self.username, 'invite_code': "", 'is_emulator': "0"}, headers=headers).json()
auth_token = json.loads(self.decrypt(res['data']))['user']['auth_token']
self.def_headers['app-user-token'] = auth_token
self.save_token_cache(auth_token, self.device_id)
def generate_signature(self, timestamp):
key_bytes = self.key.encode('utf-8')
iv_bytes = self.iv.encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
padded_timestamp = pad(timestamp.encode('utf-8'), AES.block_size)
encrypted_bytes = cipher.encrypt(padded_timestamp)
return base64.b64encode(encrypted_bytes).decode('utf-8')
def homeContent(self, filter):
result = {"class": [], "filters": {}}
for item in self.init_data.get('type_list', []):
if item['type_name'] not in {'全部', 'QQ', 'juo.one'} and '企鹅群' not in item['type_name']:
result['class'].append({"type_id": item['type_id'], "type_name": item['type_name']})
filter_items = [{"key": 'by' if ft['name'] == 'sort' else ft['name'], "name": {'class': '类型', 'area': '地区', 'lang': '语言', 'year': '年份', 'sort': '排序'}.get(ft['name'], ft['name']), "value": [{"n": v, "v": v} for v in ft['list']]} for ft in item.get('filter_type_list', []) if ft.get('list')]
if filter_items: result["filters"][str(item['type_id'])] = filter_items
return result
def homeVideoContent(self):
return {'list': self.arr2vods([vid for item in self.init_data.get('type_list', []) for vid in item.get('recommend_list', [])])}
def categoryContent(self, cid, pg, filter, ext):
cate_url = f'{self.xurl}typeFilterVodList' if self.is_api3 else f'{self.xurl}.index/typeFilterVodList'
res = self.post(cate_url, headers=self.get_headers(), data={'area': ext.get('area', '全部'), 'year': ext.get('year', '全部'), 'type_id': cid, 'page': str(pg), 'sort': ext.get('sort', '最新'), 'lang': ext.get('lang', '全部'), 'class': ext.get('class', '全部')}, verify=False).json()
return {'list': self.arr2vods(json.loads(self.decrypt(res['data']))['recommend_list']), 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999}
def _fetch_cate_page(self, page):
try:
cate_url = f'{self.xurl}typeFilterVodList' if self.is_api3 else f'{self.xurl}.index/typeFilterVodList'
res = self.post(cate_url, headers=self.get_headers(), data={'area':'全部','year':'全部','type_id':'0','page':str(page),'sort':'最新','lang':'全部','class':'全部'}, verify=False).json()
return self.arr2vods(json.loads(self.decrypt(res['data']))['recommend_list'])
except: return []
def custom_search(self, key):
vods, c_page, stop = [], 1, False
while not stop and c_page <= 100:
batch_end = min(c_page+4, 100)
with ThreadPoolExecutor(max_workers=5) as exe:
tasks = [exe.submit(self._fetch_cate_page, p) for p in range(c_page, batch_end+1)]
for fut in as_completed(tasks):
for v in fut.result():
if key in v['vod_name'] and v['vod_id'] not in [x['vod_id'] for x in vods]:
vods.append(v)
stop = True
exe.shutdown(wait=False)
break
if stop: break
c_page = batch_end + 1
return vods
def searchContent(self, key, quick, pg="1"):
if self.search_mode:
return {'list': self.custom_search(key), 'page': int(pg), 'pagecount': 100, 'limit': 90, 'total': len(self.custom_search(key))}
if 'xiaohys.com' in self.xurl:
data = self.fetch(f'{self.xurl.split("api.php")[0]}index.php/ajax/suggest?mid=1&wd={key}', timeout=self.search_timeout, verify=False).json()
return {'list': [{"vod_id": i['id'], "vod_name": i['name'], "vod_pic": i.get('pic')} for i in data['list']], 'page': pg, 'pagecount': 999, 'limit': 30, 'total': 9999}
payload = {'keywords': key, 'type_id': "0", 'page': str(pg)}
if self.search_verify:
if self.verify_code and len(self.verify_code) == 4 and self.verify_code.isdigit():
verifi = {'code': self.verify_code, 'uuid': str(uuid.uuid4())}
else:
verifi = self.verification()
if not verifi: return {'list': [], 'page': pg, 'pagecount': 0, 'limit': 30, 'total': 0}
payload.update({'code': verifi['code'], 'key': verifi['uuid']})
search_url = f'{self.xurl}{self.search_index_suffix}' if self.is_api3 else f'{self.xurl}.index/{self.search_index_suffix}'
res = self.post(search_url, data=payload, headers=self.get_headers(), verify=False, timeout=self.search_timeout).json()
if not res.get('data'): return {'list': [], 'msg': res.get('msg'), 'page': pg, 'pagecount': 0, 'limit': 30, 'total': 0}
return {'list': self.arr2vods(json.loads(self.decrypt(res['data']))['search_list']), 'page': pg, 'pagecount': 999, 'limit': 30, 'total': 9999}
def detailContent(self, ids):
did = ids[0]
payload = {'vod_id': did}
api_endpoints = ['vodDetail2', 'vodDetail3'] if 'qijiappapi' in self.xurl else ['vodDetail']
self.login()
for endpoint in api_endpoints:
detail_url = f'{self.xurl}{endpoint}' if self.is_api3 else f'{self.xurl}.index/{endpoint}'
resp = self.post(detail_url, headers=self.get_headers(), data=payload, verify=False)
if resp.status_code == 200:
resp_data = resp.json()
if any(msg in resp_data.get('msg', '') for msg in ['到期', '请先注册登录', '积分', '会员', '登录', '注册']) or resp_data.get('code') == 0:
if self.auto_vip_enabled and not self.vip_purchased and self.retry_count < 1 and not self.auto_vip_triggered:
self.silent_register_and_buy_vip()
self.vip_purchased = True
self.retry_count += 1
return self.detailContent(ids)
return None
kjson = json.loads(self.decrypt(resp_data['data']))
filter_keywords = {'防走丢', '', '防失群', '官网'} | set(self.line_block)
valid_lines = self.fuzzy_sort_lines([{'player_show': line['player_info']['show'], 'parse': line['player_info']['parse'], 'parse_type': line['player_info']['parse_type'], 'player_parse_type': line['player_info']['player_parse_type'], 'urls': line['urls']} for line in kjson['vod_play_list'] if not any(kw in line['player_info']['show'] for kw in filter_keywords)])
play_form, play_url, name_count = [], [], {}
for line in valid_lines:
show_name = line['player_show']
name_count[show_name] = name_count.get(show_name, 0) + 1
if name_count[show_name] > 1: show_name += str(name_count[show_name])
play_form.append(show_name)
play_url.append('#'.join([f"{vod['name']}${line['parse']},{vod['url']},token+{vod['token']},{line['player_parse_type']},{line['parse_type']}" for vod in line['urls']]))
vod = kjson['vod']
return {'list': [{"vod_id": did, "vod_name": vod['vod_name'], "vod_actor": vod['vod_actor'].replace('演员', ''), "vod_director": vod.get('vod_director', '').replace('导演', ''), "vod_content": vod['vod_content'], "vod_remarks": vod['vod_remarks'], "vod_year": vod['vod_year'], "vod_area": vod['vod_area'], "vod_play_from": '$$$'.join(play_form), "vod_play_url": '$$$'.join(play_url)}]}
return None
def playerContent(self, flag, vid, vip_Flags):
uid, raw_url, token, player_parse_type, parse_type = vid.split(',', 4)
token = token.replace('token+', '')
default_header = {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}
if parse_type == '0': return {"parse": 0, "url": raw_url, "header": default_header}
elif parse_type == '2': return {"parse": 1, "url": f'{uid}{raw_url}', "header": default_header}
elif player_parse_type == '2':
try: url = self.fetch(f'{uid}{raw_url}', headers=self.get_headers(1), verify=False).json().get('url', '')
except: url = ''
return {"parse": 0, "url": url, "header": default_header}
try:
parse_url = f'{self.xurl}vodParse' if self.is_api3 else f'{self.xurl}.index/vodParse'
resp = self.post(parse_url, headers=self.get_headers(), data={'parse_api': uid, 'url': self.encrypt(raw_url), 'player_parse_type': player_parse_type, 'token': token}, verify=False).json()
url = json.loads(json.loads(self.decrypt(resp['data']))['json']).get('url', '')
except: url = ''
return {"parse": 0, "playUrl": '', "url": url, "header": default_header}
def _is_captcha_error(self, response_msg):
return any(kw in response_msg for kw in ["验证码", "captcha", "code", "验证", "校验"])
def _silent_register_core(self):
try:
device_id = self.device_id or ''.join(random.choices('0123456789abcdef', k=33))
username = ''.join(random.choices('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', k=10))
password = ''.join(random.choices('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', k=10))
timestamp = str(int(time.time()))
verifi = None
if self.auto_vip == 2:
for _ in range(2):
verifi = self.verification()
if verifi: break
time.sleep(0.5)
if not verifi: return None, None
code = verifi['code'] if (self.auto_vip == 2 and verifi) else ""
key = verifi['uuid'] if (self.auto_vip == 2 and verifi) else str(uuid.uuid4())
register_data = json.dumps({"password": password, "code": code, "device_id": device_id, "user_name": username, "invite_code": "", "key": key, "is_emulator": 0}, separators=(',', ':'))
headers = self.get_headers().copy()
headers.update({"app-version-code": self.version or "120", "app-ui-mode": "light", "app-user-device-id": device_id, "app-api-verify-time": timestamp, "app-api-verify-sign": self.generate_signature(timestamp), "Content-Type": "application/x-www-form-urlencoded", "Connection": "Keep-Alive", "Accept-Encoding": "gzip"})
reg_url = f'{self.xurl}appRegisterV133' if self.is_api3 else f'{self.xurl}.index/appRegisterV133'
resp = self.post(reg_url, headers=headers, data={"data": self.encrypt(register_data)}, verify=False, timeout=10)
if resp.status_code == 200:
resp_json = resp.json()
if resp_json.get("code") != 1 and self._is_captcha_error(resp_json.get("msg", "")) and self.auto_vip == 2:
verifi = self.verification()
if verifi:
code = verifi['code']
key = verifi['uuid']
register_data = json.dumps({"password": password, "code": code, "device_id": device_id, "user_name": username, "invite_code": "", "key": key, "is_emulator": 0}, separators=(',', ':'))
resp = self.post(reg_url, headers=headers, data={"data": self.encrypt(register_data)}, verify=False, timeout=10)
resp_json = resp.json()
if resp_json.get("code") == 1:
token = json.loads(self.decrypt(resp_json["data"]))['user'].get('auth_token')
if token: return token, device_id
except: pass
return None, None
def silent_register_and_buy_vip(self):
max_retries = 3
for _ in range(max_retries):
token, device_id = self._silent_register_core()
if token and device_id:
self.def_headers.update({'app-user-token': token, 'app-user-device-id': device_id})
self.device_id = device_id
self.save_token_cache(token, device_id)
self.silent_buy_vip(token, device_id)
self.auto_vip_triggered = True
return True
if self.auto_vip == 2: time.sleep(1)
return False
def silent_buy_vip(self, token, device_id):
try:
timestamp = str(int(time.time()))
headers = self.get_headers().copy()
headers.update({"app-version-code": self.version or "120", "app-ui-mode": "light", "app-user-device-id": device_id, "app-user-token": token, "app-api-verify-time": timestamp, "app-api-verify-sign": self.generate_signature(timestamp), "Content-Type": "application/x-www-form-urlencoded", "Connection": "Keep-Alive", "Accept-Encoding": "gzip"})
buy_vip_url = f'{self.xurl}userBuyVip' if self.is_api3 else f'{self.xurl}.index/userBuyVip'
resp = self.post(buy_vip_url, headers=headers, data={"index": "0"}, verify=False, timeout=10)
return resp.status_code == 200 and resp.json().get("code") == 1
except: return True
def arr2vods(self, arr):
return [{'vod_id': item['vod_id'], 'vod_name': item['vod_name'], 'vod_pic': item.get('vod_pic'), 'vod_remarks': item.get('vod_remarks')} for item in arr if isinstance(arr, list) and item.get('vod_id')]
def decrypt(self, encrypted_data_b64):
cipher = AES.new(self.key.encode('utf-8'), AES.MODE_CBC, self.iv.encode('utf-8'))
return unpad(cipher.decrypt(base64.b64decode(encrypted_data_b64)), AES.block_size).decode('utf-8')
def encrypt(self, sencrypted_data):
cipher = AES.new(self.key.encode('utf-8'), AES.MODE_CBC, self.iv.encode('utf-8'))
return base64.b64encode(cipher.encrypt(pad(sencrypted_data.encode('utf-8'), AES.block_size))).decode('utf-8')
def verification(self):
try:
uuid_str = str(uuid.uuid4())
verify_url = f'{self.xurl}verify/create?key={uuid_str}' if self.is_api3 else f'{self.xurl}.verify/create?key={uuid_str}'
img_data = self.fetch(verify_url, headers=self.get_headers(), verify=False).content
if not img_data: return None
code = self.ocr(base64.b64encode(img_data).decode('utf-8'))
if not code: return None
replacements = {'y':'9','':'0','q':'0','u':'0','o':'0','>':'1','d':'0','b':'8','':'2','D':'0','':'5'}
if len(code) == 3: code = code.replace('566', '5066').replace('066', '1666')
code = ''.join(replacements.get(c, c) for c in code)
return {'uuid': uuid_str, 'code': code} if len(code) == 4 and code.isdigit() else None
except: return None
def ocr(self, base64img):
try: return self.post('https://api.nn.ci/ocr/b64/text', data=base64img, headers=self.get_headers(1), verify=False).text.strip() or None
except: return None
def localProxy(self, params):
proxy_map = {"m3u8": self.proxyM3u8, "media": self.proxyMedia, "ts": self.proxyTs}
return proxy_map.get(params.get('type'))(params) if proxy_map.get(params.get('type')) else None
def getName(self): pass
def isVideoFormat(self, url): pass
def manualVideoCheck(self): pass
-1068
Melihat File
@@ -1,1068 +0,0 @@
import { Crypto, _ } from 'assets://js/lib/cat.js'
let host = '';
let header = {
'User-Agent': 'okhttp/3.12.11'
};
let siteKey = '';
let siteType = '';
let siteJx = '';
const urlPattern1 = /api\.php\/.*?\/vod/;
const urlPattern2 = /api\.php\/.+?\.vod/;
const parsePattern = /\/.+\\?.+=/;
const parsePattern1 = /.*(url|v|vid|php\?id)=/;
const parsePattern2 = /https?:\/\/[^\/]*/;
const htmlVideoKeyMatch = [
/player=new/,
/<div id="video"/,
/<div id="[^"]*?player"/,
/\/\/视频链接/,
/HlsJsPlayer\(/,
/<iframe[\s\S]*?src="[^"]+?"/,
/<video[\s\S]*?src="[^"]+?"/,
];
const parseUrlMap = new Map();
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
host = cfg.ext;
if (cfg.ext.hasOwnProperty('host')) {
host = cfg.ext.host;
siteJx = cfg.ext;
}
};
async function request(reqUrl, ua, timeout = 60000) {
let res = await req(reqUrl, {
method: 'get',
headers: ua ? ua : {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'},
timeout: timeout,
});
return res.content;
}
async function home(filter) {
try {
// 苹果CMS V10模式检测
if (host.includes('/vod') || host.includes('/provide/vod')) {
const url = host;
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const result = { class: [] };
if (obj.class && Array.isArray(obj.class)) {
for (const item of obj.class) {
const typeName = item.type_name;
if (isBan(typeName)) continue;
result.class.push({
type_id: item.type_id,
type_name: typeName
});
}
}
return JSON.stringify(result);
} else {
// 原有AppYsV2模式
let url = getCateUrl(host);
let jsonArray = null;
if (url) {
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
if (obj.hasOwnProperty("class") && Array.isArray(obj.class)) {
jsonArray = obj.class;
} else if (obj.hasOwnProperty("list") && Array.isArray(obj.list)) {
jsonArray = obj.list;
} else if (obj.hasOwnProperty("data") && obj.data.hasOwnProperty("list") && Array.isArray(obj.data.list)) {
jsonArray = obj.data.list;
} else if (obj.hasOwnProperty("data") && Array.isArray(obj.data)) {
jsonArray = obj.data;
}
} else {
const filterStr = getFilterTypes(url, null);
const classes = filterStr.split("\n")[0].split("+");
jsonArray = [];
for (let i = 1; i < classes.length; i++) {
const kv = classes[i].trim().split("=");
if (kv.length < 2) continue;
const newCls = {
type_name: kv[0].trim(),
type_id: kv[1].trim(),
};
jsonArray.push(newCls);
}
}
const result = { class: [] };
if (jsonArray != null) {
for (let i = 0; i < jsonArray.length; i++) {
const jObj = jsonArray[i];
const typeName = jObj.type_name;
if (isBan(typeName)) continue;
const typeId = jObj.type_id;
const newCls = {
type_id: typeId,
type_name: typeName,
};
const typeExtend = jObj.type_extend;
if (filter) {
const filterStr = getFilterTypes(url, typeExtend);
const filters = filterStr.split("\n");
const filterArr = [];
for (let k = (url) ? 1 : 0; k < filters.length; k++) {
const l = filters[k].trim();
if (!l) continue;
const oneLine = l.split("+");
let type = oneLine[0].trim();
let typeN = type;
if (type.includes("筛选")) {
type = type.replace(/筛选/g, "");
if (type === "class") typeN = "类型";
else if (type === "area") typeN = "地区";
else if (type === "lang") typeN = "语言";
else if (type === "year") typeN = "年份";
}
const jOne = {
key: type,
name: typeN,
value: [],
};
for (let j = 1; j < oneLine.length; j++) {
const kv = oneLine[j].trim();
const sp = kv.indexOf("=");
if (sp === -1) {
if (isBan(kv)) continue;
jOne.value.push({ n: kv, v: kv });
} else {
const n = kv.substring(0, sp);
if (isBan(n)) continue;
jOne.value.push({
n: n.trim(),
v: kv.substring(sp + 1).trim(),
});
}
}
filterArr.push(jOne);
}
if (!result.hasOwnProperty("filters")) {
result.filters = {};
}
result.filters[typeId] = filterArr;
}
result.class.push(newCls);
}
}
return JSON.stringify(result);
}
} catch (e) {
SpiderDebug.log("分类接口错误:" + e);
}
return JSON.stringify({ class: [] });
}
async function homeVod() {
try {
// 苹果CMS V10模式检测
if (host.includes('/vod') || host.includes('/provide/vod')) {
const url = `${host}?ac=videolist&t=1&pg=1`;
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const videos = [];
if (obj.list && Array.isArray(obj.list)) {
for (const item of obj.list) {
videos.push({
vod_id: item.vod_id,
vod_name: (item.vod_name || "").replace(/奇迹云/g, ''),
vod_pic: item.vod_pic || "",
vod_remarks: (item.vod_remarks || "").replace(/奇迹云/g, '')
});
}
}
return JSON.stringify({ list: videos });
} else {
// 原有AppYsV2模式
const apiUrl = host;
let url = getRecommendUrl(apiUrl);
let isTV = false;
if (!url) {
url = getCateFilterUrlPrefix(apiUrl) + "movie&page=1&area=&type=&start=";
isTV = true;
}
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const videos = [];
if (isTV) {
const jsonArray = obj.data;
for (let i = 0; i < jsonArray.length; i++) {
const vObj = jsonArray[i];
const v = {
vod_id: vObj.nextlink,
vod_name: (vObj.title || "").replace(/奇迹云/g, ''),
vod_pic: vObj.pic,
vod_remarks: (vObj.state || "").replace(/奇迹云/g, ''),
};
videos.push(v);
}
} else {
const arrays = [];
findJsonArray(obj, "vlist", arrays);
if (arrays.length === 0) {
findJsonArray(obj, "vod_list", arrays);
}
const ids = [];
for (const jsonArray of arrays) {
for (let i = 0; i < jsonArray.length; i++) {
const vObj = jsonArray[i];
const vid = vObj.vod_id;
if (ids.includes(vid)) continue;
ids.push(vid);
const v = {
vod_id: vid,
vod_name: (vObj.vod_name || "").replace(/奇迹云/g, ''),
vod_pic: vObj.vod_pic,
vod_remarks: (vObj.vod_remarks || "").replace(/奇迹云/g, ''),
};
videos.push(v);
}
}
}
const result = {
list: videos,
};
return JSON.stringify(result);
}
} catch (e) {
SpiderDebug.log(e);
}
return "";
}
async function category(tid, pg, filter, extend) {
try {
// 苹果CMS V10模式检测
if (host.includes('/vod') || host.includes('/provide/vod')) {
const url = `${host}?ac=videolist&t=${tid}&pg=${pg}`;
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const videos = [];
if (obj.list && Array.isArray(obj.list)) {
for (const item of obj.list) {
videos.push({
vod_id: item.vod_id,
vod_name: (item.vod_name || "").replace(/奇迹云/g, ''),
vod_pic: item.vod_pic || "",
vod_remarks: (item.vod_remarks || "").replace(/奇迹云/g, '')
});
}
}
return JSON.stringify({
page: pg,
pagecount: obj.pagecount || 1,
limit: obj.limit || 20,
total: obj.total || 0,
list: videos
});
} else {
// 原有AppYsV2模式
const apiUrl = host;
let url = getCateFilterUrlPrefix(apiUrl) + tid + getCateFilterUrlSuffix(apiUrl);
url = url.replace(/#PN#/g, pg);
url = url.replace(/筛选class/g, extend?.class ?? "");
url = url.replace(/筛选area/g, extend?.area ?? "");
url = url.replace(/筛选lang/g, extend?.lang ?? "");
url = url.replace(/筛选year/g, extend?.year ?? "");
url = url.replace(/排序/g, extend?.排序 ?? "");
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
let totalPg = Infinity;
try {
if (obj.totalpage !== undefined && typeof obj.totalpage === "number") {
totalPg = obj.totalpage;
} else if (
obj.pagecount !== undefined &&
typeof obj.pagecount === "number"
) {
totalPg = obj.pagecount;
} else if (
obj.data !== undefined &&
typeof obj.data === "object" &&
obj.data.total !== undefined &&
typeof obj.data.total === "number" &&
obj.data.limit !== undefined &&
typeof obj.data.limit === "number"
) {
const limit = obj.data.limit;
const total = obj.data.total;
totalPg = total % limit === 0 ? total / limit : Math.floor(total / limit) + 1;
}
} catch (e) {
SpiderDebug.log(e);
}
const jsonArray =
obj.list !== undefined
? obj.list
: obj.data !== undefined && obj.data.list !== undefined
? obj.data.list
: obj.data;
const videos = [];
if (jsonArray !== undefined) {
for (let i = 0; i < jsonArray.length; i++) {
const vObj = jsonArray[i];
const v = {
vod_id: vObj.vod_id !== undefined ? vObj.vod_id : vObj.nextlink,
vod_name: ((vObj.vod_name !== undefined ? vObj.vod_name : vObj.title) || "").replace(/奇迹云/g, ''),
vod_pic: vObj.vod_pic !== undefined ? vObj.vod_pic : vObj.pic,
vod_remarks: ((vObj.vod_remarks !== undefined ? vObj.vod_remarks : vObj.state) || "").replace(/奇迹云/g, ''),
};
videos.push(v);
}
}
const result = {
page: pg,
pagecount: totalPg,
limit: 90,
total: Infinity,
list: videos,
};
return JSON.stringify(result);
}
} catch (e) {
SpiderDebug.log(e);
}
return "";
}
// 辅助函数:只替换文字,不改变分隔符和结构
function replacePlayUrlText(playUrl) {
if (!playUrl) return playUrl;
// 使用正则匹配 $$$ 或 # 作为分隔符,但保留原始分隔符不变
// 匹配模式:任意内容后跟 $$$ 或 #,或者末尾
let result = '';
let i = 0;
while (i < playUrl.length) {
// 查找 $$$ 或 # 的位置
let found = -1;
let sep = '';
let dollarPos = playUrl.indexOf('$$$', i);
let hashPos = playUrl.indexOf('#', i);
if (dollarPos !== -1 && (hashPos === -1 || dollarPos < hashPos)) {
found = dollarPos;
sep = '$$$';
} else if (hashPos !== -1) {
found = hashPos;
sep = '#';
}
if (found !== -1) {
let segment = playUrl.substring(i, found);
// 替换 segment 中 $ 前面的集数名称里的文字
let dollarInSegment = segment.indexOf('$');
if (dollarInSegment > 0) {
let episodeName = segment.substring(0, dollarInSegment);
let urlPart = segment.substring(dollarInSegment);
episodeName = episodeName.replace(/奇迹云/g, '');
result += episodeName + urlPart;
} else {
result += segment.replace(/奇迹云/g, '');
}
result += sep;
i = found + sep.length;
} else {
// 最后一段
let segment = playUrl.substring(i);
let dollarInSegment = segment.indexOf('$');
if (dollarInSegment > 0) {
let episodeName = segment.substring(0, dollarInSegment);
let urlPart = segment.substring(dollarInSegment);
episodeName = episodeName.replace(/奇迹云/g, '');
result += episodeName + urlPart;
} else {
result += segment.replace(/奇迹云/g, '');
}
break;
}
}
return result;
}
async function detail(ids) {
try {
// 苹果CMS V10模式检测
if (host.includes('/vod') || host.includes('/provide/vod')) {
const url = `${host}?ac=detail&ids=${ids}`;
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const result = { list: [] };
const vod = {};
const data = obj.list && obj.list[0] ? obj.list[0] : {};
vod.vod_id = data.vod_id || ids;
vod.vod_name = (data.vod_name || "").replace(/奇迹云/g, '');
vod.vod_pic = data.vod_pic || "";
vod.type_name = (data.type_name || "").replace(/奇迹云/g, '');
vod.vod_year = (data.vod_year || "").replace(/奇迹云/g, '');
vod.vod_area = (data.vod_area || "").replace(/奇迹云/g, '');
vod.vod_remarks = (data.vod_remarks || "").replace(/奇迹云/g, '');
vod.vod_actor = (data.vod_actor || "").replace(/奇迹云/g, '');
vod.vod_director = (data.vod_director || "").replace(/奇迹云/g, '');
vod.vod_content = (data.vod_content || "").replace(/奇迹云/g, '');
// 处理线路名称
let playFrom = data.vod_play_from || "";
if (playFrom) {
let lines = playFrom.split('$$$');
let newLines = [];
for (let line of lines) {
if (line && line.toLowerCase().includes('qijiyun4k')) {
newLines.push('狮子心4k专属🦁');
} else {
newLines.push((line || "").replace(/奇迹云/g, ''));
}
}
vod.vod_play_from = newLines.join('$$$');
} else {
vod.vod_play_from = "";
}
// 处理选集:只替换文字,保留原始分隔符和结构
vod.vod_play_url = replacePlayUrlText(data.vod_play_url || "");
result.list.push(vod);
return JSON.stringify(result);
} else {
// 原有AppYsV2模式
const apiUrl = host;
const url = getPlayUrlPrefix(apiUrl) + ids;
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const result = {
list: [],
};
const vod = {};
genPlayList(apiUrl, obj, json, vod, ids);
// 替换详情中的所有文字
if (vod.vod_name) vod.vod_name = vod.vod_name.replace(/奇迹云/g, '');
if (vod.type_name) vod.type_name = vod.type_name.replace(/奇迹云/g, '');
if (vod.vod_year) vod.vod_year = vod.vod_year.replace(/奇迹云/g, '');
if (vod.vod_area) vod.vod_area = vod.vod_area.replace(/奇迹云/g, '');
if (vod.vod_remarks) vod.vod_remarks = vod.vod_remarks.replace(/奇迹云/g, '');
if (vod.vod_actor) vod.vod_actor = vod.vod_actor.replace(/奇迹云/g, '');
if (vod.vod_director) vod.vod_director = vod.vod_director.replace(/奇迹云/g, '');
if (vod.vod_content) vod.vod_content = vod.vod_content.replace(/奇迹云/g, '');
// 替换线路名称
if (vod.vod_play_from) {
let lines = vod.vod_play_from.split('$$$');
let newLines = [];
for (let line of lines) {
if (line && line.toLowerCase().includes('qijiyun4k')) {
newLines.push('狮子心4k专属🦁');
} else {
newLines.push((line || "").replace(/奇迹云/g, ''));
}
}
vod.vod_play_from = newLines.join('$$$');
}
// 处理选集:只替换文字,保留原始分隔符和结构
vod.vod_play_url = replacePlayUrlText(vod.vod_play_url || "");
result.list.push(vod);
return JSON.stringify(result);
}
} catch (e) {
SpiderDebug.log(e);
}
return "";
}
async function play(flag, id, vipFlags) {
try {
let parseUrls = siteJx[flag];
if (!parseUrls) {
if (siteJx.hasOwnProperty('*')) {
parseUrls = siteJx['*'];
} else {
parseUrls = [];
}
}
if (parseUrls.length > 0) {
const result = await getFinalVideo(flag, parseUrls, id);
if (result !== null) {
return JSON.stringify(result);
}
}
if (isVideoFormat(id)) {
const result = {
parse: 0,
playUrl: "",
url: id
};
return JSON.stringify(result);
} else {
const result = {
parse: 1,
jx: "1",
url: id
};
return JSON.stringify(result);
}
} catch (e) {
SpiderDebug.log(e);
}
return "";
}
async function search(key, quick) {
try {
// 苹果CMS V10模式检测
if (host.includes('/vod') || host.includes('/provide/vod')) {
const url = `${host}?ac=videolist&wd=${encodeURIComponent(key)}&pg=1`;
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
const videos = [];
if (obj.list && Array.isArray(obj.list)) {
for (const item of obj.list) {
videos.push({
vod_id: item.vod_id,
vod_name: (item.vod_name || "").replace(/奇迹云/g, ''),
vod_pic: item.vod_pic || "",
vod_remarks: (item.vod_remarks || "").replace(/奇迹云/g, '')
});
}
}
return JSON.stringify({ list: videos });
} else {
// 原有AppYsV2模式
const apiUrl = host;
const url = getSearchUrl(apiUrl, encodeURIComponent(key));
const json = await request(url, getHeaders(url));
const obj = JSON.parse(json);
let jsonArray = null;
const videos = [];
if (obj.list instanceof Array) {
jsonArray = obj.list;
} else if (obj.data instanceof Object && obj.data.list instanceof Array) {
jsonArray = obj.data.list;
} else if (obj.data instanceof Array) {
jsonArray = obj.data;
}
if (jsonArray !== null) {
for (const vObj of jsonArray) {
if (vObj.vod_id) {
const v = {
vod_id: vObj.vod_id,
vod_name: (vObj.vod_name || "").replace(/奇迹云/g, ''),
vod_pic: vObj.vod_pic,
vod_remarks: (vObj.vod_remarks || "").replace(/奇迹云/g, '')
};
videos.push(v);
} else {
const v = {
vod_id: vObj.nextlink,
vod_name: (vObj.title || "").replace(/奇迹云/g, ''),
vod_pic: vObj.pic,
vod_remarks: (vObj.state || "").replace(/奇迹云/g, '')
};
videos.push(v);
}
}
}
const result = { list: videos };
return JSON.stringify(result);
}
} catch (error) {
SpiderDebug.log(error);
}
return "";
}
// 辅助函数
async function getFinalVideo(flag, parseUrls, url) {
let htmlPlayUrl = "";
for (const parseUrl of parseUrls) {
if (parseUrl === "" || parseUrl === "null") {
continue;
}
const playUrl = parseUrl + url;
const content = await request(playUrl, null, 10000);
let tryJson = null;
try {
tryJson = jsonParse(url, content);
} catch (error) { }
if (tryJson !== null && tryJson.hasOwnProperty("url") && tryJson.hasOwnProperty("header")) {
tryJson.header = JSON.stringify(tryJson.header);
return tryJson;
}
if (content.includes("<html")) {
let sniffer = false;
for (const p of htmlVideoKeyMatch) {
if (p.test(content)) {
sniffer = true;
break;
}
}
if (sniffer) {
htmlPlayUrl = parseUrl;
}
}
}
if (htmlPlayUrl !== "") {
const result = {
parse: 0,
playUrl: "",
url: url
};
return JSON.stringify(result);
}
return null;
}
function genPlayList(URL, object, json, vod, vid) {
const playUrls = [];
const playFlags = [];
// 苹果CMS V10模式
if (URL.includes('/vod') || URL.includes('/provide/vod')) {
const data = object.list && object.list[0] ? object.list[0] : {};
vod.vod_id = data.vod_id || vid;
vod.vod_name = data.vod_name || "";
vod.vod_pic = data.vod_pic || "";
vod.type_name = data.type_name || "";
vod.vod_year = data.vod_year || "";
vod.vod_area = data.vod_area || "";
vod.vod_remarks = data.vod_remarks || "";
vod.vod_actor = data.vod_actor || "";
vod.vod_director = data.vod_director || "";
vod.vod_content = data.vod_content || "";
vod.vod_play_from = data.vod_play_from || "";
vod.vod_play_url = data.vod_play_url || "";
return;
}
// AppYsV2模式
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
const data = object.data || {};
vod.vod_id = data.vod_id || vid;
vod.vod_name = data.vod_name || "";
vod.vod_pic = data.vod_pic || "";
vod.type_name = data.vod_class || "";
vod.vod_year = data.vod_year || "";
vod.vod_area = data.vod_area || "";
vod.vod_remarks = data.vod_remarks || "";
vod.vod_actor = data.vod_actor || "";
vod.vod_director = data.vod_director || "";
vod.vod_content = data.vod_content || "";
// 处理播放源
if (data.vod_url_with_player && Array.isArray(data.vod_url_with_player)) {
for (const from of data.vod_url_with_player) {
let flag = from.code?.trim() || from.name?.trim() || "";
if (!flag) continue;
playFlags.push(flag);
playUrls.push(from.url || "");
// 处理解析地址
if (from.parse_api) {
const parseUrls = parseUrlMap.get(flag) || [];
if (!parseUrls.includes(from.parse_api)) {
parseUrls.push(from.parse_api);
}
parseUrlMap.set(flag, parseUrls);
}
}
}
} else if (URL.includes(".vod")) {
const data = object.data || {};
vod.vod_id = data.vod_id || vid;
vod.vod_name = data.vod_name || "";
vod.vod_pic = data.vod_pic || "";
vod.type_name = data.vod_class || "";
vod.vod_year = data.vod_year || "";
vod.vod_area = data.vod_area || "";
vod.vod_remarks = data.vod_remarks || "";
vod.vod_actor = data.vod_actor || "";
vod.vod_director = data.vod_director || "";
vod.vod_content = data.vod_content || "";
if (data.vod_play_list && Array.isArray(data.vod_play_list)) {
for (const from of data.vod_play_list) {
let flag = from.player_info?.from?.trim() || from.player_info?.show?.trim() || "";
if (!flag) continue;
playFlags.push(flag);
playUrls.push(from.url || "");
// 处理解析地址
try {
const parseUrls = parseUrlMap.get(flag) || [];
if (from.player_info?.parse) {
const parse1 = from.player_info.parse.split(",");
parse1.forEach(purl => {
if (purl && !parseUrls.includes(purl)) {
parseUrls.push(purl);
}
});
}
if (from.player_info?.parse2) {
const parse2 = from.player_info.parse2.split(",");
parse2.forEach(purl => {
if (purl && !parseUrls.includes(purl)) {
parseUrls.push(purl);
}
});
}
parseUrlMap.set(flag, parseUrls);
} catch (e) {
SpiderDebug.log(e);
}
}
}
} else if (urlPattern1.test(URL)) {
const data = object.list && object.list[0] ? object.list[0] : {};
vod.vod_id = data.vod_id || vid;
vod.vod_name = data.vod_name || "";
vod.vod_pic = data.vod_pic || "";
vod.type_name = data.type_name || "";
vod.vod_year = data.vod_year || "";
vod.vod_area = data.vod_area || "";
vod.vod_remarks = data.vod_remarks || "";
vod.vod_actor = data.vod_actor || "";
vod.vod_director = data.vod_director || "";
vod.vod_content = data.vod_content || "";
vod.vod_play_from = data.vod_play_from || "";
vod.vod_play_url = data.vod_play_url || "";
}
// 合并播放源
if (playFlags.length > 0 && playUrls.length > 0) {
vod.vod_play_from = playFlags.join("$$$");
vod.vod_play_url = playUrls.join("$$$");
}
}
function jsonParse(input, json) {
try {
let jsonPlayData = JSON.parse(json);
if (jsonPlayData.hasOwnProperty("data") && typeof jsonPlayData.data === "object" && !jsonPlayData.hasOwnProperty("url")) {
jsonPlayData = jsonPlayData.data;
}
let url = jsonPlayData.url;
if (url.startsWith("//")) {
url = "https:" + url;
}
if (!url.trim().startsWith("http")) {
return null;
}
if (url === input) {
if (isVip(url) || !isVideoFormat(url)) {
return null;
}
}
if (isBlackVodUrl(input, url)) {
return null;
}
let headers = {};
if (jsonPlayData.hasOwnProperty("header")) {
headers = jsonPlayData.header;
} else if (jsonPlayData.hasOwnProperty("Header")) {
headers = jsonPlayData.Header;
} else if (jsonPlayData.hasOwnProperty("headers")) {
headers = jsonPlayData.headers;
} else if (jsonPlayData.hasOwnProperty("Headers")) {
headers = jsonPlayData.Headers;
}
let ua = "";
if (jsonPlayData.hasOwnProperty("user-agent")) {
ua = jsonPlayData["user-agent"];
} else if (jsonPlayData.hasOwnProperty("User-Agent")) {
ua = jsonPlayData["User-Agent"];
}
if (ua.trim().length > 0) {
headers["User-Agent"] = " " + ua;
}
let referer = "";
if (jsonPlayData.hasOwnProperty("referer")) {
referer = jsonPlayData.referer;
} else if (jsonPlayData.hasOwnProperty("Referer")) {
referer = jsonPlayData.Referer;
}
if (referer.trim().length > 0) {
headers["Referer"] = " " + referer;
}
headers = fixJsonVodHeader(headers, input, url);
const taskResult = {
header: headers,
url: url,
parse: "0"
};
return taskResult;
} catch (error) {
SpiderDebug.log(error);
}
return null;
}
function isVip(url) {
try {
let isVip = false;
const host = new URL(url).hostname;
const vipWebsites = ["iqiyi.com", "v.qq.com", "youku.com", "le.com", "tudou.com", "mgtv.com", "sohu.com", "acfun.cn", "bilibili.com", "baofeng.com", "pptv.com"];
for (let b = 0; b < vipWebsites.length; b++) {
if (host.includes(vipWebsites[b])) {
if (vipWebsites[b] === "iqiyi.com") {
if (url.includes("iqiyi.com/a_") || url.includes("iqiyi.com/w_") || url.includes("iqiyi.com/v_")) {
isVip = true;
break;
}
} else {
isVip = true;
break;
}
}
}
return isVip;
} catch (e) {
SpiderDebug.log(e);
}
return false;
}
function isBlackVodUrl(input, url) {
return url.includes("973973.xyz") || url.includes(".fit:");
}
function fixJsonVodHeader(headers, input, url) {
if (headers === null) {
headers = {};
}
if (input.includes("www.mgtv.com")) {
headers["Referer"] = " ";
headers["User-Agent"] = " Mozilla/5.0";
} else if (url.includes("titan.mgtv")) {
headers["Referer"] = " ";
headers["User-Agent"] = " Mozilla/5.0";
} else if (input.includes("bilibili")) {
headers["Referer"] = " https://www.bilibili.com/";
headers["User-Agent"] = " " + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
}
return headers;
}
const snifferMatch = /http((?!http).){26,}?\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg)\?.*|http((?!http).){26,}\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg)|http((?!http).){26,}\/m3u8\?pt=m3u8.*|http((?!http).)*?default\.ixigua\.com\/.*|http((?!http).)*?cdn-tos[^\?]*|http((?!http).)*?\/obj\/tos[^\?]*|http.*?\/player\/m3u8play\.php\?url=.*|http.*?\/player\/.*?[pP]lay\.php\?url=.*|http.*?\/playlist\/m3u8\/\?vid=.*|http.*?\.php\?type=m3u8&.*|http.*?\/download.aspx\?.*|http.*?\/api\/up_api.php\?.*|https.*?\.66yk\.cn.*|http((?!http).)*?netease\.com\/file\/.*/;
function isVideoFormat(url) {
if (snifferMatch.test(url)) {
return !url.includes("cdn-tos") || !url.includes(".js");
}
return false;
}
function isVideo(url) {
return !url.includes(".mp4") && !url.includes(".m3u8");
}
function UA(url) {
if (url.includes(".vod")) {
return "okhttp/4.1.0";
}
return "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
}
function getCateUrl(URL) {
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
return URL + "nav?token=";
} else if (URL.includes(".vod")) {
return URL + "/types";
} else {
return "";
}
}
function getPlayUrlPrefix(URL) {
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
return URL + "video_detail?id=";
} else if (URL.includes(".vod")) {
return URL + "/detail?vod_id=";
} else {
return "";
}
}
function getRecommendUrl(URL) {
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
return URL + "index_video?token=";
} else if (URL.includes(".vod")) {
return URL + "/vodPhbAll";
} else {
return "";
}
}
function getFilterTypes(URL, typeExtend) {
let str = "";
if (typeExtend !== null) {
for (let key in typeExtend) {
if (key === "class" || key === "area" || key === "lang" || key === "year") {
try {
str += "筛选" + key + "+全部=+" + typeExtend[key].replace(/,/g, "+") + "\n";
} catch (e) { }
}
}
}
if (URL.includes(".vod")) {
str += "\n" + "排序+全部=+最新=time+最热=hits+评分=score";
} else if (URL.includes("api.php/app") || URL.includes("xgapp")) {
// Do nothing, leave the string as it is.
} else {
str = "分类+全部=+电影=movie+连续剧=tvplay+综艺=tvshow+动漫=comic+4K=movie_4k+体育=tiyu\n筛选class+全部=+喜剧+爱情+恐怖+动作+科幻+剧情+战争+警匪+犯罪+动画+奇幻+武侠+冒险+枪战+恐怖+悬疑+惊悚+经典+青春+文艺+微电影+古装+历史+运动+农村+惊悚+惊悚+伦理+情色+福利+三级+儿童+网络电影\n筛选area+全部=+大陆+香港+台湾+美国+英国+法国+日本+韩国+德国+泰国+印度+西班牙+加拿大+其他\n筛选year+全部=+2025+2024+2023+2022+2021+2020+2019+2018+2017+2016+2015+2014+2013+2012+2011+2010+2009+2008+2007+2006+2005+2004+2003+2002+2001+2000";
}
return str;
}
function getCateFilterUrlSuffix(URL) {
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
return "&class=筛选class&area=筛选area&lang=筛选lang&year=筛选year&limit=18&pg=#PN#";
} else if (URL.includes(".vod")) {
return "&class=筛选class&area=筛选area&lang=筛选lang&year=筛选year&by=排序&limit=18&page=#PN#";
} else {
return "&page=#PN#&area=筛选area&type=筛选class&start=筛选year";
}
}
function getCateFilterUrlPrefix(URL) {
if (URL.includes("api.php/app") || URL.includes("xgapp")) {
return URL + "video?tid=";
} else if (URL.includes(".vod")) {
return URL + "?type=";
} else {
return URL + "?ac=list&class=";
}
}
function isBan(key) {
return key === "伦理" || key === "情色" || key === "福利";
}
function getSearchUrl(URL, KEY) {
if (URL.includes(".vod")) {
return URL + "?wd=" + KEY + "&page=";
} else if (URL.includes("api.php/app") || URL.includes("xgapp")) {
return URL + "search?text=" + KEY + "&pg=";
} else if (urlPattern1.test(URL)) {
return URL + "?ac=list&zm=" + KEY + "&page=";
}
return "";
}
function findJsonArray(obj, match, result) {
Object.keys(obj).forEach((k) => {
try {
const o = obj[k];
if (k === match && Array.isArray(o)) {
result.push(o);
}
if (typeof o === "object" && o !== null) {
if (Array.isArray(o)) {
o.forEach((item) => {
if (typeof item === "object" && item !== null) {
findJsonArray(item, match, result);
}
});
} else {
findJsonArray(o, match, result);
}
}
} catch (e) {
SpiderDebug.log(e);
}
});
}
function jsonArr2Str(array) {
const strings = [];
for (let i = 0; i < array.length; i++) {
try {
strings.push(array[i]);
} catch (e) {
SpiderDebug.log(e);
}
}
return strings.join(",");
}
function getHeaders(URL) {
const headers = {};
headers["User-Agent"] = UA(URL);
return headers;
}
function isJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}
@@ -1,391 +0,0 @@
# coding = utf-8
# !/usr/bin/python
#熊修,可py内部填写,也可以和潇洒appget一样ext下面填写,外部填写会覆盖py内部填写
from Crypto.Cipher import AES
from base.spider import Spider
from Crypto.Util.Padding import pad,unpad
import re,sys,time,uuid,json,base64,urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
sys.path.append('..')
class Spider(Spider):
xurl,key,iv,init_data,search_verify,suggest_search,username,password,device_id,version,get_type,def_headers= '','','','','','','', '', '','', '0',{'User-Agent': 'okhttp/3.14.9'}
def init(self, extend=''):
ext=json.loads(extend.strip())
api = str(ext.get('api', 'getappapi'))
if api == '2' or api == 'qiji':
self.get_type = 'qiji'
api_path = '/api.php/qijiappapi'
elif api == 'flutter':
self.get_type = 'flutter'
api_path = '/api.php/getappapi'
else:
self.get_type = 'get'
api_path = '/api.php/getappapi'
host_source = ''
if 'host' in ext:
host_source = ext['host']
elif 'url' in ext:
host_source = ext['url']
elif 'site' in ext:
host_source = ext['site']
if not host_source:
print("错误: 需要提供host、url或site参数")
return
domain_set = set()
if not re.match(r'^https?://[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?(/)?$', host_source):
try:
host_data = self.fetch(host_source, headers=self.get_headers(1), timeout=10, verify=False).text
domain_set.update([domain.strip() for domain in host_data.split('\n') if domain.strip()])
except Exception as e:
print(f"获取站点文件失败: {e}")
return
else:
domain_set.add(host_source.rstrip('/'))
ua = ext.get('ua')
if ua:
self.def_headers['User-Agent'] = ua
token = ext.get('token')
if token:
self.def_headers['app-user-token'] = token
else:
self.username = ext.get('username')
self.password = ext.get('password')
self.device_id = ext.get('deviceId') or ext.get('devideid') or '1234567890ABCDEF'
self.version = str(ext.get('version', '1.0.0'))
self.key = ext.get('key') or ext.get('datakey') or ext.get('dataKey')
if not self.key:
print("错误: 需要提供加密密钥(key/datakey/dataKey)")
return
self.iv = ext.get('iv') or ext.get('dataiv') or ext.get('dataIv') or self.key
if self.device_id:
self.def_headers['app-user-device-id'] = self.device_id
for i in domain_set:
try:
self.xurl = i + api_path
res = self.fetch(self.xurl + '.index/initV119', headers=self.get_headers(), timeout=(5, 5), verify=False).json()
encrypted_data = res['data']
response = self.decrypt(encrypted_data)
init_data = json.loads(response)
except Exception as e:
print(f"连接失败: {e}")
continue
if init_data:
self.init_data = init_data
self.search_verify = init_data['config'].get('system_search_verify_status', False)
if 'xiaohys.com' in i:
self.suggest_search = '1'
print(f"初始化成功: {i}")
break
def homeContent(self, filter):
kjson = self.init_data
result = {"class": [], "filters": {}}
for i in kjson['type_list']:
if not(i['type_name'] in {'全部', 'QQ', 'juo.one'} or '企鹅群' in i['type_name']):
result['class'].append({"type_id": i['type_id'], "type_name": i['type_name']})
name_mapping = {'class': '类型', 'area': '地区', 'lang': '语言', 'year': '年份', 'sort': '排序'}
filter_items = []
for filter_type in i.get('filter_type_list', []):
filter_name = filter_type.get('name')
values = filter_type.get('list', [])
if not values: continue
value_list = [{"n": value, "v": value} for value in values]
display_name = name_mapping.get(filter_name, filter_name)
key = 'by' if filter_name == 'sort' else filter_name
filter_items.append({ "key": key, "name": display_name, "value": value_list})
type_id = i.get('type_id')
if filter_items:
result["filters"][str(type_id)] = filter_items
return result
def homeVideoContent(self):
videos = []
kjson = self.init_data
for i in kjson['type_list']:
videos.extend(self.arr2vods(i['recommend_list']))
return {'list': videos}
def categoryContent(self, cid, pg, filter, ext):
payload = {
'area': ext.get('area','全部'),
'year': ext.get('year','全部'),
'type_id': cid,
'page': str(pg),
'sort': ext.get('sort','最新'),
'lang': ext.get('lang','全部'),
'class': ext.get('class','全部')
}
res = self.post(f'{self.xurl}.index/typeFilterVodList', headers=self.get_headers(), data=payload, verify=False).json()
encrypted_data = res['data']
kjson = self.decrypt(encrypted_data)
kjson1 = json.loads(kjson)
videos = self.arr2vods(kjson1['recommend_list'])
return {'list': videos, 'page': pg, 'pagecount': 9999, 'limit': 90, 'total': 999999}
def searchContent(self, key, quick, pg="1"):
videos = []
if self.suggest_search == '1':
host = self.xurl.split('api.php')[0]
data = self.fetch(f'{host}index.php/ajax/suggest?mid=1&wd={key}').json()
for i in data['list']:
videos.append({
"vod_id": i['id'],
"vod_name": i['name'],
"vod_pic": i.get('pic')
})
else:
payload = {'keywords': key, 'type_id': "0", 'page': str(pg)}
if self.search_verify:
verifi = self.verification()
if verifi is None:
return {'list':[]}
payload['code'] = verifi['code']
payload['key'] = verifi['uuid']
res = self.post(f'{self.xurl}.index/searchList', data=payload, headers=self.get_headers(), verify=False).json()
if not res.get('data'):
return {'list':[] ,'msg': res.get('msg')}
encrypted_data = res['data']
kjson = self.decrypt(encrypted_data)
kjson1 = json.loads(kjson)
videos.extend(self.arr2vods(kjson1['search_list']))
return {'list': videos, 'page': pg}
def detailContent(self, ids):
payload = {'vod_id': ids[0]}
if 'qijiappapi' in self.xurl:
api_endpoints = ['vodDetail2', 'vodDetail3']
else:
api_endpoints = ['vodDetail']
self.login()
response = {}
for endpoint in api_endpoints:
try:
response = self.post(f'{self.xurl}.index/{endpoint}', headers=self.get_headers(), data=payload, verify=False).json()
except Exception:
continue
if '到期' in response['msg'] or response['code'] == 0:
return None
break
if not response: return None
encrypted_data = response['data']
kjson1 = self.decrypt(encrypted_data)
kjson = json.loads(kjson1)
videos, play_form, play_url = [], [], []
lineid = 1
name_count = {}
for line in kjson['vod_play_list']:
keywords = {'防走丢', '', '防失群', '官网'}
player_show = line['player_info']['show']
if any(keyword in player_show for keyword in keywords):
player_show = f'{lineid}线'
line['player_info']['show'] = player_show
count = name_count.get(player_show, 0) + 1
name_count[player_show] = count
if count > 1:
line['player_info']['show'] = f"{player_show}{count}"
play_form.append(line['player_info']['show'])
parse = line['player_info']['parse']
parse_type = line['player_info']['parse_type']
player_parse_type = line['player_info']['player_parse_type']
kurls = []
for vod in line['urls']:
token = vod['token']
kurls.append(f"{str(vod['name'])}${parse},{vod['url']},{token},{player_parse_type},{parse_type}")
play_url.append('#'.join(kurls))
lineid += 1
play_form = '$$$'.join(play_form)
play_url = '$$$'.join(play_url)
videos.append({
"vod_id": ids[0],
"vod_name": kjson['vod']['vod_name'],
"vod_actor": kjson['vod']['vod_actor'].replace('演员', ''),
"vod_director": kjson['vod'].get('vod_director', '').replace('导演', ''),
"vod_content": kjson['vod']['vod_content'],
"vod_remarks": kjson['vod']['vod_remarks'],
"vod_year": kjson['vod']['vod_year'],
"vod_area": kjson['vod']['vod_area'],
"vod_play_from": play_form,
"vod_play_url": play_url
})
return {'list': videos}
def playerContent(self, flag, vid, vip_flags):
url = ''
uid, raw_url, token, player_parse_type, parse_type = vid.split(',', 4)
if parse_type == '0':
res = {"parse": 0, "url": raw_url, "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
elif parse_type == '2':
res = {"parse": 1, "url": f'{uid}{raw_url}', "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
elif player_parse_type == '2':
try:
response = self.fetch(f'{uid}{raw_url}', headers=self.get_headers(1), verify=False).json()
url = response['url']
except Exception:
pass
res = {"parse": 0, "url": url, "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
else:
id1 = self.encrypt(raw_url)
payload = {
'parse_api': uid,
'url': id1,
'player_parse_type': player_parse_type,
'token': token
}
try:
response = self.post(f"{self.xurl}.index/vodParse", headers=self.get_headers(), data=payload, verify=False).json()
encrypted_data = response['data']
kjson = self.decrypt(encrypted_data)
kjson1 = json.loads(kjson)['json']
kjson2 = json.loads(kjson1)
url = kjson2['url']
except Exception:
pass
res = {"parse": 0, "playUrl": '', "url": url, "header": {'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 14; 23113RK12C Build/SKQ1.231004.001)'}}
return res
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
def get_headers(self,main=0):
get_type = self.get_type
if get_type == 'qiji':
headers = {
'User-Agent': 'okhttp/3.10.0',
'Connection': 'Keep-Alive',
'Accept-Encoding': 'gzip'
}
elif get_type == 'flutter':
main_headers = {
'User-Agent': 'Dart/3.5 (dart:io)',
'Accept-Encoding': 'gzip'
}
if main == 1: return main_headers
headers = {
'User-Agent': '',
'Accept-Encoding': '',
'app-version-code': self.version,
'app-os': 'android',
'app-ui-mode': 'light',
**main_headers
}
else:
timestamp = str(int(time.time()))
main_headers ={
'User-Agent': 'okhttp/3.14.9',
'Accept-Encoding': 'gzip'
}
if main == 1: return main_headers
headers = {
'User-Agent': '',
'Connection': 'Keep-Alive',
'Accept-Encoding': '',
'app-version-code': self.version,
'app-ui-mode': 'light',
'app-user-device-id': self.device_id,
'app-api-verify-time': timestamp,
'app-api-verify-sign': self.encrypt(timestamp),
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
**main_headers
}
return {**headers, **self.def_headers}
def login(self):
if self.username and self.password and self.device_id:
payload = {
'password': self.password,
'code': "",
'device_id': self.device_id,
'user_name': self.username,
'invite_code': "",
'is_emulator': "0"
}
response = self.post(f'{self.xurl}.index/appLogin', data=payload, headers=self.get_headers()).json()
data = self.decrypt(response['data'])
auth_token = json.loads(data)['user']['auth_token']
self.def_headers['app-user-token'] = auth_token
def arr2vods(self, arr):
videos = []
if arr and isinstance(arr, list):
for i in arr:
videos.append({
'vod_id': i['vod_id'],
'vod_name': i['vod_name'],
'vod_pic': i.get('vod_pic'),
'vod_remarks': i.get('vod_remarks')
})
return videos
def decrypt(self, encrypted_data_b64):
key_bytes = self.key.encode('utf-8')
iv_bytes = self.iv.encode('utf-8')
encrypted_data = base64.b64decode(encrypted_data_b64)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
decrypted_padded = cipher.decrypt(encrypted_data)
decrypted = unpad(decrypted_padded, AES.block_size)
return decrypted.decode('utf-8')
def encrypt(self, sencrypted_data):
key_bytes = self.key.encode('utf-8')
iv_bytes = self.iv.encode('utf-8')
data_bytes = sencrypted_data.encode('utf-8')
padded_data = pad(data_bytes, AES.block_size)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
encrypted_bytes = cipher.encrypt(padded_data)
encrypted_data_b64 = base64.b64encode(encrypted_bytes).decode('utf-8')
return encrypted_data_b64
def ocr(self, base64img):
dat2 = self.post('https://api.nn.ci/ocr/b64/text', data=base64img, headers=self.get_headers(1), verify=False).text
if dat2: return dat2
return None
def verification(self):
random_uuid = str(uuid.uuid4())
dat = self.fetch(f'{self.xurl}.verify/create?key={random_uuid}', headers=self.get_headers(), verify=False).content
base64_img = base64.b64encode(dat).decode('utf-8')
if not dat:
return None
code = self.ocr(base64_img)
if not code:
return None
code = self.replace_code(code)
if not (len(code) == 4 and code.isdigit()):
return None
return {'uuid': random_uuid, 'code': code}
def replace_code(self,text):
replacements = {'y':'9','':'0','q':'0','u':'0','o':'0','>':'1','d':'0','b':'8','':'2','D':'0','':'5'}
if len(text) == 3:
text = text.replace('566', '5066').replace('066', '1666')
return ''.join(replacements.get(c, c) for c in text)
def getName(self):
return "新版APPget"
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
Binary file not shown.
File diff suppressed because one or more lines are too long
-3201
Melihat File
@@ -1,3201 +0,0 @@
import {
cheerio,
模板
} from "./drpy-core-lite.min.js";
let vercode = typeof pdfl === "function" ? "drpy2.1" : "drpy2";
const VERSION = vercode + " 3.9.52beta3 20250801";
const UpdateInfo = [{
date: "20250801",
title: "drpy依赖更新,使用drpy-core-lite.min.js",
version: "3.9.52beta3 20250801",
msg: `
drpy-core.min.js 更换为更小的drpy-core-lite.min.js
`
}, {
date: "20250729",
title: "drpy更新,所有依赖打包成一个js文件",
version: "3.9.52beta2 20250729",
msg: `
1. wasm支持
2. 引入 TextEncoder、TextDecoder对象
3. 引入 WXXH 加解密库
4. 所有依赖打包成一个js
5. 增加 buildQueryString
`
}, {
date: "20250728",
title: "drpy更新,增加tab_order线路模糊排序,优化解密算法支持文件头",
version: "3.9.52beta1 20250728",
msg: `
1. 增加tab_order线路模糊排序
2. 优化解密算法支持文件头
3. wasm支持
4. 增加 removeHeader 函数可用于清除js/py文件的头信息及所有头注释
5. 引入 TextEncoder、TextDecoder对象
6. 引入 WXXH 加解密库
`
}, {
date: "20241126",
title: "drpy更新,优化去广告算法",
version: "3.9.51beta6 20241126",
msg: `
1. 更新龙头大佬提供的去广告算法
`
}, {
date: "20241104",
title: "drpy更新,增加新特性",
version: "3.9.51beta5 20241104",
msg: `
1. rule增加 搜索验证标识 属性,可以不定义,默认为 '系统安全验证|请输入验证码'
2. rule增加 searchNoPage 属性,可以不定义,如果定义 1 将关闭该源的搜索翻页功能,超过1页直接返回空
`
}];
function getUpdateInfo() {
return UpdateInfo.map(_o => {
_o.msg = _o.msg.trim().split("\n").map(_it => _it.trim()).join("\n");
return _o
})
}
function init_test() {
console.log("init_test_start");
console.log("当前版本号:" + VERSION);
console.log("本地代理地址:" + getProxyUrl());
console.log(RKEY);
console.log(JSON.stringify(rule));
console.log("init_test_end")
}
function ocr_demo_test() {
let img_base64 = `iVBORw0KGgoAAAANSUhEUgAAAIAAAAAoBAMAAADEX+97AAAAG1BMVEXz+/4thQTa7N6QwIFFkyNeokKozqDB3b93sWHFR+MEAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABN0lEQVRIie2TQU+DQBCFt9vScvQpxR4xrcSjJCZ67JDGXsX+AdR4B3vpsSYm/m2HXaRLmuySepR3Gdidb/btDAjRq5dT96eCMlfBuzi1QLZUoZy2yz5sOvI+9iomaPEZ6nWnEtxqIyiM1RcAy44GNDhBXUjot/VVNweV1ah68FqWRyjKIOqAcyYF6rGcmpYnHzGt3fycNoMw0d3/THFu7hFSJ/8OXO6iTM8/KSg09obAzIHLO250LgQ0txOZSfgrV4Exdw98uGycJ0ErAeExZGhOmFHV9zHO6qVSj0MpLq7xZON56o++MjlsEgfVhbQWWME+xQX7J4V6zfi9A1Ly9rP1BvEXp+BbVJ/M77n+wfOIDVp51pZ4iBxvmj9AGrtvry6emwfKnVkW+ZRKd5ZNMvob36vXP9YPDmQki8QiCFAAAAAASUVORK5CYII=`;
OcrApi.api = OCR_API;
let code = OcrApi.classification(img_base64);
log("测试验证码图片的ocr识别结果为:" + code)
}
function rsa_demo_test() {
let t1 = (new Date).getTime();
let pkcs1_public = `
-----BEGIN RSA PUBLIC KEY-----
MEgCQQCrI0pQ/ERRpJ3Ou190XJedFq846nDYP52rOtXyDxlFK5D3p6JJu2RwsKwy
lsQ9xY0xYPpRZUZKMEeR7e9gmRNLAgMBAAE=
-----END RSA PUBLIC KEY-----
`.trim();
let pkcs1_public_pem = `
MEgCQQCrI0pQ/ERRpJ3Ou190XJedFq846nDYP52rOtXyDxlFK5D3p6JJu2RwsKwy
lsQ9xY0xYPpRZUZKMEeR7e9gmRNLAgMBAAE=
`.trim();
let pkcs8_public = `
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKsjSlD8RFGknc67X3Rcl50WrzjqcNg/
nas61fIPGUUrkPenokm7ZHCwrDKWxD3FjTFg+lFlRkowR5Ht72CZE0sCAwEAAQ==
-----END PUBLIC KEY-----`.trim();
let pkcs8_public_pem = `
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKsjSlD8RFGknc67X3Rcl50WrzjqcNg/
nas61fIPGUUrkPenokm7ZHCwrDKWxD3FjTFg+lFlRkowR5Ht72CZE0sCAwEAAQ==
`.trim();
let pkcs1_private = `
-----BEGIN RSA PRIVATE KEY-----
MIIBOAIBAAJBAKsjSlD8RFGknc67X3Rcl50WrzjqcNg/nas61fIPGUUrkPenokm7
ZHCwrDKWxD3FjTFg+lFlRkowR5Ht72CZE0sCAwEAAQI/b6OV1z65UokQaMvSeRXt
0Yv6wiYtduQI9qpq5nzy/ytaqsbBfClNTi/HifKPKxlRouWFkc518EQI8LBxoarJ
AiEA4DaONMplV8PQNa3TKn2F+SDEvLOCjdL0kHKdN90Ti28CIQDDZnTBaHgZwZbA
hS7Bbf5yvwjWMhO6Y7l04/Qm7R+35QIgPuQuqXIoUSD080mp1N5WyRW++atksIF+
5lGv9e6GP/MCICnj8y/rl6Pd7tXDN6zcSeqLrfdNsREKhB3dKOCXgW9JAiAFYtFS
EJNBXVRTK42SNsZ2hJ/9xLwOwnH2epT8Q43s3Q==
-----END RSA PRIVATE KEY-----
`.trim();
let pkcs8_private = `
-----BEGIN PRIVATE KEY-----
MIIBUgIBADANBgkqhkiG9w0BAQEFAASCATwwggE4AgEAAkEAqyNKUPxEUaSdzrtf
dFyXnRavOOpw2D+dqzrV8g8ZRSuQ96eiSbtkcLCsMpbEPcWNMWD6UWVGSjBHke3v
YJkTSwIDAQABAj9vo5XXPrlSiRBoy9J5Fe3Ri/rCJi125Aj2qmrmfPL/K1qqxsF8
KU1OL8eJ8o8rGVGi5YWRznXwRAjwsHGhqskCIQDgNo40ymVXw9A1rdMqfYX5IMS8
s4KN0vSQcp033ROLbwIhAMNmdMFoeBnBlsCFLsFt/nK/CNYyE7pjuXTj9CbtH7fl
AiA+5C6pcihRIPTzSanU3lbJFb75q2SwgX7mUa/17oY/8wIgKePzL+uXo93u1cM3
rNxJ6out902xEQqEHd0o4JeBb0kCIAVi0VIQk0FdVFMrjZI2xnaEn/3EvA7CcfZ6
lPxDjezd
-----END PRIVATE KEY-----
`.trim();
let data = `
NodeRsa
这是node-rsa 现在修改集成在drpy里使用`.trim();
let encryptedWithPublic = NODERSA.encryptRSAWithPublicKey(data, pkcs1_public, {
outputEncoding: "base64",
options: {
environment: "browser",
encryptionScheme: "pkcs1_oaep"
}
});
console.log("公钥加密");
console.log(encryptedWithPublic);
let decryptedWithPrivate = NODERSA.decryptRSAWithPrivateKey(encryptedWithPublic, pkcs1_private, {
options: {
environment: "browser",
encryptionScheme: "pkcs1_oaep"
}
});
console.log("私钥解密");
console.log(decryptedWithPrivate);
let pkcs1_sha256_sign = NODERSA.sign("1", pkcs1_private, {
outputEncoding: "base64",
options: {
environment: "browser",
encryptionScheme: "pkcs1",
signingScheme: "pkcs1-sha256"
}
});
console.log("pkcs1_sha256_sign");
console.log(pkcs1_sha256_sign);
let pkcs1_sha256_sign_verify = NODERSA.verify("1", "Oulx2QrgeipKYBtqEDqFb2s/+ndk2cGQxO4CkhU7iBM1vyNmmvqubpsmeoUuN3waGrYZLknSEdwBkfv0tUMpFQ==", pkcs1_private, {
options: {
environment: "browser",
encryptionScheme: "pkcs1",
signingScheme: "pkcs1-sha256"
}
});
console.log("pkcs1_sha256_sign_verify");
console.log(pkcs1_sha256_sign_verify);
let pkcs1_oaep_sha256 = NODERSA.encryptRSAWithPublicKey(data, `-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA5KOq1gRNyllLNWKQy8sGpZE3Q1ULLSmzZw+eaAhj9lvqn7IsT1du
SYn08FfoOA2qMwtz+1O2l1mgzNoSVCyVpVabnTG+C9XKeZXAnJHd8aYA7l7Sxhdm
kte+iymYZ0ZBPzijo8938iugtVvqi9UgDmnY3u/NlQDqiL5BGqSxSTd/Sgmy3zD8
PYzEa3wD9vehQ5fZZ45vKIq8GNVh2Z8+IGO85FF1OsN7+b2yGJa/FmDDNn0+HP+m
PfI+kYBqEVpo0Ztbc3UdxgFwGC8O1n8AQyriwHnSOtIiuBH62J/7qyC/3LEAApRb
Dd9YszqzmODjQUddZKHmvc638VW+azc0EwIDAQAB
-----END RSA PUBLIC KEY-----
`, {
outputEncoding: "base64",
options: {
environment: "browser",
encryptionScheme: {
scheme: "pkcs1_oaep",
hash: "sha256"
}
}
});
console.log("pkcs1_oaep_sha256");
console.log(pkcs1_oaep_sha256);
decryptedWithPrivate = NODERSA.decryptRSAWithPrivateKey("kSZesAAyYh2hdsQnYMdGqb6gKAzTauBKouvBzWcc4+F8RvGd0nwO6mVkUMVilPgUuNxjEauHayHiY8gI3Py45UI3+km0rSGyHrS6dHiHgCkMejXHieglYzAB0IxX3Jkm4z/66bdB/D+GFy0oct5fGCMI1UHPjEAYOsazJDa8lBFNbjiWFeb/qiZtIx3vGM7KYPAZzyRf/zPbbQ8zy9xOmRuOl5nnIxgo0Okp3KO/RIPO4GZOSBA8f2lx1UtNwwrXAMpcNavtoqHVcjJ/9lcotXYQFrn5b299pSIRf2gVm8ZJ31SK6Z8cc14nKtvgnmsgClDzIXJ1o1RcDK+knVAySg==", `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA5KOq1gRNyllLNWKQy8sGpZE3Q1ULLSmzZw+eaAhj9lvqn7Is
T1duSYn08FfoOA2qMwtz+1O2l1mgzNoSVCyVpVabnTG+C9XKeZXAnJHd8aYA7l7S
xhdmkte+iymYZ0ZBPzijo8938iugtVvqi9UgDmnY3u/NlQDqiL5BGqSxSTd/Sgmy
3zD8PYzEa3wD9vehQ5fZZ45vKIq8GNVh2Z8+IGO85FF1OsN7+b2yGJa/FmDDNn0+
HP+mPfI+kYBqEVpo0Ztbc3UdxgFwGC8O1n8AQyriwHnSOtIiuBH62J/7qyC/3LEA
ApRbDd9YszqzmODjQUddZKHmvc638VW+azc0EwIDAQABAoIBADZ/QGgUzInvsLp/
zO2WbfYm39o/uhNAvk9RbLt1TIZbMFhyOpeKynHi3Swwd9xsfWX/U9zS/lGi/m31
iKrhmaW4OA1G3vqpMcK7TBbFufYwUEaA+ZJX344euH8pIfdzyneMQ4z3Far2dS7l
QsmjuilVV2kEFadveXewiYoVOWCu00w6bN8wy2SIHlQn+kIL6HQhWz12iKKflIKu
eGRdzLHsKmBt6WbY1Wuhx7HU0fAKdlBDPxCHNlI+kybUYE9o5C2vJiaVM5wqJBgZ
8Dz8kt1QbLJ910JoLXkLVQ8uC8NJKQwFtqQjTGPnEq0+wbgz6Ij599rKZkwW/xq9
l6KoUiECgYEA6Ah42tVdkNW047f03xVYXFH96RgorHRS36mR8Y+ONUq1fwKidovC
WjwVujt4OPf3l1W6iyn/F6cu/bsmvPrSc3HTN0B1V31QK4OjgetxQ2PSbTldH02J
NPzkt+v+cPxXpx/P5mgt7Weefw5txU547KubGrHUV5rBKFtIx9pj16MCgYEA/EF0
o19+D24DZAPwlDS5VbEd7FStnwY4oQ5PqbuNOSbSJLMWU0AqzXcRokp8UTyCZ0X3
ATkS1REq97kShCuR+npTR6a6DlY7sdpPI1SMLNajgB2tkx0EOzX+PfNIbHUd4jpJ
I0ZMAHv/OOtkzQHDaeTWBTrzsWm6/nTiykfduNECgYEA46AMD4HpPECqKAs66e5i
tI6q7JSKskObWVdcmQEfnSAhVOwcvPb2Ptda6UuV8S0xcwDi88rLOUUFUFzc79+P
vTkY38cYVi/VChsluDpk7ptqv0PbGu5Rf+3n4pZdEjI7OvR2W64wAAn67uIUxc7p
yiO/ET0K9rYWb6S9jXGtKMkCgYEA2kPAqoO7zZoBMQ7/oR0lp/HC1HRIbiqx4RlC
8Lgpb+QZPEwA6zPAVVvLVENi4d+bbcRp/xLlKpraNNJcJSSWAMbLPFoU7sbKjA87
HnTPfRSTEA2d3Ibk3F7Rh8TzS3Ti0JZiJjVzGZAwu41iAMifzwaD8K6boUy80eNN
QH2CaaECgYBUsLYvC/MiYg3w+LGOONuQongoVUXjGqnw2bjVa9RK7lwRdXPUqJ51
MpVO98IkoLvGSI/0sGNP3GKNhC+eMGjJAVwFyEuOn+JsmMv9Y9uStIVi5tIHIhKw
m7mp8il0kaftHdSxTbspG3tZ2fjIiFIZkLEOmRpd7ogWumgOajzUdA==
-----END RSA PRIVATE KEY-----`, {
options: {
environment: "browser",
encryptionScheme: "pkcs1_oaep"
}
});
console.log("decryptedWithPrivate");
console.log(decryptedWithPrivate);
(() => {
let key = new NODERSA.NodeRSA({
b: 1024
});
key.setOptions({
encryptionScheme: "pkcs1"
});
let text = `你好drpy node-ras`;
let encrypted = key.encrypt(text, "base64");
console.log("encrypted: ", encrypted);
const decrypted = key.decrypt(encrypted, "utf8");
console.log("decrypted: ", decrypted)
})();
let t2 = (new Date).getTime();
console.log("rsa_demo_test 测试耗时:" + (t2 - t1) + "毫秒")
}
function pre() {
if (typeof rule.预处理 === "string" && rule.预处理 && rule.预处理.trim()) {
let code = rule.预处理.trim();
console.log("执行预处理代码:" + code);
if (code.startsWith("js:")) {
code = code.replace("js:", "")
}
try {
eval(code)
} catch (e) {
console.log(`预处理执行失败:${e.message}`)
}
}
}
let rule = {};
const MOBILE_UA = "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36";
const PC_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36";
const UA = "Mozilla/5.0";
const UC_UA = "Mozilla/5.0 (Linux; U; Android 9; zh-CN; MI 9 Build/PKQ1.181121.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.5.5.1035 Mobile Safari/537.36";
const IOS_UA = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
const RULE_CK = "cookie";
const CATE_EXCLUDE = "首页|留言|APP|下载|资讯|新闻|动态";
const TAB_EXCLUDE = "猜你|喜欢|下载|剧情|榜|评论";
const OCR_RETRY = 3;
const OCR_API = "https://api.nn.ci/ocr/b64/text";
if (typeof MY_URL === "undefined") {
var MY_URL
}
var HOST;
var RKEY;
var fetch;
var print;
var log;
var rule_fetch_params;
var fetch_params;
var oheaders;
var _pdfh;
var _pdfa;
var _pd;
const DOM_CHECK_ATTR = /(url|src|href|-original|-src|-play|-url|style)$/;
const SPECIAL_URL = /^(ftp|magnet|thunder|ws):/;
const NOADD_INDEX = /:eq|:lt|:gt|:first|:last|^body$|^#/;
const URLJOIN_ATTR = /(url|src|href|-original|-src|-play|-url|style)$|^(data-|url-|src-)/;
const SELECT_REGEX = /:eq|:lt|:gt|#/g;
const SELECT_REGEX_A = /:eq|:lt|:gt/g;
const $js = {
toString(func) {
let strfun = func.toString();
return strfun.replace(/^\(\)(\s+)?=>(\s+)?\{/, "js:").replace(/\}$/, "")
}
};
function window_b64() {
let b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
function btoa(str) {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
while (i < len) {
c1 = str.charCodeAt(i++) & 255;
if (i == len) {
out += b64map.charAt(c1 >> 2);
out += b64map.charAt((c1 & 3) << 4);
out += "==";
break
}
c2 = str.charCodeAt(i++);
if (i == len) {
out += b64map.charAt(c1 >> 2);
out += b64map.charAt((c1 & 3) << 4 | (c2 & 240) >> 4);
out += b64map.charAt((c2 & 15) << 2);
out += "=";
break
}
c3 = str.charCodeAt(i++);
out += b64map.charAt(c1 >> 2);
out += b64map.charAt((c1 & 3) << 4 | (c2 & 240) >> 4);
out += b64map.charAt((c2 & 15) << 2 | (c3 & 192) >> 6);
out += b64map.charAt(c3 & 63)
}
return out
}
function atob(str) {
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while (i < len) {
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 255]
} while (i < len && c1 == -1);
if (c1 == -1) break;
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 255]
} while (i < len && c2 == -1);
if (c2 == -1) break;
out += String.fromCharCode(c1 << 2 | (c2 & 48) >> 4);
do {
c3 = str.charCodeAt(i++) & 255;
if (c3 == 61) return out;
c3 = base64DecodeChars[c3]
} while (i < len && c3 == -1);
if (c3 == -1) break;
out += String.fromCharCode((c2 & 15) << 4 | (c3 & 60) >> 2);
do {
c4 = str.charCodeAt(i++) & 255;
if (c4 == 61) return out;
c4 = base64DecodeChars[c4]
} while (i < len && c4 == -1);
if (c4 == -1) break;
out += String.fromCharCode((c3 & 3) << 6 | c4)
}
return out
}
return {
atob: atob,
btoa: btoa
}
}
if (typeof atob !== "function" || typeof btoa !== "function") {
var {
atob,
btoa
} = window_b64()
}
if (typeof Object.assign !== "function") {
Object.assign = function() {
let target = arguments[0];
for (let i = 1; i < arguments.length; i++) {
let source = arguments[i];
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key]
}
}
}
return target
}
}
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
if (typeof start !== "number") {
start = 0
}
if (start + search.length > this.length) {
return false
} else {
return this.indexOf(search, start) !== -1
}
}
}
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, "includes", {
value: function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined')
}
var o = Object(this);
var len = o.length >>> 0;
if (len === 0) {
return false
}
var n = fromIndex | 0;
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
while (k < len) {
if (o[k] === searchElement) {
return true
}
k++
}
return false
},
enumerable: false
})
}
if (typeof String.prototype.startsWith !== "function") {
String.prototype.startsWith = function(prefix) {
return this.slice(0, prefix.length) === prefix
}
}
if (typeof String.prototype.endsWith !== "function") {
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1
}
}
Object.defineProperty(Object.prototype, "myValues", {
value: function(obj) {
if (obj == null) {
throw new TypeError("Cannot convert undefined or null to object")
}
var res = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
res.push(obj[k])
}
}
return res
},
enumerable: false
});
if (typeof Object.prototype.values !== "function") {
Object.defineProperty(Object.prototype, "values", {
value: function(obj) {
if (obj == null) {
throw new TypeError("Cannot convert undefined or null to object")
}
var res = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
res.push(obj[k])
}
}
return res
},
enumerable: false
})
}
if (typeof Array.prototype.join !== "function") {
Object.defineProperty(Array.prototype, "join", {
value: function(emoji) {
emoji = emoji || "";
let self = this;
let str = "";
let i = 0;
if (!Array.isArray(self)) {
throw String(self) + "is not Array"
}
if (self.length === 0) {
return ""
}
if (self.length === 1) {
return String(self[0])
}
i = 1;
str = this[0];
for (; i < self.length; i++) {
str += String(emoji) + String(self[i])
}
return str
},
enumerable: false
})
}
if (typeof Array.prototype.toReversed !== "function") {
Object.defineProperty(Array.prototype, "toReversed", {
value: function() {
const clonedList = this.slice();
const reversedList = clonedList.reverse();
return reversedList
},
enumerable: false
})
}
Object.defineProperty(Array.prototype, "append", {
value: Array.prototype.push,
enumerable: false
});
Object.defineProperty(String.prototype, "strip", {
value: String.prototype.trim,
enumerable: false
});
Object.defineProperty(String.prototype, "rstrip", {
value: function(chars) {
let regex = new RegExp(chars + "$");
return this.replace(regex, "")
},
enumerable: false
});
function 是否正版(vipUrl) {
let flag = new RegExp("qq.com|iqiyi.com|youku.com|mgtv.com|bilibili.com|sohu.com|ixigua.com|pptv.com|miguvideo.com|le.com|1905.com|fun.tv");
return flag.test(vipUrl)
}
function urlDeal(vipUrl) {
if (!vipUrl) {
return ""
}
if (!是否正版(vipUrl)) {
return vipUrl
}
if (!/miguvideo/.test(vipUrl)) {
vipUrl = vipUrl.split("#")[0].split("?")[0]
}
return vipUrl
}
function setResult(d) {
if (!Array.isArray(d)) {
return []
}
VODS = [];
d.forEach(function(it) {
let obj = {
vod_id: it.url || "",
vod_name: it.title || "",
vod_remarks: it.desc || "",
vod_content: it.content || "",
vod_pic: it.pic_url || it.img || ""
};
let keys = Object.keys(it);
if (keys.includes("tname")) {
obj.type_name = it.tname || ""
}
if (keys.includes("tid")) {
obj.type_id = it.tid || ""
}
if (keys.includes("year")) {
obj.vod_year = it.year || ""
}
if (keys.includes("actor")) {
obj.vod_actor = it.actor || ""
}
if (keys.includes("director")) {
obj.vod_director = it.director || ""
}
if (keys.includes("area")) {
obj.vod_area = it.area || ""
}
VODS.push(obj)
});
return VODS
}
function setResult2(res) {
VODS = res.list || [];
return VODS
}
function setHomeResult(res) {
if (!res || typeof res !== "object") {
return []
}
return setResult(res.list)
}
function rc(js) {
if (js === "maomi_aes.js") {
var a = CryptoJS.enc.Utf8.parse("625222f9149e961d");
var t = CryptoJS.enc.Utf8.parse("5efdtf6060e2o330");
return {
De: function(word) {
word = CryptoJS.enc.Hex.parse(word);
return CryptoJS.AES.decrypt(CryptoJS.enc.Base64.stringify(word), a, {
iv: t,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8)
},
En: function(word) {
var Encrypted = CryptoJS.AES.encrypt(word, a, {
iv: t,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return Encrypted.ciphertext.toString()
}
}
}
return {}
}
function maoss(jxurl, ref, key) {
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
eval(getCryptoJS());
try {
var getVideoInfo = function(text) {
return CryptoJS.AES.decrypt(text, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8)
};
var token_key = key == undefined ? "dvyYRQlnPRCMdQSe" : key;
if (ref) {
var html = request(jxurl, {
headers: {
Referer: ref
}
})
} else {
var html = request(jxurl)
}
if (html.indexOf("&btwaf=") != -1) {
html = request(jxurl + "&btwaf" + html.match(/&btwaf(.*?)"/)[1], {
headers: {
Referer: ref
}
})
}
var token_iv = html.split('_token = "')[1].split('"')[0];
var key = CryptoJS.enc.Utf8.parse(token_key);
var iv = CryptoJS.enc.Utf8.parse(token_iv);
eval(html.match(/var config = {[\s\S]*?}/)[0] + "");
if (!config.url.startsWith("http")) {
config.url = CryptoJS.AES.decrypt(config.url, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8)
}
return config.url
} catch (e) {
return ""
}
}
function urlencode(str) {
str = (str + "").toString();
return encodeURIComponent(str).replace(/!/g, "%21").replace(/'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/\*/g, "%2A").replace(/%20/g, "+")
}
function encodeUrl(str) {
if (typeof encodeURI == "function") {
return encodeURI(str)
} else {
str = (str + "").toString();
return encodeURIComponent(str).replace(/%2F/g, "/").replace(/%3F/g, "?").replace(/%3A/g, ":").replace(/%40/g, "@").replace(/%3D/g, "=").replace(/%3A/g, ":").replace(/%2C/g, ",").replace(/%2B/g, "+").replace(/%24/g, "$")
}
}
function base64Encode(text) {
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(text))
}
function base64Decode(text) {
return CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(text))
}
function md5(text) {
return CryptoJS.MD5(text).toString()
}
function uint8ArrayToBase64(uint8Array) {
let binaryString = String.fromCharCode.apply(null, Array.from(uint8Array));
return btoa(binaryString)
}
function Utf8ArrayToStr(array) {
var out, i, len, c;
var char2, char3;
out = "";
len = array.length;
i = 0;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
out += String.fromCharCode(c);
break;
case 12:
case 13:
char2 = array[i++];
out += String.fromCharCode((c & 31) << 6 | char2 & 63);
break;
case 14:
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode((c & 15) << 12 | (char2 & 63) << 6 | (char3 & 63) << 0);
break
}
}
return out
}
function gzip(str) {
let arr = pako.gzip(str, {});
return uint8ArrayToBase64(arr)
}
function ungzip(b64Data) {
let strData = atob(b64Data);
const charData = strData.split("").map(function(x) {
return x.charCodeAt(0)
});
const binData = new Uint8Array(charData);
const data = pako.inflate(binData);
return Utf8ArrayToStr(data)
}
function encodeStr(input, encoding) {
encoding = encoding || "gbk";
if (encoding.startsWith("gb")) {
input = gbkTool.encode(input)
}
return input
}
function decodeStr(input, encoding) {
encoding = encoding || "gbk";
if (encoding.startsWith("gb")) {
input = gbkTool.decode(input)
}
return input
}
function getCryptoJS() {
return 'console.log("CryptoJS已装载");'
}
const RSA = {
decode: function(data, key, option) {
option = option || {};
if (typeof JSEncrypt === "function") {
let chunkSize = option.chunkSize || 117;
let privateKey = this.getPrivateKey(key);
const decryptor = new JSEncrypt;
decryptor.setPrivateKey(privateKey);
let uncrypted = "";
uncrypted = decryptor.decryptUnicodeLong(data);
return uncrypted
} else {
return false
}
},
encode: function(data, key, option) {
option = option || {};
if (typeof JSEncrypt === "function") {
let chunkSize = option.chunkSize || 117;
let publicKey = this.getPublicKey(key);
const encryptor = new JSEncrypt;
encryptor.setPublicKey(publicKey);
let encrypted = "";
encrypted = encryptor.encryptUnicodeLong(data);
return encrypted
} else {
return false
}
},
fixKey(key, prefix, endfix) {
if (!key.includes(prefix)) {
key = prefix + key
}
if (!key.includes(endfix)) {
key += endfix
}
return key
},
getPrivateKey(key) {
let prefix = "-----BEGIN RSA PRIVATE KEY-----";
let endfix = "-----END RSA PRIVATE KEY-----";
return this.fixKey(key, prefix, endfix)
},
getPublicKey(key) {
let prefix = "-----BEGIN PUBLIC KEY-----";
let endfix = "-----END PUBLIC KEY-----";
return this.fixKey(key, prefix, endfix)
}
};
function getProxyUrl() {
if (typeof getProxy === "function") {
return getProxy(true)
} else {
return "http://127.0.0.1:9978/proxy?do=js"
}
}
function fixAdM3u8(m3u8_text, m3u8_url, ad_remove) {
if (!m3u8_text && !m3u8_url || !m3u8_text && m3u8_url && !m3u8_url.startsWith("http")) {
return ""
}
if (!m3u8_text) {
log("m3u8_url:" + m3u8_url);
m3u8_text = request(m3u8_url)
}
log("len(m3u8_text):" + m3u8_text.length);
if (!ad_remove) {
return m3u8_text
}
if (ad_remove.startsWith("reg:")) {
ad_remove = ad_remove.slice(4)
} else if (ad_remove.startsWith("js:")) {
ad_remove = ad_remove.slice(3)
}
let m3u8_start = m3u8_text.slice(0, m3u8_text.indexOf("#EXTINF")).trim();
let m3u8_body = m3u8_text.slice(m3u8_text.indexOf("#EXTINF"), m3u8_text.indexOf("#EXT-X-ENDLIST")).trim();
let m3u8_end = m3u8_text.slice(m3u8_text.indexOf("#EXT-X-ENDLIST")).trim();
let murls = [];
let m3_body_list = m3u8_body.split("\n");
let m3_len = m3_body_list.length;
let i = 0;
while (i < m3_len) {
let mi = m3_body_list[i];
let mi_1 = m3_body_list[i + 1];
if (mi.startsWith("#EXTINF")) {
murls.push([mi, mi_1].join("&"));
i += 2
} else if (mi.startsWith("#EXT-X-DISCONTINUITY")) {
let mi_2 = m3_body_list[i + 2];
murls.push([mi, mi_1, mi_2].join("&"));
i += 3
} else {
break
}
}
let new_m3u8_body = [];
for (let murl of murls) {
if (ad_remove && new RegExp(ad_remove).test(murl)) {} else {
let murl_list = murl.split("&");
if (!murl_list[murl_list.length - 1].startsWith("http") && m3u8_url.startsWith("http")) {
murl_list[murl_list.length - 1] = urljoin(m3u8_url, murl_list[murl_list.length - 1])
}
murl_list.forEach(it => {
new_m3u8_body.push(it)
})
}
}
new_m3u8_body = new_m3u8_body.join("\n").trim();
m3u8_text = [m3u8_start, new_m3u8_body, m3u8_end].join("\n").trim();
return m3u8_text
}
function fixAdM3u8Ai(m3u8_url, headers) {
let ts = (new Date).getTime();
let option = headers ? {
headers: headers
} : {};
function b(s1, s2) {
let i = 0;
while (i < s1.length) {
if (s1[i] !== s2[i]) {
break
}
i++
}
return i
}
function reverseString(str) {
return str.split("").reverse().join("")
}
let m3u8 = request(m3u8_url, option);
m3u8 = m3u8.trim().split("\n").map(it => it.startsWith("#") ? it : urljoin(m3u8_url, it)).join("\n");
m3u8 = m3u8.replace(/\n\n/gi, "\n");
let last_url = m3u8.split("\n").slice(-1)[0];
if (last_url.length < 5) {
last_url = m3u8.split("\n").slice(-2)[0]
}
if (last_url.includes(".m3u8") && last_url !== m3u8_url) {
m3u8_url = urljoin2(m3u8_url, last_url);
log("嵌套的m3u8_url:" + m3u8_url);
m3u8 = request(m3u8_url, option)
}
let s = m3u8.trim().split("\n").filter(it => it.trim()).join("\n");
let ss = s.split("\n");
if (m3u8_url.indexOf("ffzy") > 0) {
let j = 0,
k1 = 0,
m = 0,
n = 0,
t = 0;
let s2 = "";
for (let i = 0; i < ss.length; i++) {
let s = ss[i];
let s1 = "";
if (s.startsWith("#EXTINF")) {
s1 = s.slice(8);
n++;
if (n == 1) k1 = i;
if (s2.indexOf(s1) == -1) {
s2 = s2 + s1;
m++
}
t = t + parseFloat(s1);
i++;
s = ss[i]
}
if (s.startsWith("#EXT-X-DISCONTINUITY")) {
if (n == 5) {
log("n:" + n);
log("m:" + m);
for (let j = k1; j < k1 + n * 2; j++) {
log(ss[j])
}
log("广告位置:" + k1);
log("数据条数:" + n);
log("数据种类:" + m);
log("广告时间:" + t.toFixed(5));
ss.splice(k1, 2 * n + 1);
i = i - 2 * n + 1
}
t = 0;
m = 0;
n = 0;
s2 = ""
}
}
}
let firststr = "";
let maxl = 0;
let kk = 0;
let kkk1 = 1;
let kkk2 = 0;
let secondstr = "";
for (let i = 0; i < ss.length; i++) {
let s = ss[i];
if (!s.startsWith("#")) {
if (kk == 0) firststr = s;
if (kk > 0) {
if (maxl > b(firststr, s) + 1) {
if (secondstr.length < 5) secondstr = s;
kkk2++
} else {
maxl = b(firststr, s);
kkk1++
}
}
kk++;
if (kk >= 30) break
}
}
if (kkk2 > kkk1) firststr = secondstr;
let firststrlen = firststr.length;
let ml = Math.round(ss.length / 2).toString().length;
let maxc = 0;
let laststr = ss.toReversed().find(x => {
if (!x.startsWith("#")) {
let k = b(reverseString(firststr), reverseString(x));
maxl = b(firststr, x);
maxc++;
if (firststrlen - maxl <= ml + k || maxc > 10) {
return true
}
}
return false
});
log("最后一条切片:" + laststr);
let ad_urls = [];
for (let i = 0; i < ss.length; i++) {
let s = ss[i];
if (!s.startsWith("#")) {
if (b(firststr, s) < maxl) {
ad_urls.push(s);
ss.splice(i - 1, 2);
i = i - 2
} else {
ss[i] = urljoin(m3u8_url, s)
}
} else {
ss[i] = s.replace(/URI=\"(.*)\"/, 'URI="' + urljoin(m3u8_url, "$1") + '"')
}
}
log("处理的m3u8地址:" + m3u8_url);
log("----广告地址----");
log(ad_urls);
m3u8 = ss.join("\n");
log("处理耗时:" + ((new Date).getTime() - ts).toString());
log(m3u8);
return m3u8
}
function forceOrder(lists, key, option) {
let start = Math.floor(lists.length / 2);
let end = Math.min(lists.length - 1, start + 1);
if (start >= end) {
return lists
}
let first = lists[start];
let second = lists[end];
if (key) {
try {
first = first[key];
second = second[key]
} catch (e) {}
}
if (option && typeof option === "function") {
try {
first = option(first);
second = option(second)
} catch (e) {}
}
first += "";
second += "";
if (first.match(/(\d+)/) && second.match(/(\d+)/)) {
let num1 = Number(first.match(/(\d+)/)[1]);
let num2 = Number(second.match(/(\d+)/)[1]);
if (num1 > num2) {
lists.reverse()
}
}
return lists
}
let VODS = [];
let VOD = {};
let TABS = [];
let LISTS = [];
function getQuery(url) {
try {
if (url.indexOf("?") > -1) {
url = url.slice(url.indexOf("?") + 1)
}
let arr = url.split("#")[0].split("&");
const resObj = {};
arr.forEach(item => {
let arr1 = item.split("=");
let key = arr1[0];
let value = arr1.slice(1).join("=");
resObj[key] = value
});
return resObj
} catch (err) {
log(`getQuery发生错误:${e.message}`);
return {}
}
}
function urljoin(fromPath, nowPath) {
fromPath = fromPath || "";
nowPath = nowPath || "";
return joinUrl(fromPath, nowPath)
}
var urljoin2 = urljoin;
const defaultParser = {
pdfh: pdfh,
pdfa: pdfa,
pd: pd
};
function pdfh2(html, parse) {
let html2 = html;
try {
if (typeof html !== "string") {
html2 = html.rr(html.ele).toString()
}
} catch (e) {
print(`html对象转文本发生了错误:${e.message}`)
}
let result = defaultParser.pdfh(html2, parse);
let option = parse.includes("&&") ? parse.split("&&").slice(-1)[0] : parse.split(" ").slice(-1)[0];
if (/style/.test(option.toLowerCase()) && /url\(/.test(result)) {
try {
result = result.match(/url\((.*?)\)/)[1];
result = result.replace(/^['|"](.*)['|"]$/, "$1")
} catch (e) {}
}
return result
}
function pdfa2(html, parse) {
let html2 = html;
try {
if (typeof html !== "string") {
html2 = html.rr(html.ele).toString()
}
} catch (e) {
print(`html对象转文本发生了错误:${e.message}`)
}
return defaultParser.pdfa(html2, parse)
}
function pd2(html, parse, uri) {
let ret = pdfh2(html, parse);
if (typeof uri === "undefined" || !uri) {
uri = ""
}
if (DOM_CHECK_ATTR.test(parse) && !SPECIAL_URL.test(ret)) {
if (/http/.test(ret)) {
ret = ret.slice(ret.indexOf("http"))
} else {
ret = urljoin(MY_URL, ret)
}
}
return ret
}
const parseTags = {
jsp: {
pdfh: pdfh2,
pdfa: pdfa2,
pd: pd2
},
json: {
pdfh(html, parse) {
if (!parse || !parse.trim()) {
return ""
}
if (typeof html === "string") {
html = JSON.parse(html)
}
parse = parse.trim();
if (!parse.startsWith("$.")) {
parse = "$." + parse
}
parse = parse.split("||");
for (let ps of parse) {
let ret = cheerio.jp(ps, html);
if (Array.isArray(ret)) {
ret = ret[0] || ""
} else {
ret = ret || ""
}
if (ret && typeof ret !== "string") {
ret = ret.toString()
}
if (ret) {
return ret
}
}
return ""
},
pdfa(html, parse) {
if (!parse || !parse.trim()) {
return ""
}
if (typeof html === "string") {
html = JSON.parse(html)
}
parse = parse.trim();
if (!parse.startsWith("$.")) {
parse = "$." + parse
}
let ret = cheerio.jp(parse, html);
if (Array.isArray(ret) && Array.isArray(ret[0]) && ret.length === 1) {
return ret[0] || []
}
return ret || []
},
pd(html, parse) {
let ret = parseTags.json.pdfh(html, parse);
if (ret) {
return urljoin(MY_URL, ret)
}
return ret
}
},
jq: {
pdfh(html, parse) {
if (!html || !parse || !parse.trim()) {
return ""
}
parse = parse.trim();
let result = defaultParser.pdfh(html, parse);
return result
},
pdfa(html, parse) {
if (!html || !parse || !parse.trim()) {
return []
}
parse = parse.trim();
let result = defaultParser.pdfa(html, parse);
print(`pdfa解析${parse}=>${result.length}`);
return result
},
pd(html, parse, base_url) {
if (!html || !parse || !parse.trim()) {
return ""
}
parse = parse.trim();
base_url = base_url || MY_URL;
return defaultParser.pd(html, parse, base_url)
}
},
getParse(p0) {
if (p0.startsWith("jsp:")) {
return this.jsp
} else if (p0.startsWith("json:")) {
return this.json
} else if (p0.startsWith("jq:")) {
return this.jq
} else {
return this.jq
}
}
};
const stringify = JSON.stringify;
const jsp = parseTags.jsp;
const jq = parseTags.jq;
function readFile(filePath) {
filePath = filePath || "./uri.min.js";
var fd = os.open(filePath);
var buffer = new ArrayBuffer(1024);
var len = os.read(fd, buffer, 0, 1024);
console.log(len);
let text = String.fromCharCode.apply(null, new Uint8Array(buffer));
console.log(text);
return text
}
function dealJson(html) {
try {
html = html.trim();
if (!(html.startsWith("{") && html.endsWith("}") || html.startsWith("[") && html.endsWith("]"))) {
html = "{" + html.match(/.*?\{(.*)\}/m)[1] + "}"
}
} catch (e) {}
try {
html = JSON.parse(html)
} catch (e) {}
return html
}
var OcrApi = {
api: OCR_API,
classification: function(img) {
let code = "";
try {
log("通过drpy_ocr验证码接口过验证...");
let html = "";
if (this.api.endsWith("drpy/text")) {
html = request(this.api, {
data: {
img: img
},
headers: {
"User-Agent": PC_UA
},
method: "POST"
}, true)
} else {
html = post(this.api, {
body: img
})
}
code = html || ""
} catch (e) {
log(`OCR识别验证码发生错误:${e.message}`)
}
return code
}
};
function verifyCode(url) {
let cnt = 0;
let host = getHome(url);
let cookie = "";
while (cnt < OCR_RETRY) {
try {
let yzm_url = `${host}/index.php/verify/index.html`;
console.log(`验证码链接:${yzm_url}`);
let hhtml = request(yzm_url, {
withHeaders: true,
toBase64: true
}, true);
let json = JSON.parse(hhtml);
if (!cookie) {
let setCk = Object.keys(json).find(it => it.toLowerCase() === "set-cookie");
cookie = setCk ? json[setCk].split(";")[0] : ""
}
console.log("cookie:" + cookie);
let img = json.body;
let code = OcrApi.classification(img);
console.log(`${cnt+1}次验证码识别结果:${code}`);
let submit_url = `${host}/index.php/ajax/verify_check?type=search&verify=${code}`;
console.log(submit_url);
let html = request(submit_url, {
headers: {
Cookie: cookie
},
method: "POST"
});
html = JSON.parse(html);
if (html.msg === "ok") {
console.log(`${cnt+1}次验证码提交成功`);
return cookie
} else if (html.msg !== "ok" && cnt + 1 >= OCR_RETRY) {
cookie = ""
}
} catch (e) {
console.log(`${cnt+1}次验证码提交失败:${e.message}`);
if (cnt + 1 >= OCR_RETRY) {
cookie = ""
}
}
cnt += 1
}
return cookie
}
function setItem(k, v) {
local.set(RKEY, k, v);
console.log(`规则${RKEY}设置${k} => ${v}`)
}
function getItem(k, v) {
return local.get(RKEY, k) || v
}
function clearItem(k) {
local.delete(RKEY, k)
}
function getHome(url) {
if (!url) {
return ""
}
let tmp = url.split("//");
url = tmp[0] + "//" + tmp[1].split("/")[0];
try {
url = decodeURIComponent(url)
} catch (e) {}
return url
}
function buildUrl(url, obj) {
obj = obj || {};
if (url.indexOf("?") < 0) {
url += "?"
}
let param_list = [];
let keys = Object.keys(obj);
keys.forEach(it => {
param_list.push(it + "=" + obj[it])
});
let prs = param_list.join("&");
if (keys.length > 0 && !url.endsWith("?")) {
url += "&"
}
url += prs;
return url
}
function $require(url) {
eval(request(url))
}
function keysToLowerCase(obj) {
return Object.keys(obj).reduce((result, key) => {
const newKey = key.toLowerCase();
result[newKey] = obj[key];
return result
}, {})
}
function buildQueryString(params) {
const queryArray = [];
for (const key in params) {
if (params.hasOwnProperty(key)) {
let value = params[key];
if (value === undefined || value === null) {
value = ""
} else {
value = value.toString()
}
const encodedKey = encodeURIComponent(key);
const encodedValue = encodeURIComponent(value);
queryArray.push(encodedKey + "=" + encodedValue)
}
}
return queryArray.join("&")
}
function parseQueryString(query) {
const params = {};
query.split("&").forEach(function(part) {
const regex = /^(.*?)=(.*)/;
const match = part.match(regex);
if (match) {
const key = decodeURIComponent(match[1]);
const value = decodeURIComponent(match[2]);
params[key] = value
}
});
return params
}
function encodeIfContainsSpecialChars(value) {
const specialChars = ":/?#[]@!$'()*+,;=%";
if (specialChars.split("").some(char => value.includes(char))) {
return encodeURIComponent(value)
}
return value
}
function objectToQueryString(obj) {
const encoded = [];
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
encoded.push(encodeURIComponent(key) + "=" + encodeIfContainsSpecialChars(obj[key]))
}
}
return encoded.join("&")
}
function request(url, obj, ocr_flag) {
ocr_flag = ocr_flag || false;
if (typeof obj === "undefined" || !obj || obj === {}) {
if (!fetch_params || !fetch_params.headers) {
let headers = {
"User-Agent": MOBILE_UA
};
if (rule.headers) {
Object.assign(headers, rule.headers)
}
if (!fetch_params) {
fetch_params = {}
}
fetch_params.headers = headers
}
if (!fetch_params.headers.Referer) {
fetch_params.headers.Referer = getHome(url)
}
obj = fetch_params
} else {
let headers = obj.headers || {};
let keys = Object.keys(headers).map(it => it.toLowerCase());
if (!keys.includes("user-agent")) {
headers["User-Agent"] = MOBILE_UA;
if (typeof fetch_params === "object" && fetch_params && fetch_params.headers) {
let fetch_headers = keysToLowerCase(fetch_params.headers);
if (fetch_headers["user-agent"]) {
headers["User-Agent"] = fetch_headers["user-agent"]
}
}
}
if (!keys.includes("referer")) {
headers["Referer"] = getHome(url)
}
obj.headers = headers
}
if (rule.encoding && rule.encoding !== "utf-8" && !ocr_flag) {
if (!obj.headers.hasOwnProperty("Content-Type") && !obj.headers.hasOwnProperty("content-type")) {
obj.headers["Content-Type"] = "text/html; charset=" + rule.encoding
}
}
if (typeof obj.body != "undefined" && obj.body && typeof obj.body === "string") {
if (!obj.headers.hasOwnProperty("Content-Type") && !obj.headers.hasOwnProperty("content-type")) {
obj.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=" + rule.encoding
}
} else if (typeof obj.body != "undefined" && obj.body && typeof obj.body === "object") {
obj.data = obj.body;
delete obj.body
}
if (!url) {
return obj.withHeaders ? "{}" : ""
}
if (obj.toBase64) {
obj.buffer = 2;
delete obj.toBase64
}
if (obj.redirect === false) {
obj.redirect = 0
}
if (obj.headers.hasOwnProperty("Content-Type") || obj.headers.hasOwnProperty("content-type")) {
let _contentType = obj.headers["Content-Type"] || obj.headers["content-type"] || "";
if (_contentType.includes("application/x-www-form-urlencoded")) {
log("custom body is application/x-www-form-urlencoded");
if (typeof obj.body == "string") {
let temp_obj = parseQueryString(obj.body);
console.log(JSON.stringify(temp_obj))
}
}
}
console.log(JSON.stringify(obj.headers));
console.log("request:" + url + `|method:${obj.method||"GET"}|body:${obj.body||""}`);
let res = req(url, obj);
let html = res.content || "";
if (obj.withHeaders) {
let htmlWithHeaders = res.headers;
htmlWithHeaders.body = html;
return JSON.stringify(htmlWithHeaders)
} else {
return html
}
}
function post(url, obj) {
obj = obj || {};
obj.method = "POST";
return request(url, obj)
}
function reqCookie(url, obj, all_cookie) {
obj = obj || {};
obj.withHeaders = true;
all_cookie = all_cookie || false;
let html = request(url, obj);
let json = JSON.parse(html);
let setCk = Object.keys(json).find(it => it.toLowerCase() === "set-cookie");
let cookie = setCk ? json[setCk] : "";
if (Array.isArray(cookie)) {
cookie = cookie.join(";")
}
if (!all_cookie) {
cookie = cookie.split(";")[0]
}
html = json.body;
return {
cookie: cookie,
html: html
}
}
fetch = request;
print = function(data) {
data = data || "";
if (typeof data == "object" && Object.keys(data).length > 0) {
try {
data = JSON.stringify(data);
console.log(data)
} catch (e) {
console.log(typeof data + ":" + data.length);
return
}
} else if (typeof data == "object" && Object.keys(data).length < 1) {
console.log("null object")
} else {
console.log(data)
}
};
log = print;
function checkHtml(html, url, obj) {
if (/\?btwaf=/.test(html)) {
let btwaf = html.match(/btwaf(.*?)"/)[1];
url = url.split("#")[0] + "?btwaf" + btwaf;
print("宝塔验证访问链接:" + url);
html = request(url, obj)
}
return html
}
function getCode(url, obj) {
let html = request(url, obj);
html = checkHtml(html, url, obj);
return html
}
function getHtml(url) {
let obj = {};
if (rule.headers) {
obj.headers = rule.headers
}
let cookie = getItem(RULE_CK, "");
if (cookie) {
if (obj.headers && !Object.keys(obj.headers).map(it => it.toLowerCase()).includes("cookie")) {
log("历史无cookie,新增过验证后的cookie");
obj.headers["Cookie"] = cookie
} else if (obj.headers && obj.headers.cookie && obj.headers.cookie !== cookie) {
obj.headers["Cookie"] = cookie;
log("历史有小写过期的cookie,更新过验证后的cookie")
} else if (obj.headers && obj.headers.Cookie && obj.headers.Cookie !== cookie) {
obj.headers["Cookie"] = cookie;
log("历史有大写过期的cookie,更新过验证后的cookie")
} else if (!obj.headers) {
obj.headers = {
Cookie: cookie
};
log("历史无headers,更新过验证后的含cookie的headers")
}
}
let html = getCode(url, obj);
return html
}
function homeParse(homeObj) {
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let classes = [];
if (homeObj.class_name && homeObj.class_url) {
let names = homeObj.class_name.split("&");
let urls = homeObj.class_url.split("&");
let cnt = Math.min(names.length, urls.length);
for (let i = 0; i < cnt; i++) {
classes.push({
type_id: urls[i],
type_name: names[i]
})
}
}
if (homeObj.class_parse) {
if (homeObj.class_parse.startsWith("js:")) {
var input = homeObj.MY_URL;
try {
eval(homeObj.class_parse.replace("js:", ""));
if (Array.isArray(input)) {
classes = input
}
} catch (e) {
log(`通过js动态获取分类发生了错误:${e.message}`)
}
} else {
let p = homeObj.class_parse.split(";");
let p0 = p[0];
let _ps = parseTags.getParse(p0);
let is_json = p0.startsWith("json:");
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
MY_URL = rule.url;
if (is_json) {
try {
let cms_cate_url = homeObj.MY_URL.replace("ac=detail", "ac=list");
let html = homeObj.home_html || getHtml(cms_cate_url);
if (html) {
if (cms_cate_url === homeObj.MY_URL) {
homeHtmlCache = html
}
let list = _pdfa(html, p0.replace("json:", ""));
if (list && list.length > 0) {
classes = list
}
}
} catch (e) {
console.log(e.message)
}
} else if (p.length >= 3 && !is_json) {
try {
let html = homeObj.home_html || getHtml(homeObj.MY_URL);
if (html) {
homeHtmlCache = html;
let list = _pdfa(html, p0);
if (list && list.length > 0) {
list.forEach((it, idex) => {
try {
let name = _pdfh(it, p[1]);
if (homeObj.cate_exclude && new RegExp(homeObj.cate_exclude).test(name)) {
return
}
let url = _pd(it, p[2]);
if (p.length > 3 && p[3] && !homeObj.home_html) {
let exp = new RegExp(p[3]);
url = url.match(exp)[1]
}
classes.push({
type_id: url.trim(),
type_name: name.trim()
})
} catch (e) {
console.log(`分类列表定位第${idex}个元素正常报错:${e.message}`)
}
})
}
}
} catch (e) {
console.log(e.message)
}
}
}
}
classes = classes.filter(it => !homeObj.cate_exclude || !new RegExp(homeObj.cate_exclude).test(it.type_name));
let resp = {
class: classes
};
if (homeObj.filter) {
resp.filters = homeObj.filter
}
console.log(JSON.stringify(resp));
return JSON.stringify(resp)
}
function getPP(p, pn, pp, ppn) {
try {
let ps = p[pn] === "*" && pp.length > ppn ? pp[ppn] : p[pn];
return ps
} catch (e) {
return ""
}
}
function homeVodParse(homeVodObj) {
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let d = [];
MY_URL = homeVodObj.homeUrl;
console.log(MY_URL);
let t1 = (new Date).getTime();
let p = homeVodObj.推荐;
print("p:" + p);
if (p === "*" && rule.一级) {
p = rule.一级;
homeVodObj.double = false
}
if (!p || typeof p !== "string") {
return "{}"
}
p = p.trim();
let pp = rule.一级 ? rule.一级.split(";") : [];
if (p.startsWith("js:")) {
const TYPE = "home";
var input = MY_URL;
HOST = rule.host;
eval(p.replace("js:", ""));
d = VODS
} else {
p = p.split(";");
if (!homeVodObj.double && p.length < 5) {
return "{}"
} else if (homeVodObj.double && p.length < 6) {
return "{}"
}
let p0 = getPP(p, 0, pp, 0);
let _ps = parseTags.getParse(p0);
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
let is_json = p0.startsWith("json:");
p0 = p0.replace(/^(jsp:|json:|jq:)/, "");
let html = homeHtmlCache || getHtml(MY_URL);
homeHtmlCache = undefined;
if (is_json) {
html = dealJson(html)
}
try {
console.log("double:" + homeVodObj.double);
if (homeVodObj.double) {
let items = _pdfa(html, p0);
let p1 = getPP(p, 1, pp, 0);
let p2 = getPP(p, 2, pp, 1);
let p3 = getPP(p, 3, pp, 2);
let p4 = getPP(p, 4, pp, 3);
let p5 = getPP(p, 5, pp, 4);
let p6 = getPP(p, 6, pp, 5);
for (let item of items) {
let items2 = _pdfa(item, p1);
for (let item2 of items2) {
try {
let title = _pdfh(item2, p2);
let img = "";
try {
img = _pd(item2, p3)
} catch (e) {}
let desc = "";
try {
desc = _pdfh(item2, p4)
} catch (e) {}
let links = [];
for (let _p5 of p5.split("+")) {
let link = !homeVodObj.detailUrl ? _pd(item2, _p5, MY_URL) : _pdfh(item2, _p5);
links.push(link)
}
let content;
if (p.length > 6 && p[6]) {
content = _pdfh(item2, p6)
} else {
content = ""
}
let vid = links.join("$");
if (rule.二级 === "*") {
vid = vid + "@@" + title + "@@" + img
}
let vod = {
vod_name: title,
vod_pic: img,
vod_remarks: desc,
vod_content: content,
vod_id: vid
};
d.push(vod)
} catch (e) {
console.log(`首页列表双层定位处理发生错误:${e.message}`)
}
}
}
} else {
let items = _pdfa(html, p0);
let p1 = getPP(p, 1, pp, 1);
let p2 = getPP(p, 2, pp, 2);
let p3 = getPP(p, 3, pp, 3);
let p4 = getPP(p, 4, pp, 4);
let p5 = getPP(p, 5, pp, 5);
for (let item of items) {
try {
let title = _pdfh(item, p1);
let img = "";
try {
img = _pd(item, p2, MY_URL)
} catch (e) {}
let desc = "";
try {
desc = _pdfh(item, p3)
} catch (e) {}
let links = [];
for (let _p5 of p4.split("+")) {
let link = !homeVodObj.detailUrl ? _pd(item, _p5, MY_URL) : _pdfh(item, _p5);
links.push(link)
}
let content;
if (p.length > 5 && p[5]) {
content = _pdfh(item, p5)
} else {
content = ""
}
let vid = links.join("$");
if (rule.二级 === "*") {
vid = vid + "@@" + title + "@@" + img
}
let vod = {
vod_name: title,
vod_pic: img,
vod_remarks: desc,
vod_content: content,
vod_id: vid
};
d.push(vod)
} catch (e) {
console.log(`首页列表单层定位处理发生错误:${e.message}`)
}
}
}
} catch (e) {}
}
let t2 = (new Date).getTime();
console.log("加载首页推荐耗时:" + (t2 - t1) + "毫秒");
if (rule.图片替换) {
if (rule.图片替换.startsWith("js:")) {
d.forEach(it => {
try {
var input = it.vod_pic;
eval(rule.图片替换.trim().replace("js:", ""));
it.vod_pic = input
} catch (e) {
log(`图片:${it.vod_pic}替换错误:${e.message}`)
}
})
} else if (rule.图片替换.includes("=>")) {
let replace_from = rule.图片替换.split("=>")[0];
let replace_to = rule.图片替换.split("=>")[1];
d.forEach(it => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic.replace(replace_from, replace_to)
}
})
}
}
if (rule.图片来源) {
d.forEach(it => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic + rule.图片来源
}
})
}
if (d.length > 0) {
print(d.slice(0, 2))
}
return JSON.stringify({
list: d
})
}
function categoryParse(cateObj) {
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let p = cateObj.一级;
if (!p || typeof p !== "string") {
return "{}"
}
let d = [];
let url = cateObj.url.replaceAll("fyclass", cateObj.tid);
if (cateObj.pg === 1 && url.includes("[") && url.includes("]")) {
url = url.split("[")[1].split("]")[0]
} else if (cateObj.pg > 1 && url.includes("[") && url.includes("]")) {
url = url.split("[")[0]
}
if (rule.filter_url) {
if (!/fyfilter/.test(url)) {
if (!url.endsWith("&") && !rule.filter_url.startsWith("&")) {
url += "&"
}
url += rule.filter_url
} else {
url = url.replace("fyfilter", rule.filter_url)
}
url = url.replaceAll("fyclass", cateObj.tid);
let fl = cateObj.filter ? cateObj.extend : {};
if (rule.filter_def && typeof rule.filter_def === "object") {
try {
if (Object.keys(rule.filter_def).length > 0 && rule.filter_def.hasOwnProperty(cateObj.tid)) {
let self_fl_def = rule.filter_def[cateObj.tid];
if (self_fl_def && typeof self_fl_def === "object") {
let fl_def = JSON.parse(JSON.stringify(self_fl_def));
fl = Object.assign(fl_def, fl)
}
}
} catch (e) {
print(`合并不同分类对应的默认筛选出错:${e.message}`)
}
}
let new_url;
new_url = cheerio.jinja2(url, {
fl: fl,
fyclass: cateObj.tid
});
url = new_url
}
if (/fypage/.test(url)) {
if (url.includes("(") && url.includes(")")) {
let url_rep = url.match(/.*?\((.*)\)/)[1];
let cnt_page = url_rep.replaceAll("fypage", cateObj.pg);
let cnt_pg = eval(cnt_page);
url = url.replaceAll(url_rep, cnt_pg).replaceAll("(", "").replaceAll(")", "")
} else {
url = url.replaceAll("fypage", cateObj.pg)
}
}
MY_URL = url;
console.log(MY_URL);
p = p.trim();
const MY_CATE = cateObj.tid;
if (p.startsWith("js:")) {
var MY_FL = cateObj.extend;
const TYPE = "cate";
var input = MY_URL;
const MY_PAGE = cateObj.pg;
var desc = "";
eval(p.trim().replace("js:", ""));
d = VODS
} else {
p = p.split(";");
if (p.length < 5) {
return "{}"
}
let _ps = parseTags.getParse(p[0]);
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
let is_json = p[0].startsWith("json:");
p[0] = p[0].replace(/^(jsp:|json:|jq:)/, "");
try {
let html = getHtml(MY_URL);
if (html) {
if (is_json) {
html = dealJson(html)
}
let list = _pdfa(html, p[0]);
list.forEach(it => {
let links = p[4].split("+").map(p4 => {
return !rule.detailUrl ? _pd(it, p4, MY_URL) : _pdfh(it, p4)
});
let link = links.join("$");
let vod_id = rule.detailUrl ? MY_CATE + "$" + link : link;
let vod_name = _pdfh(it, p[1]).replace(/\n|\t/g, "").trim();
let vod_pic = _pd(it, p[2], MY_URL);
if (rule.二级 === "*") {
vod_id = vod_id + "@@" + vod_name + "@@" + vod_pic
}
d.push({
vod_id: vod_id,
vod_name: vod_name,
vod_pic: vod_pic,
vod_remarks: _pdfh(it, p[3]).replace(/\n|\t/g, "").trim()
})
})
}
} catch (e) {
console.log(e.message)
}
}
if (rule.图片替换) {
if (rule.图片替换.startsWith("js:")) {
d.forEach(it => {
try {
var input = it.vod_pic;
eval(rule.图片替换.trim().replace("js:", ""));
it.vod_pic = input
} catch (e) {
log(`图片:${it.vod_pic}替换错误:${e.message}`)
}
})
} else if (rule.图片替换.includes("=>")) {
let replace_from = rule.图片替换.split("=>")[0];
let replace_to = rule.图片替换.split("=>")[1];
d.forEach(it => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic.replace(replace_from, replace_to)
}
})
}
}
if (rule.图片来源) {
d.forEach(it => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic + rule.图片来源
}
})
}
if (d.length > 0) {
print(d.slice(0, 2))
}
let pagecount = 0;
if (rule.pagecount && typeof rule.pagecount === "object" && rule.pagecount.hasOwnProperty(MY_CATE)) {
print(`MY_CATE:${MY_CATE},pagecount:${JSON.stringify(rule.pagecount)}`);
pagecount = parseInt(rule.pagecount[MY_CATE])
}
let nodata = {
list: [{
vod_name: "无数据,防无限请求",
vod_id: "no_data",
vod_remarks: "不要点,会崩的",
vod_pic: "https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/404.jpg"
}],
total: 1,
pagecount: 1,
page: 1,
limit: 1
};
let vod = d.length < 1 ? JSON.stringify(nodata) : JSON.stringify({
page: parseInt(cateObj.pg),
pagecount: pagecount || 999,
limit: 20,
total: 999,
list: d
});
return vod
}
function searchParse(searchObj) {
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let d = [];
if (!searchObj.searchUrl) {
return "{}"
}
if (rule.searchNoPage && Number(searchObj.pg) > 1) {
return "{}"
}
let p = searchObj.搜索 === "*" && rule.一级 ? rule.一级 : searchObj.搜索;
if (!p || typeof p !== "string") {
return "{}"
}
p = p.trim();
let pp = rule.一级 ? rule.一级.split(";") : [];
let url = searchObj.searchUrl.replaceAll("**", searchObj.wd);
if (searchObj.pg === 1 && url.includes("[") && url.includes("]") && !url.includes("#")) {
url = url.split("[")[1].split("]")[0]
} else if (searchObj.pg > 1 && url.includes("[") && url.includes("]") && !url.includes("#")) {
url = url.split("[")[0]
}
if (/fypage/.test(url)) {
if (url.includes("(") && url.includes(")")) {
let url_rep = url.match(/.*?\((.*)\)/)[1];
let cnt_page = url_rep.replaceAll("fypage", searchObj.pg);
let cnt_pg = eval(cnt_page);
url = url.replaceAll(url_rep, cnt_pg).replaceAll("(", "").replaceAll(")", "")
} else {
url = url.replaceAll("fypage", searchObj.pg)
}
}
MY_URL = url;
console.log(MY_URL);
if (p.startsWith("js:")) {
const TYPE = "search";
const MY_PAGE = searchObj.pg;
const KEY = searchObj.wd;
var input = MY_URL;
var detailUrl = rule.detailUrl || "";
eval(p.trim().replace("js:", ""));
d = VODS
} else {
p = p.split(";");
if (p.length < 5) {
return "{}"
}
let p0 = getPP(p, 0, pp, 0);
let _ps = parseTags.getParse(p0);
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
let is_json = p0.startsWith("json:");
p0 = p0.replace(/^(jsp:|json:|jq:)/, "");
try {
let req_method = MY_URL.split(";").length > 1 ? MY_URL.split(";")[1].toLowerCase() : "get";
let html;
if (req_method === "post") {
let rurls = MY_URL.split(";")[0].split("#");
let rurl = rurls[0];
let params = rurls.length > 1 ? rurls[1] : "";
print(`post=》rurl:${rurl},params:${params}`);
let _fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let postData = {
body: params
};
Object.assign(_fetch_params, postData);
html = post(rurl, _fetch_params)
} else if (req_method === "postjson") {
let rurls = MY_URL.split(";")[0].split("#");
let rurl = rurls[0];
let params = rurls.length > 1 ? rurls[1] : "";
print(`postjson-》rurl:${rurl},params:${params}`);
try {
params = JSON.parse(params)
} catch (e) {
params = "{}"
}
let _fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let postData = {
body: params
};
Object.assign(_fetch_params, postData);
html = post(rurl, _fetch_params)
} else {
html = getHtml(MY_URL)
}
if (html) {
let search_tag = rule.搜索验证标识 || "系统安全验证|输入验证码";
if (new RegExp(search_tag).test(html)) {
let cookie = verifyCode(MY_URL);
if (cookie) {
console.log(`本次成功过验证,cookie:${cookie}`);
setItem(RULE_CK, cookie)
} else {
console.log(`本次自动过搜索验证失败,cookie:${cookie}`)
}
html = getHtml(MY_URL)
}
if (!html.includes(searchObj.wd)) {
console.log("搜索结果源码未包含关键字,疑似搜索失败,正为您打印结果源码");
console.log(html)
}
if (is_json) {
html = dealJson(html)
}
let list = _pdfa(html, p0);
let p1 = getPP(p, 1, pp, 1);
let p2 = getPP(p, 2, pp, 2);
let p3 = getPP(p, 3, pp, 3);
let p4 = getPP(p, 4, pp, 4);
let p5 = getPP(p, 5, pp, 5);
list.forEach(it => {
let links = p4.split("+").map(_p4 => {
return !rule.detailUrl ? _pd(it, _p4, MY_URL) : _pdfh(it, _p4)
});
let link = links.join("$");
let content;
if (p.length > 5 && p[5]) {
content = _pdfh(it, p5)
} else {
content = ""
}
let vod_id = link;
let vod_name = _pdfh(it, p1).replace(/\n|\t/g, "").trim();
let vod_pic = _pd(it, p2, MY_URL);
if (rule.二级 === "*") {
vod_id = vod_id + "@@" + vod_name + "@@" + vod_pic
}
let ob = {
vod_id: vod_id,
vod_name: vod_name,
vod_pic: vod_pic,
vod_remarks: _pdfh(it, p3).replace(/\n|\t/g, "").trim(),
vod_content: content.replace(/\n|\t/g, "").trim()
};
d.push(ob)
})
}
} catch (e) {
print(`搜索发生错误:${e.message}`);
return "{}"
}
}
if (rule.图片替换) {
if (rule.图片替换.startsWith("js:")) {
d.forEach(it => {
try {
var input = it.vod_pic;
eval(rule.图片替换.trim().replace("js:", ""));
it.vod_pic = input
} catch (e) {
log(`图片:${it.vod_pic}替换错误:${e.message}`)
}
})
} else if (rule.图片替换.includes("=>")) {
let replace_from = rule.图片替换.split("=>")[0];
let replace_to = rule.图片替换.split("=>")[1];
d.forEach(it => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic.replace(replace_from, replace_to)
}
})
}
}
if (rule.图片来源) {
d.forEach(it => {
if (it.vod_pic && it.vod_pic.startsWith("http")) {
it.vod_pic = it.vod_pic + rule.图片来源
}
})
}
return JSON.stringify({
page: parseInt(searchObj.pg),
pagecount: 10,
limit: 20,
total: 100,
list: d
})
}
function detailParse(detailObj) {
let t1 = (new Date).getTime();
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
let orId = detailObj.orId;
let vod_name = "片名";
let vod_pic = "";
let vod_id = orId;
if (rule.二级 === "*") {
let extra = orId.split("@@");
vod_name = extra.length > 1 ? extra[1] : vod_name;
vod_pic = extra.length > 2 ? extra[2] : vod_pic
}
let vod = {
vod_id: vod_id,
vod_name: vod_name,
vod_pic: vod_pic,
type_name: "类型",
vod_year: "年份",
vod_area: "地区",
vod_remarks: "更新信息",
vod_actor: "主演",
vod_director: "导演",
vod_content: "简介"
};
let p = detailObj.二级;
let url = detailObj.url;
let detailUrl = detailObj.detailUrl;
let fyclass = detailObj.fyclass;
let tab_exclude = detailObj.tab_exclude;
let html = detailObj.html || "";
MY_URL = url;
if (detailObj.二级访问前) {
try {
print(`尝试在二级访问前执行代码:${detailObj.二级访问前}`);
eval(detailObj.二级访问前.trim().replace("js:", ""))
} catch (e) {
print(`二级访问前执行代码出现错误:${e.message}`)
}
}
if (p === "*") {
vod.vod_play_from = "在线播放";
vod.vod_remarks = detailUrl;
vod.vod_actor = "没有二级,只有一级链接直接嗅探播放";
vod.vod_content = MY_URL;
vod.vod_play_url = "嗅探播放$" + MY_URL.split("@@")[0]
} else if (typeof p === "string" && p.trim().startsWith("js:")) {
const TYPE = "detail";
var input = MY_URL;
var play_url = "";
eval(p.trim().replace("js:", ""));
vod = VOD;
console.log(JSON.stringify(vod))
} else if (p && typeof p === "object") {
let tt1 = (new Date).getTime();
if (!html) {
html = getHtml(MY_URL)
}
print(`二级${MY_URL}仅获取源码耗时:${(new Date).getTime()-tt1}毫秒`);
let _ps;
if (p.is_json) {
print("二级是json");
_ps = parseTags.json;
html = dealJson(html)
} else if (p.is_jsp) {
print("二级是jsp");
_ps = parseTags.jsp
} else if (p.is_jq) {
print("二级是jq");
_ps = parseTags.jq
} else {
print("二级默认jq");
_ps = parseTags.jq
}
let tt2 = (new Date).getTime();
print(`二级${MY_URL}获取并装载源码耗时:${tt2-tt1}毫秒`);
_pdfa = _ps.pdfa;
_pdfh = _ps.pdfh;
_pd = _ps.pd;
if (p.title) {
let p1 = p.title.split(";");
vod.vod_name = _pdfh(html, p1[0]).replace(/\n|\t/g, "").trim();
let type_name = p1.length > 1 ? _pdfh(html, p1[1]).replace(/\n|\t/g, "").replace(/ /g, "").trim() : "";
vod.type_name = type_name || vod.type_name
}
if (p.desc) {
try {
let p1 = p.desc.split(";");
vod.vod_remarks = _pdfh(html, p1[0]).replace(/\n|\t/g, "").trim();
vod.vod_year = p1.length > 1 ? _pdfh(html, p1[1]).replace(/\n|\t/g, "").trim() : "";
vod.vod_area = p1.length > 2 ? _pdfh(html, p1[2]).replace(/\n|\t/g, "").trim() : "";
vod.vod_actor = p1.length > 3 ? _pdfh(html, p1[3]).replace(/\n|\t/g, "").trim() : "";
vod.vod_director = p1.length > 4 ? _pdfh(html, p1[4]).replace(/\n|\t/g, "").trim() : ""
} catch (e) {}
}
if (p.content) {
try {
let p1 = p.content.split(";");
vod.vod_content = _pdfh(html, p1[0]).replace(/\n|\t/g, "").trim()
} catch (e) {}
}
if (p.img) {
try {
let p1 = p.img.split(";");
vod.vod_pic = _pd(html, p1[0], MY_URL)
} catch (e) {}
}
let vod_play_from = "$$$";
let playFrom = [];
if (p.重定向 && p.重定向.startsWith("js:")) {
print("开始执行重定向代码:" + p.重定向);
html = eval(p.重定向.replace("js:", ""))
}
if (p.tabs) {
if (p.tabs.startsWith("js:")) {
print("开始执行tabs代码:" + p.tabs);
var input = MY_URL;
eval(p.tabs.replace("js:", ""));
playFrom = TABS
} else {
let p_tab = p.tabs.split(";")[0];
let vHeader = _pdfa(html, p_tab);
console.log(vHeader.length);
let tab_text = p.tab_text || "body&&Text";
let new_map = {};
for (let v of vHeader) {
let v_title = _pdfh(v, tab_text).trim();
if (!v_title) {
v_title = "线路空"
}
console.log(v_title);
if (tab_exclude && new RegExp(tab_exclude).test(v_title)) {
continue
}
if (!new_map.hasOwnProperty(v_title)) {
new_map[v_title] = 1
} else {
new_map[v_title] += 1
}
if (new_map[v_title] > 1) {
v_title += Number(new_map[v_title] - 1)
}
playFrom.push(v_title)
}
}
console.log(JSON.stringify(playFrom))
} else {
playFrom = ["在线播放"]
}
vod.vod_play_from = playFrom.join(vod_play_from);
let vod_play_url = "$$$";
let vod_tab_list = [];
if (p.lists) {
if (p.lists.startsWith("js:")) {
print("开始执行lists代码:" + p.lists);
try {
var input = MY_URL;
var play_url = "";
eval(p.lists.replace("js:", ""));
for (let i in LISTS) {
if (LISTS.hasOwnProperty(i)) {
try {
LISTS[i] = LISTS[i].map(it => it.split("$").slice(0, 2).join("$"))
} catch (e) {
print(`格式化LISTS发生错误:${e.message}`)
}
}
}
vod_play_url = LISTS.map(it => it.join("#")).join(vod_play_url)
} catch (e) {
print(`js执行lists: 发生错误:${e.message}`)
}
} else {
let list_text = p.list_text || "body&&Text";
let list_url = p.list_url || "a&&href";
let list_url_prefix = p.list_url_prefix || "";
let is_tab_js = p.tabs.trim().startsWith("js:");
for (let i = 0; i < playFrom.length; i++) {
let tab_name = playFrom[i];
let tab_ext = p.tabs.split(";").length > 1 && !is_tab_js ? p.tabs.split(";")[1] : "";
let p1 = p.lists.replaceAll("#idv", tab_name).replaceAll("#id", i);
tab_ext = tab_ext.replaceAll("#idv", tab_name).replaceAll("#id", i);
let tabName = tab_ext ? _pdfh(html, tab_ext) : tab_name;
console.log(tabName);
let new_vod_list = [];
let tt1 = (new Date).getTime();
if (typeof pdfl === "function") {
new_vod_list = pdfl(html, p1, list_text, list_url, MY_URL);
if (list_url_prefix) {
new_vod_list = new_vod_list.map(it => it.split("$")[0] + "$" + list_url_prefix + it.split("$").slice(1).join("$"))
}
} else {
let vodList = [];
try {
vodList = _pdfa(html, p1);
console.log("len(vodList):" + vodList.length)
} catch (e) {}
for (let i = 0; i < vodList.length; i++) {
let it = vodList[i];
new_vod_list.push(_pdfh(it, list_text).trim() + "$" + list_url_prefix + _pd(it, list_url, MY_URL))
}
}
if (new_vod_list.length > 0) {
new_vod_list = forceOrder(new_vod_list, "", x => x.split("$")[0]);
console.log(`drpy影响性能代码共计列表数循环次数:${new_vod_list.length},耗时:${(new Date).getTime()-tt1}毫秒`)
}
let vlist = new_vod_list.join("#");
vod_tab_list.push(vlist)
}
vod_play_url = vod_tab_list.join(vod_play_url)
}
}
vod.vod_play_url = vod_play_url
}
if (rule.图片替换 && rule.图片替换.includes("=>")) {
let replace_from = rule.图片替换.split("=>")[0];
let replace_to = rule.图片替换.split("=>")[1];
vod.vod_pic = vod.vod_pic.replace(replace_from, replace_to)
}
if (rule.图片来源 && vod.vod_pic && vod.vod_pic.startsWith("http")) {
vod.vod_pic = vod.vod_pic + rule.图片来源
}
if (!vod.vod_id || vod_id.includes("$") && vod.vod_id !== vod_id) {
vod.vod_id = vod_id
}
let t2 = (new Date).getTime();
console.log(`加载二级界面${MY_URL}耗时:${t2-t1}毫秒`);
try {
vod = vodDeal(vod)
} catch (e) {
console.log(`vodDeal发生错误:${e.message}`)
}
return JSON.stringify({
list: [vod]
})
}
function get_tab_index(vod) {
let obj = {};
vod.vod_play_from.split("$$$").forEach((it, index) => {
obj[it] = index
});
return obj
}
function vodDeal(vod) {
let vod_play_from = vod.vod_play_from.split("$$$");
let vod_play_url = vod.vod_play_url.split("$$$");
let tab_removed_list = vod_play_from;
let tab_ordered_list = vod_play_from;
let tab_renamed_list = vod_play_from;
let tab_list = vod_play_from;
let play_ordered_list = vod_play_url;
if (rule.tab_remove && rule.tab_remove.length > 0 || rule.tab_order && rule.tab_order.length > 0) {
let tab_index_dict = get_tab_index(vod);
if (rule.tab_remove && rule.tab_remove.length > 0) {
tab_removed_list = vod_play_from.filter(it => !rule.tab_remove.includes(it));
tab_list = tab_removed_list
}
if (rule.tab_order && rule.tab_order.length > 0) {
let tab_order = rule.tab_order;
tab_ordered_list = tab_removed_list.sort((a, b) => {
const getOrderIndex = (tabName, orderRules) => {
for (let i = 0; i < orderRules.length; i++) {
if (tabName.includes(orderRules[i])) {
return i
}
}
return 9999
};
const indexA = getOrderIndex(a, tab_order);
const indexB = getOrderIndex(b, tab_order);
return indexA - indexB
});
tab_list = tab_ordered_list
}
play_ordered_list = tab_list.map(it => vod_play_url[tab_index_dict[it]])
}
if (rule.tab_rename && typeof rule.tab_rename === "object" & Object.keys(rule.tab_rename).length > 0) {
tab_renamed_list = tab_list.map(it => rule.tab_rename[it] || it);
tab_list = tab_renamed_list
}
vod.vod_play_from = tab_list.join("$$$");
vod.vod_play_url = play_ordered_list.join("$$$");
return vod
}
function tellIsJx(url) {
try {
let is_vip = !/\.(m3u8|mp4|m4a)$/.test(url.split("?")[0]) && 是否正版(url);
return is_vip ? 1 : 0
} catch (e) {
return 1
}
}
function playParse(playObj) {
fetch_params = JSON.parse(JSON.stringify(rule_fetch_params));
MY_URL = playObj.url;
var MY_FLAG = playObj.flag;
if (!/http/.test(MY_URL)) {
try {
MY_URL = base64Decode(MY_URL)
} catch (e) {}
}
MY_URL = decodeURIComponent(MY_URL);
var input = MY_URL;
var flag = MY_FLAG;
let common_play = {
parse: SPECIAL_URL.test(input) || /^(push:)/.test(input) ? 0 : 1,
url: input,
flag: flag,
jx: tellIsJx(input)
};
let lazy_play;
if (!rule.play_parse || !rule.lazy) {
lazy_play = common_play
} else if (rule.play_parse && rule.lazy && typeof rule.lazy === "string") {
try {
let lazy_code = rule.lazy.trim();
if (lazy_code.startsWith("js:")) {
lazy_code = lazy_code.replace("js:", "").trim()
}
print("开始执行js免嗅=>" + lazy_code);
eval(lazy_code);
lazy_play = typeof input === "object" ? input : {
parse: SPECIAL_URL.test(input) || /^(push:)/.test(input) ? 0 : 1,
jx: tellIsJx(input),
url: input
}
} catch (e) {
print(`js免嗅错误:${e.message}`);
lazy_play = common_play
}
} else {
lazy_play = common_play
}
if (Array.isArray(rule.play_json) && rule.play_json.length > 0) {
let web_url = lazy_play.url;
for (let pjson of rule.play_json) {
if (pjson.re && (pjson.re === "*" || web_url.match(new RegExp(pjson.re)))) {
if (pjson.json && typeof pjson.json === "object") {
let base_json = pjson.json;
lazy_play = Object.assign(lazy_play, base_json);
break
}
}
}
} else if (rule.play_json && !Array.isArray(rule.play_json)) {
let base_json = {
jx: 1,
parse: 1
};
lazy_play = Object.assign(lazy_play, base_json)
} else if (!rule.play_json) {
let base_json = {
jx: 0,
parse: 1
};
lazy_play = Object.assign(lazy_play, base_json)
}
console.log(JSON.stringify(lazy_play));
return JSON.stringify(lazy_play)
}
function proxyParse(proxyObj) {
var input = proxyObj.params;
if (proxyObj.proxy_rule) {
log("准备执行本地代理规则:\n" + proxyObj.proxy_rule);
try {
eval(proxyObj.proxy_rule);
if (input && input !== proxyObj.params && Array.isArray(input) && input.length >= 3) {
return input
} else {
return [404, "text/plain", "Not Found"]
}
} catch (e) {
return [500, "text/plain", "代理规则错误:" + e.message]
}
} else {
return [404, "text/plain", "Not Found"]
}
}
function isVideoParse(isVideoObj) {
var input = isVideoObj.url;
if (!isVideoObj.t) {
let re_matcher = new RegExp(isVideoObj.isVideo, "i");
return re_matcher.test(input)
} else {
try {
eval(isVideoObj.isVideo);
if (typeof input === "boolean") {
return input
} else {
return false
}
} catch (e) {
log(`执行嗅探规则发生错误:${e.message}`);
return false
}
}
}
function removeHeader(content, options = {}) {
const {
mode = "header-only", fileType
} = options;
const COMMENT_CONFIG = {
".js": {
start: "/*",
end: "*/",
regex: /^\s*\/\*([\s\S]*?)\*\/\s*/,
headerRegex: /@header\(([\s\S]*?)\)/,
topCommentsRegex: /^(\s*(\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)\s*)+/
},
".py": {
start: '"""',
end: '"""',
regex: /^\s*"""([\s\S]*?)"""\s*/,
headerRegex: /@header\(([\s\S]*?)\)/,
topCommentsRegex: /^(\s*(#[^\n]*\n|'''[\s\S]*?'''|"""[\s\S]*?""")\s*)+/
}
};
if (!fileType) throw new Error("fileType option is required");
const ext = fileType.startsWith(".") ? fileType : `.${fileType}`;
const config = COMMENT_CONFIG[ext];
if (!config) throw new Error(`Unsupported file type: ${ext}`);
if (mode === "top-comments") {
const match = content.match(config.topCommentsRegex);
if (match) {
return content.substring(match[0].length).trim()
}
return content.trim()
}
const match = content.match(config.regex);
if (!match) return content.trim();
let [fullComment, innerContent] = match;
if (config.headerRegex.test(innerContent)) {
innerContent = innerContent.replace(config.headerRegex, "");
const cleanedInner = innerContent.split("\n").filter(line => line.trim().length > 0).join("\n");
if (!cleanedInner.trim()) {
return content.replace(fullComment, "").trim()
} else {
const newComment = `${config.start}${cleanedInner}${config.end}`;
return content.replace(fullComment, newComment).trim()
}
}
return content.trim()
}
function getOriginalJs(js_code) {
let current_match = /var rule|function|let |var |const|class Rule|async|this\./;
if (current_match.test(js_code)) {
return js_code
}
js_code = removeHeader(js_code, {
mode: "top-comments",
fileType: ".js"
});
let rsa_private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqin/jUpqM6+fgYP/oMqj9zcdHMM0mEZXLeTyixIJWP53lzJV2N2E3OP6BBpUmq2O1a9aLnTIbADBaTulTNiOnVGoNG58umBnupnbmmF8iARbDp2mTzdMMeEgLdrfXS6Y3VvazKYALP8EhEQykQVarexR78vRq7ltY3quXx7cgI0ROfZz5Sw3UOLQJ+VoWmwIxu9AMEZLVzFDQN93hzuzs3tNyHK6xspBGB7zGbwCg+TKi0JeqPDrXxYUpAz1cQ/MO+Da0WgvkXnvrry8NQROHejdLVOAslgr6vYthH9bKbsGyNY3H+P12kcxo9RAcVveONnZbcMyxjtF5dWblaernAgMBAAECggEAGdEHlSEPFmAr5PKqKrtoi6tYDHXdyHKHC5tZy4YV+Pp+a6gxxAiUJejx1hRqBcWSPYeKne35BM9dgn5JofgjI5SKzVsuGL6bxl3ayAOu+xXRHWM9f0t8NHoM5fdd0zC3g88dX3fb01geY2QSVtcxSJpEOpNH3twgZe6naT2pgiq1S4okpkpldJPo5GYWGKMCHSLnKGyhwS76gF8bTPLoay9Jxk70uv6BDUMlA4ICENjmsYtd3oirWwLwYMEJbSFMlyJvB7hjOjR/4RpT4FPnlSsIpuRtkCYXD4jdhxGlvpXREw97UF2wwnEUnfgiZJ2FT/MWmvGGoaV/CfboLsLZuQKBgQDTNZdJrs8dbijynHZuuRwvXvwC03GDpEJO6c1tbZ1s9wjRyOZjBbQFRjDgFeWs9/T1aNBLUrgsQL9c9nzgUziXjr1Nmu52I0Mwxi13Km/q3mT+aQfdgNdu6ojsI5apQQHnN/9yMhF6sNHg63YOpH+b+1bGRCtr1XubuLlumKKscwKBgQDOtQ2lQjMtwsqJmyiyRLiUOChtvQ5XI7B2mhKCGi8kZ+WEAbNQcmThPesVzW+puER6D4Ar4hgsh9gCeuTaOzbRfZ+RLn3Aksu2WJEzfs6UrGvm6DU1INn0z/tPYRAwPX7sxoZZGxqML/z+/yQdf2DREoPdClcDa2Lmf1KpHdB+vQKBgBXFCVHz7a8n4pqXG/HvrIMJdEpKRwH9lUQS/zSPPtGzaLpOzchZFyQQBwuh1imM6Te+VPHeldMh3VeUpGxux39/m+160adlnRBS7O7CdgSsZZZ/dusS06HAFNraFDZf1/VgJTk9BeYygX+AZYu+0tReBKSs9BjKSVJUqPBIVUQXAoGBAJcZ7J6oVMcXxHxwqoAeEhtvLcaCU9BJK36XQ/5M67ceJ72mjJC6/plUbNukMAMNyyi62gO6I9exearecRpB/OGIhjNXm99Ar59dAM9228X8gGfryLFMkWcO/fNZzb6lxXmJ6b2LPY3KqpMwqRLTAU/zy+ax30eFoWdDHYa4X6e1AoGAfa8asVGOJ8GL9dlWufEeFkDEDKO9ww5GdnpN+wqLwePWqeJhWCHad7bge6SnlylJp5aZXl1+YaBTtOskC4Whq9TP2J+dNIgxsaF5EFZQJr8Xv+lY9lu0CruYOh9nTNF9x3nubxJgaSid/7yRPfAGnsJRiknB5bsrCvgsFQFjJVs=";
let decode_content = "";
function aes_decrypt(data) {
let key = CryptoJS.enc.Hex.parse("686A64686E780A0A0A0A0A0A0A0A0A0A");
let iv = CryptoJS.enc.Hex.parse("647A797964730A0A0A0A0A0A0A0A0A0A");
let encrypted = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(data)
}, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
return encrypted
}
let error_log = false;
function logger(text) {
if (error_log) {
log(text)
}
}
let decode_funcs = [text => {
try {
return ungzip(text)
} catch (e) {
logger("非gzip加密");
return ""
}
}, text => {
try {
return base64Decode(text)
} catch (e) {
logger("非b64加密");
return ""
}
}, text => {
try {
return aes_decrypt(text)
} catch (e) {
logger("非aes加密");
return ""
}
}, text => {
try {
return RSA.decode(text, rsa_private_key, null)
} catch (e) {
logger("非rsa加密");
return ""
}
}];
let func_index = 0;
while (!current_match.test(decode_content)) {
decode_content = decode_funcs[func_index](js_code);
func_index++;
if (func_index >= decode_funcs.length) {
break
}
}
return decode_content
}
function runMain(main_func_code, arg) {
let mainFunc = function() {
return ""
};
try {
eval(main_func_code + "\nmainFunc=main;");
return mainFunc(arg)
} catch (e) {
log(`执行main_funct发生了错误:${e.message}`);
return ""
}
}
function init(ext) {
console.log("init");
rule = {};
rule_fetch_params = {};
fetch_params = null;
try {
let muban = 模板.getMubans();
if (typeof ext == "object") {
rule = ext
} else if (typeof ext == "string") {
let is_file = ext.startsWith("file://");
if (ext.startsWith("http") || is_file) {
let query = getQuery(ext);
if (is_file) {
ext = ext.split("?")[0]
}
let js = request(ext, {
method: "GET"
});
if (js) {
js = getOriginalJs(js);
eval("(function(){" + js.replace("var rule", "rule") + "})()")
}
if (query.type === "url" && query.params) {
if (is_file && /^http/.test(query.params)) {
rule.params = query.params
} else {
rule.params = urljoin(ext, query.params)
}
} else if (query.params) {
rule.params = query.params
}
} else {
ext = getOriginalJs(ext);
eval("(function(){" + ext.replace("var rule", "rule") + "})()")
}
} else {
console.log(`规则加载失败,不支持的规则类型:${typeof ext}`);
return
}
rule.host = (rule.host || "").rstrip("/");
HOST = rule.host;
if (rule.hostJs) {
console.log(`检测到hostJs,准备执行...`);
try {
eval(rule.hostJs);
rule.host = HOST.rstrip("/")
} catch (e) {
console.log(`执行${rule.hostJs}获取host发生错误:${e.message}`)
}
}
if (rule["模板"] === "自动") {
try {
let host_headers = rule["headers"] || {};
let host_html = getCode(HOST, {
headers: host_headers
});
let match_muban = "";
let muban_keys = Object.keys(muban).filter(it => !/默认|短视2|采集1/.test(it));
for (let muban_key of muban_keys) {
try {
let host_data = JSON.parse(home({}, host_html, muban[muban_key].class_parse));
if (host_data.class && host_data.class.length > 0) {
match_muban = muban_key;
console.log(`自动匹配模板:【${muban_key}`);
break
}
} catch (e) {
console.log(`自动匹配模板:【${muban_key}】错误:${e.message}`)
}
}
if (match_muban) {
muban["自动"] = muban[match_muban];
if (rule["模板修改"] && rule["模板修改"].startsWith("js:")) {
eval(rule["模板修改"].replace("js:", "").trim())
}
} else {
delete rule["模板"]
}
} catch (e) {
delete rule["模板"]
}
}
if (rule.模板 && muban.hasOwnProperty(rule.模板)) {
print("继承模板:" + rule.模板);
rule = Object.assign(muban[rule.模板], rule)
}
let rule_cate_excludes = (rule.cate_exclude || "").split("|").filter(it => it.trim());
let rule_tab_excludes = (rule.tab_exclude || "").split("|").filter(it => it.trim());
rule_cate_excludes = rule_cate_excludes.concat(CATE_EXCLUDE.split("|").filter(it => it.trim()));
rule_tab_excludes = rule_tab_excludes.concat(TAB_EXCLUDE.split("|").filter(it => it.trim()));
rule.cate_exclude = rule_cate_excludes.join("|");
rule.tab_exclude = rule_tab_excludes.join("|");
rule.类型 = rule.类型 || "影视";
rule.url = rule.url || "";
rule.double = rule.double || false;
rule.homeUrl = rule.homeUrl || "";
rule.detailUrl = rule.detailUrl || "";
rule.searchUrl = rule.searchUrl || "";
rule.homeUrl = rule.host && rule.homeUrl ? urljoin(rule.host, rule.homeUrl) : rule.homeUrl || rule.host;
rule.homeUrl = cheerio.jinja2(rule.homeUrl, {
rule: rule
});
rule.detailUrl = rule.host && rule.detailUrl ? urljoin(rule.host, rule.detailUrl) : rule.detailUrl;
rule.二级访问前 = rule.二级访问前 || "";
if (rule.url.includes("[") && rule.url.includes("]")) {
let u1 = rule.url.split("[")[0];
let u2 = rule.url.split("[")[1].split("]")[0];
rule.url = rule.host && rule.url ? urljoin(rule.host, u1) + "[" + urljoin(rule.host, u2) + "]" : rule.url
} else {
rule.url = rule.host && rule.url ? urljoin(rule.host, rule.url) : rule.url
}
if (rule.searchUrl.includes("[") && rule.searchUrl.includes("]") && !rule.searchUrl.includes("#")) {
let u1 = rule.searchUrl.split("[")[0];
let u2 = rule.searchUrl.split("[")[1].split("]")[0];
rule.searchUrl = rule.host && rule.searchUrl ? urljoin(rule.host, u1) + "[" + urljoin(rule.host, u2) + "]" : rule.searchUrl
} else {
rule.searchUrl = rule.host && rule.searchUrl ? urljoin(rule.host, rule.searchUrl) : rule.searchUrl
}
rule.timeout = rule.timeout || 5e3;
rule.encoding = rule.编码 || rule.encoding || "utf-8";
rule.search_encoding = rule.搜索编码 || rule.search_encoding || "";
rule.图片来源 = rule.图片来源 || "";
rule.图片替换 = rule.图片替换 || "";
rule.play_json = rule.hasOwnProperty("play_json") ? rule.play_json : [];
rule.pagecount = rule.hasOwnProperty("pagecount") ? rule.pagecount : {};
rule.proxy_rule = rule.hasOwnProperty("proxy_rule") ? rule.proxy_rule : "";
if (!rule.hasOwnProperty("sniffer")) {
rule.sniffer = false
}
rule.sniffer = rule.hasOwnProperty("sniffer") ? rule.sniffer : "";
rule.sniffer = !!(rule.sniffer && rule.sniffer !== "0" && rule.sniffer !== "false");
rule.isVideo = rule.hasOwnProperty("isVideo") ? rule.isVideo : "";
if (rule.sniffer && !rule.isVideo) {
rule.isVideo = "http((?!http).){12,}?\\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)|http((?!http).)*?video/tos*|http((?!http).)*?obj/tos*"
}
rule.tab_remove = rule.hasOwnProperty("tab_remove") ? rule.tab_remove : [];
rule.tab_order = rule.hasOwnProperty("tab_order") ? rule.tab_order : [];
rule.tab_rename = rule.hasOwnProperty("tab_rename") ? rule.tab_rename : {};
if (rule.headers && typeof rule.headers === "object") {
try {
let header_keys = Object.keys(rule.headers);
for (let k of header_keys) {
if (k.toLowerCase() === "user-agent") {
let v = rule.headers[k];
console.log(v);
if (["MOBILE_UA", "PC_UA", "UC_UA", "IOS_UA", "UA"].includes(v)) {
rule.headers[k] = eval(v)
}
} else if (k.toLowerCase() === "cookie") {
let v = rule.headers[k];
if (v && v.startsWith("http")) {
console.log(v);
try {
v = fetch(v);
console.log(v);
rule.headers[k] = v
} catch (e) {
console.log(`${v}获取cookie发生错误:${e.message}`)
}
}
}
}
} catch (e) {
console.log(`处理headers发生错误:${e.message}`)
}
} else {
rule.headers = {}
}
oheaders = deepCopy(rule.headers);
rule_fetch_params = {
headers: rule.headers,
timeout: rule.timeout,
encoding: rule.encoding
};
RKEY = typeof key !== "undefined" && key ? key : "drpy_" + (rule.title || rule.host);
pre();
init_test()
} catch (e) {
console.log(`init_test发生错误:${e.message}`)
}
}
let homeHtmlCache = undefined;
function home(filter, home_html, class_parse) {
console.log("home");
home_html = home_html || "";
class_parse = class_parse || "";
if (typeof rule.filter === "string" && rule.filter.trim().length > 0) {
try {
let filter_json = ungzip(rule.filter.trim());
rule.filter = JSON.parse(filter_json)
} catch (e) {
rule.filter = {}
}
}
let homeObj = {
filter: rule.filter || false,
MY_URL: rule.homeUrl,
class_name: rule.class_name || "",
class_url: rule.class_url || "",
class_parse: class_parse || rule.class_parse || "",
cate_exclude: rule.cate_exclude,
home_html: home_html
};
return homeParse(homeObj)
}
function homeVod(params) {
console.log("homeVod");
let homeVodObj = {
"推荐": rule.推荐,
double: rule.double,
homeUrl: rule.homeUrl,
detailUrl: rule.detailUrl
};
return homeVodParse(homeVodObj)
}
function category(tid, pg, filter, extend) {
let cateObj = {
url: rule.url,
"一级": rule.一级,
tid: tid,
pg: parseInt(pg),
filter: filter,
extend: extend
};
return categoryParse(cateObj)
}
function detail(vod_url) {
let orId = vod_url;
let fyclass = "";
log("orId:" + orId);
if (vod_url.indexOf("$") > -1) {
let tmp = vod_url.split("$");
fyclass = tmp[0];
vod_url = tmp[1]
}
let detailUrl = vod_url.split("@@")[0];
let url;
if (!detailUrl.startsWith("http") && !detailUrl.includes("/")) {
url = rule.detailUrl.replaceAll("fyid", detailUrl).replaceAll("fyclass", fyclass)
} else if (detailUrl.includes("/")) {
url = urljoin(rule.homeUrl, detailUrl)
} else {
url = detailUrl
}
let detailObj = {
orId: orId,
url: url,
"二级": rule.二级,
"二级访问前": rule.二级访问前,
detailUrl: detailUrl,
fyclass: fyclass,
tab_exclude: rule.tab_exclude
};
return detailParse(detailObj)
}
function play(flag, id, flags) {
let playObj = {
url: id,
flag: flag,
flags: flags
};
return playParse(playObj)
}
function search(wd, quick, pg) {
if (rule.search_encoding) {
if (rule.search_encoding.toLowerCase() !== "utf-8") {
wd = encodeStr(wd, rule.search_encoding)
}
} else if (rule.encoding && rule.encoding.toLowerCase() !== "utf-8") {
wd = encodeStr(wd, rule.encoding)
}
let searchObj = {
searchUrl: rule.searchUrl,
"搜索": rule.搜索,
wd: wd,
pg: pg || 1,
quick: quick
};
return searchParse(searchObj)
}
function proxy(params) {
if (rule.proxy_rule && rule.proxy_rule.trim()) {
rule.proxy_rule = rule.proxy_rule.trim()
}
if (rule.proxy_rule.startsWith("js:")) {
rule.proxy_rule = rule.proxy_rule.replace("js:", "")
}
let proxyObj = {
params: params,
proxy_rule: rule.proxy_rule
};
return proxyParse(proxyObj)
}
function sniffer() {
let enable_sniffer = rule.sniffer || false;
if (enable_sniffer) {
log("开始执行辅助嗅探代理规则...")
}
return enable_sniffer
}
function isVideo(url) {
let t = 0;
let is_video;
if (rule.isVideo && rule.isVideo.trim()) {
is_video = rule.isVideo.trim()
}
if (is_video.startsWith("js:")) {
is_video = is_video.replace("js:", "");
t = 1
}
let isVideoObj = {
url: url,
isVideo: is_video,
t: t
};
let result = isVideoParse(isVideoObj);
if (result) {
log("成功执行辅助嗅探规则并检测到视频地址:\n" + rule.isVideo)
}
return result
}
function getRule(key) {
return key ? rule[key] || "" : rule
}
function deepCopy(_obj) {
return JSON.parse(JSON.stringify(_obj))
}
function matchesAll(str, pattern, flatten) {
if (!pattern.global) {
pattern = new RegExp(pattern.source, "g" + (pattern.ignoreCase ? "i" : "") + (pattern.multiline ? "m" : ""))
}
var matches = [];
var match;
while ((match = pattern.exec(str)) !== null) {
matches.push(match)
}
return flatten ? matches.flat() : matches
}
function stringUtils() {
Object.defineProperties(String.prototype, {
replaceX: {
value: function(regex, replacement) {
let matches = matchesAll(this, regex, true);
if (matches && matches.length > 1) {
const hasCaptureGroup = /\$\d/.test(replacement);
if (hasCaptureGroup) {
return this.replace(regex, m => m.replace(regex, replacement))
} else {
return this.replace(regex, (m, p1) => m.replace(p1, replacement))
}
}
return this.replace(regex, replacement)
},
configurable: true,
enumerable: false,
writable: true
},
parseX: {
get: function() {
try {
return JSON.parse(this)
} catch (e) {
console.log(e.message);
return this.startsWith("[") ? [] : {}
}
},
configurable: true,
enumerable: false
}
})
}
function cut(text, start, end, method, All) {
let result = "";
let c = (t, s, e) => {
let result = "";
let rs = [];
let results = [];
try {
let lr = new RegExp(String.raw`${s}`.toString());
let rr = new RegExp(String.raw`${e}`.toString());
const segments = t.split(lr);
if (segments.length < 2) return "";
let cutSegments = segments.slice(1).map(segment => {
let splitSegment = segment.split(rr);
return splitSegment.length < 2 ? undefined : splitSegment[0] + e
}).filter(f => f);
if (All) {
return `[${cutSegments.join(",")}]`
} else {
return cutSegments[0]
}
} catch (e) {
console.log(`Error cutting text:${e.message}`)
}
return result
};
result = c(text, start, end);
stringUtils();
if (method && typeof method === "function") {
result = method(result)
}
return result
}
function DRPY() {
return {
runMain: runMain,
getRule: getRule,
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy,
sniffer: sniffer,
isVideo: isVideo,
fixAdM3u8Ai: fixAdM3u8Ai
}
}
export default {
runMain: runMain,
getRule: getRule,
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
proxy: proxy,
sniffer: sniffer,
isVideo: isVideo,
fixAdM3u8Ai: fixAdM3u8Ai,
DRPY: DRPY
};
Binary file not shown.

Before

Width:  |  Height:  |  Ukuran: 1.2 MiB

-1
Melihat File
@@ -1 +0,0 @@
__pus=12fd6f406097e6ad7b59ce2b94da18e1AATYn5CsxNOBdy5gdD9AOGUj+hyODyKfX5CYOF7FT/2msT18L+WvAzPTEdh29MVktlv2eMnFu29JO2hYkHt/L1/R;
-1
Melihat File
@@ -1 +0,0 @@
__pus=4f5424234020f4d43638b7bbb501c2dfAAQ6EjxrmDHiJwB8cjYO7BHkLaCtyfWI9OYlpVEaREgU/9PscMnx2yuInMi2orkAAh/BLE8vlrD3Nn7xMoG2D2TG;
@@ -1,169 +0,0 @@
var rule = {
title: '优酷[官]',
host: 'https://www.%79%6f%75%6b%75.com',
homeUrl: '',
searchUrl: 'https://search.%79%6f%75%6b%75.com/api/search?pg=fypage&keyword=**',
searchable: 2,
quickSearch: 0,
filterable: 1,
multi: 1,
url: '/category/data?optionRefresh=1&pageNo=fypage&params=fyfilter',
filter_url: '{{fl}}',
filter: 'H4sIAAAAAAAAA+1cW28bu7X+K4Uf+lIFsHJ3Hw7Q3d1TbODgtA9FgYODDUNJdLKNJs6u46RIiw3IF9nyRfJNtiVLjnyRLd9081UaWdKfGXJm/sXhDMm1SElWnGxnuwECGE6+tTgccpFc6+Mix//qseJndm6CTOV6fvu//+r5W/Bdz297XgYGBvsDQ8FAj69nMPAyyEQkvOeM7ZF0icwaTPo28OJN0HtisIOSiXp+8gndRNhVsPq5wqzkSarOpVCIVoqtJZzdJJNiNXPtdcyVaLUBJZzMPpZwQaoOOqsRQ50LFJ09U0adCxQdXd1BHQM0fYS6E6VFLnCf+97VciMOB56/brWfVa6R9zNX2A+Vqv2c9UWa2JHd4gCNkrW3w0InAHQ5UqZjUicA1DlWJ5VRWScHUOdKGrvFgY/Ov7eOFrDnkYRpTMmec4DDnaKr0CQOwNKlKCstLc0BPDdyTsbm5HMcwHP5XTJ7IJ/jAN+36CT34X0eABPsN+3zaWkCDqTOrCXNxoacTxxA//K7qBMAdKNH1sqC1HEA76sf0M2IfB8H0M7COTHysp0cgC42QeaOpY4D0FVPzdq21HGAfU/T9QXouwfUGfguGBhqW8FuFfWrVjAo1Rl4t/fufSHz/qvI76H8niq/i/K7qtyPcr8q70V5ryL394Gc/VeRP0b5Y1X+COWPVPlDlD9U5Q9Q/kCV37/DfmFj/X4XY89p6pSuyknnqno1u78eDgy/aVv7dm6cblxeYXlUar4zvGfVF6yZI7oopw6azbxMOOELe/KARM5lS/HJi2NSmLVqS0KDo0OiJ6Q0YVamLaMplNgxK5PHxf9A69SPgXf9w+9+DGK3zFrCPq1e4dJalXq3okwnpDjef/3uz2394NVg31UrvxoaxsZYtUsyH6GxRWLMtTWmVak2xhrLE2OXpkPOoXRNOHWYmK6UNGP5VSXZqdvF8TYbu5rsGhs0Gm9gl77/6XufG25JvfxZY223QKvF1i7hVouwXYKuiKUdAyuJlphlpXviQAmsLERrwdrXIb5C1TK+St1Rjp5KjynAZ4i914iFZHrPrKdlEQ6glaEDEoYecHCdGNotdHeLP93iFtmZJNWabCcH8L7cAuoEuE587RqXp/eseA3t4gJo59g0HV2T7eQA2jJdZJFTtoUDeG5knoZW5HMcwPumcmgzAa4TXy3jgNSXralJ+UrA6Gc37AIsKg7Q4rN25D1Y3AOKL1Wq5QA94LlZkz0RQPdtb4aeBltn8CdEECe51cl1uVGllha+qNUPa/EGXTHzj7QSNpsFko22eTx/7+Ne6b3vfyUhN0dCsFH+Xp2E3O3t7WOSXizR65boxTb29Wrs0d/X13uH/cICj1sLPHYLPMYCj1oLPHILPMICOhPy9z3s+4VJg3m5RhYSbZPVGq1qnOmX5w0dCMAnkgo9rvW/CDwJvuj3mo9WrRhmfYPG9uzofLtVW5SafzhMkMgEaYattLS4JsJYvkKMnOYwNBGUK83ZxVMar1qX4N5UEbx3acTeDFmbR7Qsg6AmghCTm6DLEZLNoSvVRGC2y0MWYbT3aiIYtdo6o0O0PGrFM9I1qyIol86YhuH9ntFq7aCAts6OmZeyVgGgvpFDKzJB3x/gBlgTgf3qZRadrNocCVek/VQR9HemSJcXzMqKtTwr+6uKkMdN2rOSnggAY7B/REPrliGJIGJodWzGbE6TSVkCMfS5fECiMSdxRgpybWoiaO96zIoB3eEAueAGiSVI9lSjW61SeON52B6rk+mUfB1gJIdb7Bk6n6eb0nFpIkHEa5f2lHHLRPznEWyRrBJ2EJmrz8CCu6VmIu/tqkx5CADzK3NiVqXHEQApYJiOy7UiwEewbrO+ZI9KRicAVF2p0IhsrgBgzVSFbMtxEQBeu79GR2TnBcApek5KwFg5AF1yjQUhqeMAdIkYTWTsQtMuSSNpIuiPcUzy0lQCQJvjGXoK7JwDqH9lksyCw+NAmTnOdgZnjguwP2FmGeiPB9BG0zRpgI088JXQ3Rihu/2sUtfEEVdekXLiZwXCc3IldvxjU05fUG6pherpHLGdB7YwPXdcV6TTeawq7eYCuQyhpftUJSOQjAbaBaOjyW6cCTLnzUKPdfieXsbRn6MIDBxJOKk9mliWnhKwyhoqIRKVPhExRoZ9Yki1AApToFNNZ0khCwJj6uSCZFfcZk2HZCFVBOXOkrScIdFDNmdlOVWEoThNV6paOU0EPT8+MY0FpwqhELDSc7sZxm67APu1ZzcPoFMeUHWMxsBZBWKwWG3cCxyyBGIoMZY3jSNnW2YjECMvyjmJE7KXZj/AixQR9LNxwfplZSUvQYzvWqAjBrzIA7jYY6QEhxIcKG1klVnGMbZRYJiFpw0rJtUCcL5GpvcYo1f42g3t4z60Vbs6xdthE6cs0F+WTorcqQzoWiK1G4W8Lg39UMLqhqgmc6ZsDyib6gEf2x7RlVVsyXSZNFdlSzjA9TeuJDI5gOfmss52TD7nJQF9QgZGHJmxInJ7KwBM3S7HsHRjk6SkDxcAJnRzns1c2aRsg6S2fEIGrf7E9KuTj9MT6YYFUOYDUQieB0B3XKPjQEc5wGlt4A5VANDF9qx58KQc4MrucqIsEwCyG50SApyoYyHAWiG5pZeFOm3xXUcRGnF9hZwjAqspaGuqShfkqhYAKqiM2VszuIdArM74p69e/vgiOBx8htPebr6363W2myETZ23TvlWp+SCPIbCF18ZbWkmV/5bTa1/3AT03sA9AudpfP/bXr/bXj/31q/3VthIg79VTtiIr7O/VJpuasu3r+7zE8t632lkQQGiPt7XXHZYqghmazVnxC7MCh0qAwQkdJqzJMemEOAA/PD9rnchHBYBJ3ixYablTFgBaFwrRVchJcQB1noctI2fPlJ2UdCWaCOoondKNBbITYT+yJlUEPbzcoOsyzAsADitzYsVLpA7JC8DwdCFCp7OMFFjz0gaaCMqlJ+zShSzBAejKZdyqCID2j5q1STC+B0BnZGjm1AlN2Ftwx0UVgaUbuzS2JS3NAYYskfCDqCWxEoNZm0hkjSZk0lMTQU2dzkg5iSwtkPHmZ0r6ceKksSgfP1b3/dyknsbCXHZWkDv3ToeHP7z6h1jCenD49Axgl8NcZk+al8MhAPKxfRKWU00AvU7tRKHlLMGqJRiNpcth05At0kRQzkvJyxIcIPdwB1zLWGgiGLsuCTg2Sa3TLfdguABHvaoId7UnzpacdgJojOGHgRfP+jsxZRKZYIa/arKBUh2Sjlm6a5BGUq07NRnQBVDInxWHWxUc4NQ7Yq5Wo5xc5GthnqaRdUJr5GIHR14TIdmedxpJINseUOfG1L4y36aUDnTh/2RuRrkEwAFmDbxthHifvqfoRuBpftusQjKCgy7blWuxeutwxy6uSx0HHTcMLTsFs7JET/bw7AMxWCCSckIbWAIx9GfsxC5vYgnESstpsoAtdwE+HSbLsAfgAEPlulVjHr9mN8D5qiKcSqf2+TbJVEkYfIoqAksU83QFTv04ULwkk6CXdAG0Y7lE8vLekQBYZ8Pam7EbYVK8hJoVkbpeA8/bfCejVk5j/Gp+K5TqQmXsixyPSGJ9BwncvTv3UcEAKB7ceYgKBkDxiInN2o5ZkVmgR3d+6e1AS8pUiLXs6s0ftX/wwLxr/qY9jao/GT+3V+UrH8jDQbgFhFThplIcXY5l7MkDa1xGdgFgRLpcYmLhCB2+ABgMUhg/BUBfbaCfFQDp5CQpSP8sAHqZBUbewMV4APqXbeBxmACqZ4GcrQBI/zocSbXstwOD79pW5KRBlkauWpGgVEfgm29+L0RPnjz1PRkaGB54/YNCcwuYB+bA55K5bEF8KTFX8j19OvzWJ/Jk1Sabe5y58AL29KiVKrCYRxNLbpmmQr095ubxcXiDKpLl/uvV2+Cv/jsw/GYoKIq9cCWDXAKl/vgdaF/9bWDwOWh+9+s/CE0Ai//pL/8phP8XHHwa/LqXv5m9/M8607vVBM4NHXJ18NxKsuFnXaDu5JrFKfeN+2W7FEFOJgDoxstkbtvKSdeFGEqoR/wth/t24ZgYORaByDpcWlFFyFDnaOqY/eBehYt8QgYVeudyykdLgKEqZiSkQByoTgh0AkDNUwZNy9s+AsBzmapdyHO2JJ9WRTh2U2S7ZFbh9YC1mR989eMLZd7zYSXZHFlcaRu3VqU2/Q52mZqeS9Mihn3Z/hFNHzhj0l0hhjqSdXK8T9clgUAMndoK06LcWQgA9ScjzvGIXZYJZ8Tw9N60lZRcVwB4d32VzhZZgJXvBgyDsjhDV6p2BK6WAdbzAsCl2zICX937V/f+hbh3kXtB9/73gcF/DvQ/Dw4O3UgmK79sGnC3jANYZ6PHbmIow7bjkp2pIh8HdqPBmLIAbAPO2JvPilTYDxf5nLW4WdsWgP/D73xhI3bqjGlbuagdhcRCMUr2T634HuOrPno2w6zmU2WicMdNhNvCwx0u8rF9rPsP6xpNZ5ydgnbra2qGXOx8+93/yJd6+NnAO2XrnGQttnOjpCkPqTQRbhzcUdLSappIL2cai5jS4CJO8H0CeGd9AjiJsF2s+Xi20MdWF2uAj8wX7UXcf9jzs2RPJrkFgC7wm4Ki8fq1QTfVuivHVgBtvQ4Fnw8GBp++63893GH37yTOaaH9ZK9Vqc23LIu9kDDjQJmLbvfg5IFjbapW8praPSFUn06u6U8n165KBD8JPHnX3ymhEZnoktAAZY+W0PCrCQ1c7/4791DBgJLpeKhmOtDxuuLfCPnDD+UyeJuuaOpHuUtN+W/oND8mnXE9zuyt4ZvnzCR8RC5DjP8B9ZAYSsxHmbdkv0lCnutoIpWwXnWRtRspNS932cZZyzloIhiQ+Qnm6uTK5+A6mRW2e3dLI18GjEM9R8/kvRIBQFfY1J5GjP5hBfOYAoBNTpZJQ9pcANxTbFqFVZqW0wAx1Lx0rDSbA3h6ZNasrHH2LitQRZgDcr9TF7NH1KSKPk9+5i9/+FaI3NsV0ObQOWPV7h4AeqWJsN8Rs57SymkinHFFsr5r7c5pRVulwPGNmpUe4ROHyZ2kPMTsoLiOG+NJoivMgsrruLTbSsl+yE21eqLrsMKOV+pcB8bjODqwZwNvB14PvBpstatLyK48tkWl2hX100VsjHYD+mHnQXhwK5b9aOOJbwZu33g4J+9/0QYVH5x8cQa9qROMYgGvmAgAXvr8BHUCQMvm1Kspc9qllN9/8zuhcP8HXndxySnLczoBvogZIr52uv0Z0mU2fOarLy26D18xvu6fpuj6Jyc+kAh7+eb1wNN+b190Q1dj6GWcxMvKB2CAZYkXA2+DVqxEgKspApjoWyNkZ4WEK1YWprsqguXV5XM7Ui+7x1OxDH7hpongXd7c5GkM+S5VpJdjTA/ZkSbSy7X+HYVWqV765VutGIMtrVM/TtJEX8TyF18d3v7y/8gA8Zy1rf/JUGDwWWtDP4Gvut+/hMJ2dNsOwZGvKoL2LM6S6ol13LBn4NNyVYQbret9um03L8z6hvZptCaC8YssWGvj+ifUqgjKZaPW1D7bD9BIgoydkRIcUrcrcHPh5udZq0g+YTdT6ta2TQH9OzoyjThbgfjJniaCcrOHzD52aMS5lH/rRRPBStple7QNetogRTnamgjq8/4wmvs1OsxjTQR29S612iNxKwUnEaroMzAN+2zcLsDOnwPQ5bbtoswpCIChpIarQQAYmuOklVqUw8EBmKLLpTo+ZlLHAerO3Nyn+kWaJoKpHl1mW3S3QRAMNBHUx//IAJw3IoaautzItFIJa7QKvfAA9J5/VqFlW1SRXk5b2JoIRqE4Ts/kuAkAbSyNk0loIwfQxjxbY5CP4QCe63Z9MXpCV8/ZgsOnNRGW27Sm4FYqBzhzFu2pYzpVUL509ET/IWRfQIz56f8BvNNeN7lTAAA=',
headers: {
'User-Agent': 'PC_UA',
'Cookie': 'cna=VvNvGX3e0ywCAavVEXlnA2bg; __ysuid=1626676228345Rl1; __ayft=1652434048647; __arycid=dm-1-00; __arcms=dm-1-00; __ayvstp=85; __arpvid=1667204023100cWWdgM-1667204023112; __ayscnt=10; __aypstp=60; isg=BBwcqxvvk3BxkWQGugbLpUSf7TrOlcC_U7GAj_YdfYfvQbzLHqYGT4Hgp6m5TvgX; tfstk=c3JOByYUH20ilVucLOhh0pCtE40lZfGc-PjLHLLfuX7SWNyAiQvkeMBsIw7PWDC..; l=eBQguS-PjdJFGJT-BOfwourza77OSIRA_uPzaNbMiOCPOb1B5UxfW6yHp4T6C3GVhsGJR3rp2umHBeYBqQd-nxvOF8qmSVDmn',
'Referer': 'https://www.youku.com',
},
timeout: 5000,
class_name: '电视剧&电影&综艺&动漫&少儿&纪录片&文化&亲子&教育&搞笑&生活&体育&音乐&游戏',
class_url: '电视剧&电影&综艺&动漫&少儿&纪录片&文化&亲子&教育&搞笑&生活&体育&音乐&游戏',
limit: 20,
//play_parse: true,
lazy:'js:input=""+input.split("?")[0];log(input);let html=JSON.parse(request(input));log(html);input=html.url||input',
一级: $js.toString(() => {
let d = [];
MY_FL.type = MY_CATE;
let fl = stringify(MY_FL);
fl = encodeUrl(fl);
input = input.split("{")[0] + fl;
if (MY_PAGE > 1) {
let old_session = getItem("yk_session_" + MY_CATE, "{}");
if (MY_PAGE === 2) {
input = input.replace("optionRefresh=1", "session=" + encodeUrl(old_session))
} else {
input = input.replace("optionRefresh=1", "session=" + encodeUrl(old_session))
}
}
let html = fetch(input, fetch_params);
try {
html = JSON.parse(html);
let lists = html.data.filterData.listData;
let session = html.data.filterData.session;
session = stringify(session);
if (session !== getItem("yk_session_" + MY_CATE, "{}")) {
setItem("yk_session_" + MY_CATE, session)
}
lists.forEach(function (it) {
let vid;
if (it.videoLink.includes("id_")) {
vid = it.videoLink.split("id_")[1].split(".html")[0]
} else {
vid = "msearch:"
}
d.push({
title: it.title,
img: it.img,
desc: it.summary,
url: "https://search.youku.com/api/search?appScene=show_episode&showIds=" + vid,
content: it.subTitle
})
})
} catch (e) {
log("一级列表解析发生错误:" + e.message)
}
setResult(d);
}),
二级: $js.toString(() => {
var d = [];
VOD = {};
let html = request(input);
let json = JSON.parse(html);
if (/keyword/.test(input)) {
input = "https://search.youku.com/api/search?appScene=show_episode&showIds=" + json.pageComponentList[0].commonData.showId;
json = JSON.parse(fetch(MY_URL, fetch_params))
}
let video_lists = json.serisesList;
var name = json.sourceName;
if (/优酷/.test(name) && video_lists.length > 0) {
let ourl = "https://v.youku.com/v_show/id_" + video_lists[0].videoId + ".html";
let _img = video_lists[0].thumbUrl;
let html = fetch(ourl, {
headers: {
Referer: "https://v.youku.com/",
"User-Agent": PC_UA
}
});
let json = /__INITIAL_DATA__/.test(html) ? html.split("window.__INITIAL_DATA__ =")[1].split(";")[0] : "{}";
if (json === "{}") {
log("触发了优酷人机验证");
VOD.vod_remarks = ourl;
VOD.vod_pic = _img;
VOD.vod_name = video_lists[0].title.replace(/(\d+)/g, "");
VOD.vod_content = "触发了优酷人机验证,本次未获取详情,但不影响播放(" + ourl + ")"
} else {
try {
json = JSON.parse(json);
let data = json.data.data;
let data_extra = data.data.extra;
let img = data_extra.showImgV;
let model = json.data.model;
let m = model.detail.data.nodes[0].nodes[0].nodes[0].data;
let _type = m.showGenre;
let _desc = m.updateInfo || m.subtitle;
let JJ = m.desc;
let _title = m.introTitle;
VOD.vod_pic = img;
VOD.vod_name = _title;
VOD.vod_type = _type;
VOD.vod_remarks = _desc;
VOD.vod_content = JJ
} catch (e) {
log("海报渲染发生错误:" + e.message);
print(json);
VOD.vod_remarks = name
}
}
}
if (!/优酷/.test(name)) {
VOD.vod_content = "非自家播放源,暂无视频简介及海报";
VOD.vod_remarks = name
}
function adhead(url) {
return urlencode(url)
}
play_url = play_url.replace("&play_url=", "&type=json&play_url=");
video_lists.forEach(function (it) {
let url = "https://v.youku.com/v_show/id_" + it.videoId + ".html";
if (it.thumbUrl) {
d.push({
desc: it.showVideoStage ? it.showVideoStage.replace("期", "集") : it.displayName,
pic_url: it.thumbUrl,
title: it.title,
url: play_url + adhead(url)
})
} else if (name !== "优酷") {
d.push({
title: it.displayName ? it.displayName : it.title,
url: play_url + adhead(it.url)
})
}
});
VOD.vod_play_from = name;
VOD.vod_play_url = d.map(function (it) {
return it.title + "$" + it.url
})
.join("#");
}),
搜索: $js.toString(() => {
var d = [];
let html = request(input);
let json = JSON.parse(html);
json.pageComponentList.forEach(function (it) {
if (it.hasOwnProperty("commonData")) {
it = it.commonData;
d.push({
title: it.titleDTO.displayName,
img: it.posterDTO.vThumbUrl,
desc: it.stripeBottom,
content: it.updateNotice + " " + it.feature,
url: "https://search.youku.com/api/search?appScene=show_episode&showIds=" + it.showId + "&appCaller=h5"
})
}
});
setResult(d)
}),
}
@@ -1,116 +0,0 @@
/**
* 影视TV 弹幕支持
* https://t.me/fongmi_offical/
* https://github.com/FongMi/Release/tree/main/apk
* Cookie设置
* Cookie获取方法 https://ghproxy.net/https://raw.githubusercontent.com/UndCover/PyramidStore/main/list.md
* Cookie设置方法1: DR-PY 后台管理界面
* CMS后台管理 > 设置中心 > 环境变量 > {"bili_cookie":"XXXXXXX","vmid":"XXXXXX"} > 保存
* Cookie设置方法2: 手动替换Cookie
* 底下代码 headers的
* "Cookie":"$bili_cookie"
* 手动替换为
* "Cookie":"将获取的Cookie黏贴在这"
* 客户端长期Cookie设置教程:
* 抓包哔哩手机端搜索access_key,取任意链接里的access_key和appkey在drpy环境变量中增加同名的环境变量即可
* 此时哔哩.js这个解析可用于此源的解析线路用
*/
var rule = {
title:'bili',
host:'https://api.bilibili.com',
url:'/fyclass-fypage&vmid=$vmid',
detailUrl:'/pgc/view/web/season?season_id=fyid',
filter_url:'fl={{fl}}',
vmid获取教程:'登录后访问https://api.bilibili.com/x/web-interface/nav,搜索mid就是,cookie需要 bili_jct,DedeUserID,SESSDATA参数',
searchUrl:'/x/web-interface/search/type?keyword=**&page=fypage&search_type=',
searchable:1,
filterable:1,
quickSearch:0,
headers:{
'User-Agent':'PC_UA',
"Referer": "https://www.bilibili.com",
"Cookie":""
},
tab_order:['bilibili','720P'],//线路顺序,按里面的顺序优先,没写的依次排后面
timeout:5000,
class_name:'番剧&国创&电影&电视剧&纪录片&综艺&全部&追番&追剧&时间表',
class_url:'1&4&2&5&3&7&全部&追番&追剧&时间表',
filter:{"全部":[{"key":"tid","name":"分类","value":[{"n":"番剧","v":"1"},{"n":"国创","v":"4"},{"n":"电影","v":"2"},{"n":"电视剧","v":"5"},{"n":"记录片","v":"3"},{"n":"综艺","v":"7"}]},{"key":"order","name":"排序","value":[{"n":"播放数量","v":"2"},{"n":"更新时间","v":"0"},{"n":"最高评分","v":"4"},{"n":"弹幕数量","v":"1"},{"n":"追看人数","v":"3"},{"n":"开播时间","v":"5"},{"n":"上映时间","v":"6"}]},{"key":"season_status","name":"付费","value":[{"n":"全部","v":"-1"},{"n":"免费","v":"1"},{"n":"付费","v":"2%2C6"},{"n":"大会员","v":"4%2C6"}]}],"时间表":[{"key":"tid","name":"分类","value":[{"n":"番剧","v":"1"},{"n":"国创","v":"4"}]}]},
play_parse:true,
play_json:[{re:'http://jiexi.fc8001.top/AXogZOBnwSzZOtQf.php?url=', json:{jx:1, parse:0,header:JSON.stringify({"user-agent":"PC_UA"})}}],
pagecount:{"1":1,"2":1,"3":1,"4":1,"5":1,"7":1,"时间表":1},
lazy:'',
limit:5,
推荐:'',
推荐:'js:let d=[];function get_result(url){let videos=[];let html=request(url);let jo=JSON.parse(html);if(jo["code"]===0){let vodList=jo.result?jo.result.list:jo.data.list;vodList.forEach(function(vod){let aid=(vod["season_id"]+"").trim();let title=vod["title"].trim();let img=vod["cover"].trim();let remark=vod.new_ep?vod["new_ep"]["index_show"]:vod["index_show"];videos.push({vod_id:aid,vod_name:title,vod_pic:img,vod_remarks:remark})})}return videos}function get_rank(tid,pg){return get_result("https://api.bilibili.com/pgc/web/rank/list?season_type="+tid+"&pagesize=20&page="+pg+"&day=3")}function get_rank2(tid,pg){return get_result("https://api.bilibili.com/pgc/season/rank/web/list?season_type="+tid+"&pagesize=20&page="+pg+"&day=3")}function home_video(){let videos=get_rank(1).slice(0,5);[4,2,5,3,7].forEach(function(i){videos=videos.concat(get_rank2(i).slice(0,5))});return videos}VODS=home_video();',
一级:'',
一级:'js:let d=[];let vmid=input.split("vmid=")[1].split("&")[0];function get_result(url){let videos=[];let html=request(url);let jo=JSON.parse(html);if(jo["code"]===0){let vodList=jo.result?jo.result.list:jo.data.list;vodList.forEach(function(vod){let aid=(vod["season_id"]+"").trim();let title=vod["title"].trim();let img=vod["cover"].trim();let remark=vod.new_ep?vod["new_ep"]["index_show"]:vod["index_show"];videos.push({vod_id:aid,vod_name:title,vod_pic:img,vod_remarks:remark})})}return videos}function get_rank(tid,pg){return get_result("https://api.bilibili.com/pgc/web/rank/list?season_type="+tid+"&pagesize=20&page="+pg+"&day=3")}function get_rank2(tid,pg){return get_result("https://api.bilibili.com/pgc/season/rank/web/list?season_type="+tid+"&pagesize=20&page="+pg+"&day=3")}function get_zhui(pg,mode){let url="https://api.bilibili.com/x/space/bangumi/follow/list?type="+mode+"&follow_status=0&pn="+pg+"&ps=10&vmid="+vmid;return get_result(url)}function get_all(tid,pg,order,season_status){let url="https://api.bilibili.com/pgc/season/index/result?order="+order+"&pagesize=20&type=1&season_type="+tid+"&page="+pg+"&season_status="+season_status;return get_result(url)}function get_timeline(tid,pg){let videos=[];let url="https://api.bilibili.com/pgc/web/timeline/v2?season_type="+tid+"&day_before=2&day_after=4";let html=request(url);let jo=JSON.parse(html);if(jo["code"]===0){let videos1=[];let vodList=jo.result.latest;vodList.forEach(function(vod){let aid=(vod["season_id"]+"").trim();let title=vod["title"].trim();let img=vod["cover"].trim();let remark=vod["pub_index"]+" "+vod["follows"].replace("系列","");videos1.push({vod_id:aid,vod_name:title,vod_pic:img,vod_remarks:remark})});let videos2=[];for(let i=0;i<7;i++){let vodList=jo["result"]["timeline"][i]["episodes"];vodList.forEach(function(vod){if(vod["published"]+""==="0"){let aid=(vod["season_id"]+"").trim();let title=vod["title"].trim();let img=vod["cover"].trim();let date=vod["pub_ts"];let remark=date+" "+vod["pub_index"];videos2.push({vod_id:aid,vod_name:title,vod_pic:img,vod_remarks:remark})}})}videos=videos2.concat(videos1)}return videos}function cate_filter(d,cookie){if(MY_CATE==="1"){return get_rank(MY_CATE,MY_PAGE)}else if(["2","3","4","5","7"].includes(MY_CATE)){return get_rank2(MY_CATE,MY_PAGE)}else if(MY_CATE==="全部"){let tid=MY_FL.tid||"1";let order=MY_FL.order||"2";let season_status=MY_FL.season_status||"-1";return get_all(tid,MY_PAGE,order,season_status)}else if(MY_CATE==="追番"){return get_zhui(MY_PAGE,1)}else if(MY_CATE==="追剧"){return get_zhui(MY_PAGE,2)}else if(MY_CATE==="时间表"){let tid=MY_FL.tid||"1";return get_timeline(tid,MY_PAGE)}else{return[]}}VODS=cate_filter();',
二级:{
is_json:true,
title:".result.title;.result.share_sub_title",
img:".result.cover",
desc:".result.new_ep.desc;.result.publish.pub_time;.result.subtitle",
content:".result.evaluate",
tabs:"js:pdfa=jsp.pdfa;TABS=['B站']",
lists:".result.episodes",
list_text:'title',
list_url:'cid',
},
二级:'',
二级:'js:function zh(num){let p="";if(Number(num)>1e8){p=(num/1e8).toFixed(2)+"亿"}else if(Number(num)>1e4){p=(num/1e4).toFixed(2)+"万"}else{p=num}return p}let html=request(input);let jo=JSON.parse(html).result;let id=jo["season_id"];let title=jo["title"];let pic=jo["cover"];let areas=jo["areas"][0]["name"];let typeName=jo["share_sub_title"];let date=jo["publish"]["pub_time"].substr(0,4);let dec=jo["evaluate"];let remark=jo["new_ep"]["desc"];let stat=jo["stat"];let status="弹幕: "+zh(stat["danmakus"])+" 点赞: "+zh(stat["likes"])+" 投币: "+zh(stat["coins"])+" 追番追剧: "+zh(stat["favorites"]);let score=jo.hasOwnProperty("rating")?"评分: "+jo["rating"]["score"]+" "+jo["subtitle"]:"暂无评分"+" "+jo["subtitle"];let vod={vod_id:id,vod_name:title,vod_pic:pic,type_name:typeName,vod_year:date,vod_area:areas,vod_remarks:remark,vod_actor:status,vod_director:score,vod_content:dec};let ja=jo["episodes"];let playurls1=[];let playurls2=[];ja.forEach(function(tmpJo){let eid=tmpJo["id"];let cid=tmpJo["cid"];let link=tmpJo["link"];let part=tmpJo["title"].replace("#","-")+" "+tmpJo["long_title"];playurls1.push(part+"$"+eid+"_"+cid);playurls2.push(part+"$"+link)});let playUrl=playurls1.join("#")+"$$$"+playurls2.join("#");vod["vod_play_from"]="B站$$$bilibili";vod["vod_play_url"]=playUrl;VOD=vod;',
搜索:'',
搜索:'js:let url1=input+"media_bangumi";let url2=input+"media_ft";let html=request(url1);let msg=JSON.parse(html).message;if(msg!=="0"){VODS=[{vod_name:KEY+"➢"+msg,vod_id:"no_data",vod_remarks:"别点,缺少bili_cookie",vod_pic:"https://ghproxy.net/https://raw.githubusercontent.com/hjdhnx/dr_py/main/404.jpg"}]}else{let jo1=JSON.parse(html).data;html=request(url2);let jo2=JSON.parse(html).data;let videos=[];let vodList=[];if(jo1["numResults"]===0){vodList=jo2["result"]}else if(jo2["numResults"]===0){vodList=jo1["result"]}else{vodList=jo1["result"].concat(jo2["result"])}vodList.forEach(function(vod){let aid=(vod["season_id"]+"").trim();let title=KEY+"➢"+vod["title"].trim().replace(\'<em class="keyword">\',"").replace("</em>","");let img=vod["cover"].trim();let remark=vod["index_show"];videos.push({vod_id:aid,vod_name:title,vod_pic:img,vod_remarks:remark})});VODS=videos}',
lazy:'',
lazy:`js:
if (/^http/.test(input)) {
input = {
jx: 1,
url: input,
parse: 0,
header: JSON.stringify({
"user-agent": "Mozilla/5.0"
})
}
} else {
let ids = input.split("_");
let dan = 'https://api.bilibili.com/x/v1/dm/list.so?oid=' + ids[1];
let result = {};
let url = "https://api.bilibili.com/pgc/player/web/playurl?qn=116&ep_id=" + ids[0] + "&cid=" + ids[1];
let html = request(url);
let jRoot = JSON.parse(html);
if (jRoot["message"] !== "success") {
print("需要大会员权限才能观看");
input = ""
} else {
let jo = jRoot["result"];
let ja = jo["durl"];
let maxSize = -1;
let position = -1;
ja.forEach(function(tmpJo, i) {
if (maxSize < Number(tmpJo["size"])) {
maxSize = Number(tmpJo["size"]);
position = i
}
});
let url = "";
if (ja.length > 0) {
if (position === -1) {
position = 0
}
url = ja[position]["url"]
}
result["parse"] = 0;
result["playUrl"] = "";
result["url"] = url;
result["header"] = {
Referer: "https://www.bilibili.com",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
};
result["contentType"] = "video/x-flv";
result["danmaku"] = dan;
input = result
}
}
`,
}
@@ -1,350 +0,0 @@
# -*- coding: utf-8 -*-
# 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
# 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
#junyouyun
import sys
import json
import time
import base64
import hashlib
import urllib3
import concurrent.futures
from urllib.parse import quote
from base.spider import Spider
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
sys.path.append('..')
class Spider(Spider):
host, userid, episode_list = '', '', []
# ---------- 加密与签名相关常量 ----------
PUB_KEY_B64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoYt0BP77U+DM08BiI/QbSRIfxijXo85BTPqIM1Ow8BNwhLETzRIZ+dEwdWDbydG/PspgBAfRpGaYVdJYtvaC2JnoO8+Ik6qMWojfEJxSFLa0Pb0A892tun4gsxoEMjcreZ+YGyaBxAfqX0BSMfdrOgIYaZQjYrw9TRLlUT31QoQIDAQAB"
APP_SIGN_SHA1 = "09a8dc51639a31801af5f6418caebfabc695eb24"
DEVICE_ID = "2d590b9842d064a1"
# RSA 私钥(用于解密响应)
PRIV_KEY_B64 = """MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCquQQ5r6+yJI8CDFkXRp8vUsdD45ov8EP12ooLs56ca2DQXaSNGS9910bAPVA9chkp0mKIvKqjAsHz5Tl9EeNPblarGEeJUIxpxZtiSqNTpvtiD/TjhpzuHYic7RAfQ/h7p/ypE8ymU42pYjsB5t26Mv6XgkLV+jzrSf73HlCuS0iMyLmt6zz3Mw9izM13EpB8iFLtfbbYymycKTx4RAmPQLwhNGex/AlUIYxXP4R2yyaa4W6mEtc6aME2QuzJFxPgP3HJ9NBx/LWVn4skxWjZ7zg+VRQRHnjyVaSLu3Z5gN5ITWCyE32qaHJa6WBahZj5jWhRyAG1bQ+xKJa8lBL5AgMBAAECggEAUwv9SjJ0PSwbhNuM2w23kcWquROWhYtTA91zGY4esehqB/IFgb2mpIh8Gje5OKqwIu/8jpd4SiOlRYdUF8sD0DfUYRZGdj2AkFNX6tBz8tVfo6wvbB6naA1lzzBij1L5JO3qsjS3cJFkb+kg2yP66AC2Z+0tpfk8eRhdtshAZwfcd1DEGt1uAvYL1eaUK9HRvpt9lPeGcHERDl2hBd4uyaF0K1O+zF9y59nYbTySWPxRZq3sFEE85xRMlstD7YZi7W2gKvMFRD4/FKmrZ3m7aKJRITtyKOyyPcYmepNv3Qv7kk59Pg38n2WWQ0Ra/bCH3E48YNCnQvZMpitkTfJhoQKBgQDbnROOYTP8OTJ6f/qhoGjxeO3x1VOaOp8l0x7b0SCfoqNGS0Cyiqj72BmJtPMPqSTjn6MmNzqbg1KOdhXyzNozs+i5ccW1M56j96mr5I/Z0FpE3oyIHNfDDBlf9M8YQqEF9oYxniYYft9oapO7cRQkHER6qpvnHTavwlv4m78CXwKBgQDHAjs2YlpKDdI1lcbZJCc7TwtH+Pd2bUki8YXafWNcPhITQHbOZjr310eK1QJC6GJncjkOqbX7yv3ivvTO35FZTQhuA1xEG1P00FG8bE0tHYPIwQHi9y0eA5cieMdo8E6XYria1mw/3fqSQEsfZyJlR32JQIoGAipM8iO1X2nZpwKBgDkMFIhnt5lNQk+P7wsNIDWZtDWdtJnboHuy29E+Abt2A/O+mI/IdRz2hau/1WO8DFkUnszOi+rZshhPlGP90rCbi1igtTrcrdjp/KkqNjPea5R4OwkgdOu1uOG0NheXNzzVTQaWjk7Opjn5dWa7eP/oV+GFb/oZHJuLYVizHGsBAoGADA7rjZEKDYCm4w5PPSr+oY5ZjaPdQrS+gLqHtMRyN82fBMGcMUdqfUfzEstzVqCEDeaS5HuOBlK3bXzKkppjUTjksN3NQmcxgBz7RuJ9DqXCLXDcb2cwuafYCYOt+YLOEEgwDVm+t2P44dG5e46hO+fICH/7nP+WlpD5buz4GfMCgYB57r3g/6hi9WUDnfc7ZAzWMqR0EhJVYKYy+KFEtdIPzhkkIHq5RASe88E9kzoGoZFdb3tIjvGZWcHerirrqWkMsuQtP/Qi0zjieid5tAPj+r4kbiCVTw0E0jnmPBzGInQi7lpeTTKnG1fbyS5lBS+WmHfIuzpECgCkxhaT+LJJkg=="""
headers = {
'User-Agent': "okhttp/4.12.0",
'Connection': "Keep-Alive",
'Accept-Encoding': "gzip",
'Content-Type': "application/json;charset=UTF-8",
'Cache-Control': "no-cache",
'token': "",
'deviceId': DEVICE_ID,
'client': "app",
'deviceType': "Android"
}
# ---------- RSA 加密 ----------
def rsa_encrypt(self, data: str) -> str:
key = RSA.import_key(base64.b64decode(self.PUB_KEY_B64))
cipher = PKCS1_v1_5.new(key)
encrypted = cipher.encrypt(data.encode('utf-8'))
return base64.b64encode(encrypted).decode('utf-8')
# ---------- RSA 解密(支持分块) ----------
def rsa_decrypt(self, encrypted_b64: str) -> str:
key = RSA.import_key(base64.b64decode(self.PRIV_KEY_B64))
cipher = PKCS1_v1_5.new(key)
encrypted_bytes = base64.b64decode(encrypted_b64)
block_size = 256
decrypted_parts = []
for i in range(0, len(encrypted_bytes), block_size):
block = encrypted_bytes[i:i+block_size]
decrypted_parts.append(cipher.decrypt(block, None))
return b''.join(decrypted_parts).decode('utf-8')
# ---------- 构建签名参数 ----------
def build_params_string(self, episode_id="", episode_index="", vid="", player_id="", type_id="", user_id=""):
return (f"episodeId{episode_id}"
f"episodeIndex{episode_index}"
f"id{vid}"
f"playerId{player_id}"
f"source0"
f"typeId{type_id}"
f"userId{user_id}")
def generate_sign(self, timestamp: str, params_str: str, device_id: str) -> str:
raw = f"SaltLSFBTimestamp{timestamp}Params{params_str}ClientappDeviceId{device_id}"
b64 = base64.b64encode(raw.encode('utf-8')).decode('utf-8')
md5 = hashlib.md5(b64.encode('utf-8')).hexdigest().upper()
return md5
def build_encrypted_headers(self, body_json: str, params_str: str) -> dict:
timestamp = str(int(time.time()))
encrypted_key = self.rsa_encrypt(body_json)
snjm = self.rsa_encrypt("113")
appsign = self.rsa_encrypt(self.APP_SIGN_SHA1)
sign = self.generate_sign(timestamp, params_str, self.DEVICE_ID)
headers = {
"snjm": snjm,
"appsign": appsign,
"timestamp": timestamp,
"sign": sign,
"deviceId": self.DEVICE_ID,
"token": self.headers.get('token', ''),
"client": "app",
"deviceType": "Android",
"Content-Type": "application/json;charset=UTF-8",
"Cache-Control": "no-cache",
"User-Agent": "okhttp/4.12.0"
}
return headers, {"key": encrypted_key}
# ---------- 原有接口(保持不变) ----------
def init(self, extend=''):
self.headers['deviceId'] = self.DEVICE_ID
self.host = 'http://qkys.qukanwh.com'
response = self.fetch(f'{self.host}/api/v1/app/user/visitorInfo', headers=self.headers).json()
self.userid = response['data']['id']
token = response['data']['token']
self.headers['token'] = token
def homeContent(self, filter):
response = self.post(f'{self.host}/api/v1/app/screen/screenType', headers=self.headers).json()
data = response['data']
classes = []
for i in data:
classes.append({'type_id': i['id'], 'type_name': i['name']})
return {'class': classes}
def homeVideoContent(self):
response = self.post(f'{self.host}/api/v1/app/recommend/recommendList', headers=self.headers).json()
data = response['data']
videos = []
with concurrent.futures.ThreadPoolExecutor() as executor:
future_to_id = {
executor.submit(
self.post,
f'{self.host}/api/v1/app/recommend/recommendSubList',
data=json.dumps({
"condition": item['id'],
"pageNum": 1,
"pageSize": 6
}),
headers=self.headers
): item['id'] for item in data
}
for future in concurrent.futures.as_completed(future_to_id):
try:
response = future.result().json()
for video in response['data']['records']:
videos.append({
"vod_id": video['id'],
"vod_name": video['name'],
"vod_pic": video['cover']
})
except Exception as e:
print(f"Request failed for item {future_to_id[future]}: {str(e)}")
return {'list': videos}
def categoryContent(self, tid, pg, filter, extend):
payload = {
"condition": {
"classify": "",
"region": "",
"sreecnTypeEnum": "NEWEST",
"typeId": tid,
"year": ""
},
"pageNum": pg,
"pageSize": 40
}
response = self.post(f'{self.host}/api/v1/app/screen/screenMovie', data=json.dumps(payload), headers=self.headers).json()
videos = []
for i in response['data']['records']:
videos.append({
"vod_id": i['id'],
"vod_name": i['name'],
"vod_pic": i['cover'],
"vod_remarks": i['area'],
"vod_year": i['year']
})
return {'list': videos, 'page': pg}
def searchContent(self, key, quick, pg='1'):
payload = {
"condition": {
"value": key
},
"pageNum": pg,
"pageSize": 40
}
response = self.post(f'{self.host}/api/v1/app/search/searchMovie', data=json.dumps(payload), headers=self.headers).json()
videos = []
for i in response['data']['records']:
videos.append({
'vod_id': i['id'],
'vod_name': i['name'],
'vod_pic': i['cover'],
'vod_remarks': i['area'],
'vod_year': i['year'],
'vod_area': i['area'],
'vod_content': i['desc']
})
return {'list': videos, 'page': pg}
# ---------- 详情页(已集成解密) ----------
def detailContent(self, ids):
type_id = "M15" # 注意:原脚本写死为 M17,可根据需要修改
vid = ids[0]
body = {
"id": vid,
"source": 0,
"typeId": type_id,
"userId": self.userid,
"episodeId": "",
"episodeIndex": "",
"playerId": ""
}
body_json = json.dumps(body, separators=(',', ':'))
params_str = self.build_params_string(
episode_id="",
episode_index="",
vid=str(vid),
player_id="",
type_id=type_id,
user_id=str(self.userid)
)
headers, payload = self.build_encrypted_headers(body_json, params_str)
# 发送加密请求
resp_raw = self.post(f'{self.host}/api/v1/app/play/movieDetails', data=json.dumps(payload), headers=headers).json()
encrypted_data = resp_raw.get('data')
if not encrypted_data:
raise Exception("响应中 data 为空")
# 解密 data 字段
decrypted_json_str = self.rsa_decrypt(encrypted_data)
data = json.loads(decrypted_json_str)
# 后续处理与原脚本相同
currentplayerid = data['playerId']
play_urls = []
play_url = []
show = []
for i in data['episodeList']:
play_url.append(f"{i['episode']}${ids[0]}@{currentplayerid}@{i['id']}@episode")
play_urls.append('#'.join(play_url))
moviePlayerList = data['moviePlayerList']
for i2 in moviePlayerList:
if i2['id'] == currentplayerid:
show.append(i2['moviePlayerName'])
for j in moviePlayerList:
playerid = j['id']
episodeTotal = j.get('episodeTotal')
if playerid == currentplayerid or episodeTotal is None:
continue
play_url = []
for k in range(1, episodeTotal + 1):
play_url.append(f"{k}集${k}@{playerid}@{ids[0]}@virtual")
play_urls.append('#'.join(play_url))
if j['moviePlayerName'] not in show:
show.append(j['moviePlayerName'])
# 获取简介(此接口可能无需加密,保持原样)
payload_desc = {
"id": ids[0],
"typeId": type_id
}
response_desc = self.post(f'{self.host}/api/v1/app/play/movieDesc', data=json.dumps(payload_desc), headers=self.headers).json()
data2 = response_desc['data']
video = {
'vod_id': data2['id'],
'vod_name': data2['name'],
'vod_pic': data2['cover'],
'vod_content': data2['introduce'],
'vod_year': data2['year'],
'vod_area': data2['area'],
'vod_remarks': '',
'vod_score': data2['score'],
'type_name': data2['classify'],
'vod_director': data2['director'],
'vod_actor': data2['star'],
'vod_play_from': '$$$'.join(show),
'vod_play_url': '$$$'.join(play_urls)
}
return {'list': [video]}
# ---------- 播放页(已集成解密) ----------
def playerContent(self, flag, id, vipflags):
param, playerid, param2, param3 = id.split('@')
if param3 == 'virtual':
payload = {
"episodeIndex": str(int(param) - 1),
"id": int(param2),
"playerId": playerid,
"source": 0,
"typeId": "M15",
"userId": self.userid,
"episodeId": ""
}
else:
payload = {
"episodeId": param2,
"id": int(param),
"playerId": playerid,
"source": 0,
"typeId": "M15",
"userId": self.userid,
"episodeIndex": ""
}
body_json = json.dumps(payload, separators=(',', ':'))
print(body_json)
params_str = self.build_params_string(
episode_id=payload.get("episodeId", ""),
episode_index=payload.get("episodeIndex", ""),
vid=str(payload["id"]),
player_id=payload["playerId"],
type_id=payload["typeId"],
user_id=str(payload["userId"])
)
print(params_str)
headers, encrypted_payload = self.build_encrypted_headers(body_json, params_str)
print(headers)
print(encrypted_payload)
# 获取播放信息(加密响应)
resp_raw = self.post(f'{self.host}/api/v1/app/play/movieDetails', data=json.dumps(encrypted_payload), headers=headers).json()
encrypted_data = resp_raw.get('data')
if not encrypted_data:
raise Exception("响应中 data 为空")
decrypted_json_str = self.rsa_decrypt(encrypted_data)
data = json.loads(decrypted_json_str)
print(data)
parse_url = data['url']
playerid = data['playerId']
# 调用分析接口(注:analysisMovieUrl 的响应可能也是加密的,但原脚本直接取 data,这里暂不做额外解密)
analysis_body = {
"playerUrl": parse_url,
"playerId": playerid
}
analysis_json = json.dumps(analysis_body, separators=(',', ':'))
# analysisMovieUrl 接口的参数拼接?理论上也需要签名,但原脚本是 GET 方式,为了兼容,我们沿用原脚本的 GET 方式
# 原脚本使用 fetch GET 带参数,并未加密。这里也采用 GET 方式,不使用加密 headers
resp_analysis = self.fetch(f"{self.host}/api/v1/app/play/analysisMovieUrl?playerUrl={quote(parse_url,safe='')}&playerId={playerid}", headers=self.headers).json()
url = resp_analysis.get('data')
return {'jx': '0', 'parse': '0', 'url': url, 'header': {'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'}}
def getName(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
def localProxy(self, param):
pass
@@ -1,211 +0,0 @@
// 本资源来源于互联网公开渠道,仅可用于个人学习爬虫技术。
// 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
import {Crypto, _} from 'assets://js/lib/cat.js';
let host = 'https://bubutv.top';
let device_id = '';
const pkg = 'com.sunshine.tv';
const ver = '4';
const device_id_cache_key = 'com.sunshine.tv_3qys_B7k7Dt56Rn';
async function init(cfg) {
const ext = cfg.ext;
if (typeof cfg.ext === 'string' && cfg.ext.startsWith('http')) {
host = cfg.ext.trim().replace(/\/$/, '');
}
}
async function home(filter) {
const hd = await getHeaders();
const resp = await req(`${host}/api.php/app/index/home`, { headers: hd });
const json = JSON.parse(resp.content);
const classes = _.map(json.data.categories, (i) => ({
'type_id': i.type_name,
'type_name': i.type_name
}));
const videos = [];
for (const cat of json.data.categories) {
videos.push(...arr2vods(cat.videos));
}
return JSON.stringify({ class: classes, list: videos });
}
async function homeVod() {
return JSON.stringify({ list: [] });
}
async function category(tid, pg, filter, extend) {
const hd = await getHeaders();
const url = `${host}/api.php/app/filter/vod?type_name=${encodeURIComponent(tid)}&page=${pg}&sort=hits`;
const resp = await req(url, { headers: hd });
const json = JSON.parse(resp.content);
return JSON.stringify({
list: arr2vods(json.data),
pagecount: json.pageCount,
page: parseInt(pg)
});
}
async function search(wd, quick, pg=1) {
const hd = await getHeaders();
const url = `${host}/api.php/app/search/index?wd=${encodeURIComponent(wd)}&page=${pg}&limit=15`;
const resp = await req(url, { headers: hd });
const json = JSON.parse(resp.content);
return JSON.stringify({
list: arr2vods(json.data),
pagecount: json.pageCount,
page: parseInt(pg)
});
}
async function detail(id) {
const hd = await getHeaders();
const resp = await req(`${host}/api.php/app/vod/get_detail?vod_id=${id}`, { headers: hd });
const json = JSON.parse(resp.content);
const data = json.data[0];
const vodplayer = json.vodplayer;
const shows = [];
const play_urls = [];
const raw_shows = data.vod_play_from.split('$$$');
const raw_urls_list = data.vod_play_url.split('$$$');
for (let i = 0; i < raw_shows.length; i++) {
const show_code = raw_shows[i];
const urls_str = raw_urls_list[i];
let need_parse = 0;
let is_show = 0;
let name = show_code;
const player_info = _.find(vodplayer, (p) => p.from === show_code);
if (player_info) {
is_show = 1;
need_parse = player_info.decode_status;
if (show_code.toLowerCase() !== player_info.show.toLowerCase()) {
name = `${player_info.show} (${show_code})`;
}
}
if (is_show === 1) {
const urls = [];
for (const url_item of urls_str.split('#')) {
if (url_item.includes('$')) {
const [episode, url] = url_item.split('$');
urls.push(`${episode}$${show_code}@${need_parse}@${url}`);
}
}
if (urls.length > 0) {
play_urls.push(urls.join('#'));
shows.push(name);
}
}
}
const video = {
'vod_id': data.vod_id.toString(),
'vod_name': data.vod_name,
'vod_pic': data.vod_pic,
'vod_remarks': data.vod_remarks,
'vod_year': data.vod_year,
'vod_area': data.vod_area,
'vod_actor': data.vod_actor,
'vod_director': data.vod_director,
'vod_content': data.vod_content,
'vod_play_from': shows.join('$$$'),
'vod_play_url': play_urls.join('$$$'),
'type_name': data.vod_class
};
return JSON.stringify({ list: [video] });
}
async function play(flag, vid, flags) {
const parts = vid.split('@');
const play_from = parts[0];
const need_parse = parts[1];
const raw_url = parts[2];
let url = '';
let jx = 0;
if (need_parse === '1') {
try {
const hd = await getHeaders();
const apiUrl = `${host}/api.php/app/decode/url/?url=${encodeURIComponent(raw_url)}&vodFrom=${play_from}`;
const resp = await req(apiUrl, { headers: hd, timeout: 30000 });
const json = JSON.parse(resp.content);
if (json.data && json.data.startsWith('http')) {
url = json.data;
}
} catch (e) {
console.error('Play decode error:', e);
}
}
if (!url) {
url = raw_url;
if (/(www\.iqiyi|v\.qq|v\.youku|www\.mgtv|www\.bilibili)\.com/.test(raw_url)) {
jx = 1;
}
}
return JSON.stringify({ jx: jx, parse: 0, url: url, header: {'User-Agent': 'com.sunshine.tv/1.2.0 (Linux;Android 15) AndroidXMedia3/1.4.1'}});
}
async function getHeaders() {
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = randomStr(3, '0123456789');
if (!device_id) {
device_id = await local.get('cache', device_id_cache_key);
if (!device_id || device_id.length !== 16) {
device_id = randomStr(16);
await local.set('cache', device_id_cache_key, device_id);
}
}
const sign_str = `finger=SF-C3B2B41F6EFFFF9869176CF68F6790E8F07506FC88632C94B4F5F0430D5498CA&id=${pkg}&nonce=${nonce}&sk=SK-thanks&time=${timestamp}&v=${ver}`;
const sign = sha256(sign_str);
return {
'User-Agent': 'okhttp/4.12.0',
'Accept': 'application/json',
'x-aid': pkg,
'x-ave': ver,
'x-time': timestamp,
'x-nonc': nonce,
'x-sign': sign,
'x-device-id': device_id,
'x-device-brand': 'vivo',
'x-device-model': 'V2309A',
'x-update-id': '0245861b-2ebf-5524-389d-f983830651ec'
};
}
function arr2vods(arr) {
return _.map(arr, (i) => {
let type_name = i.type_name || '';
if (i.vod_class) {
type_name = type_name + (type_name ? ',' : '') + i.vod_class;
}
return {
'vod_id': i.vod_id.toString(),
'vod_name': i.vod_name,
'vod_pic': i.vod_pic,
'vod_remarks': i.vod_remarks,
'type_name': type_name,
'vod_year': i.vod_year
};
});
}
function randomStr(len, chars = '0123456789abcdef') {
let str = '';
for (let i = 0; i < len; i++) {
str += chars[_.random(0, chars.length - 1)];
}
return str;
}
function sha256(text) {
return Crypto.SHA256(text).toString().toUpperCase();
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
search: search,
detail: detail,
play: play
};
}
-948
Melihat File
@@ -1,948 +0,0 @@
import cheerio from 'assets://js/lib/cheerio.min.js';
// import cheerio from '../lib/cheerio.min.js';
const sites = [
'https://www.cd-zj.com',
'https://www.gzwlr.com',
]
const appConfig = {
siteName: "枫叶4k影院",
siteUrl: sites[0]
}
const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
const Headers = {
"User-Agent": UA,
"Referer": appConfig.siteUrl + "/",
}
async function init(ext) {}
function getYearFilter() {
let years = [{
"n": "全部",
"v": ""
}];
const currentYear = new Date().getFullYear().toString();
for (let y = currentYear; y >= currentYear - 22; y--) {
years.push({
"n": String(y),
"v": String(y)
});
}
return {
"key": "year",
"name": "年份",
"value": years
};
}
function getLetterFilter() {
return {
"key": "letter",
"name": "字母",
"value": [{
"n": "全部",
"v": ""
},
{
"n": "A",
"v": "A"
}, {
"n": "B",
"v": "B"
}, {
"n": "C",
"v": "C"
}, {
"n": "D",
"v": "D"
},
{
"n": "E",
"v": "E"
}, {
"n": "F",
"v": "F"
}, {
"n": "G",
"v": "G"
}, {
"n": "H",
"v": "H"
},
{
"n": "I",
"v": "I"
}, {
"n": "J",
"v": "J"
}, {
"n": "K",
"v": "K"
}, {
"n": "L",
"v": "L"
},
{
"n": "M",
"v": "M"
}, {
"n": "N",
"v": "N"
}, {
"n": "O",
"v": "O"
}, {
"n": "P",
"v": "P"
},
{
"n": "Q",
"v": "Q"
}, {
"n": "R",
"v": "R"
}, {
"n": "S",
"v": "S"
}, {
"n": "T",
"v": "T"
},
{
"n": "U",
"v": "U"
}, {
"n": "V",
"v": "V"
}, {
"n": "W",
"v": "W"
}, {
"n": "X",
"v": "X"
},
{
"n": "Y",
"v": "Y"
}, {
"n": "Z",
"v": "Z"
}, {
"n": "0-9",
"v": "0-9"
}
]
}
}
const OtherFilters = [{
"key": "area",
"name": "地区",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "大陆",
"v": "大陆"
}, {
"n": "香港",
"v": "香港"
},
{
"n": "台湾",
"v": "台湾"
}, {
"n": "美国",
"v": "美国"
}, {
"n": "韩国",
"v": "韩国"
},
{
"n": "日本",
"v": "日本"
}, {
"n": "泰国",
"v": "泰国"
}, {
"n": "新加坡",
"v": "新加坡"
},
{
"n": "马来西亚",
"v": "马来西亚"
}, {
"n": "印度",
"v": "印度"
}, {
"n": "英国",
"v": "英国"
},
{
"n": "法国",
"v": "法国"
}, {
"n": "加拿大",
"v": "加拿大"
}, {
"n": "西班牙",
"v": "西班牙"
},
{
"n": "俄罗斯",
"v": "俄罗斯"
}, {
"n": "其它",
"v": "其它"
}
]
},
getYearFilter(),
{
"key": "lang",
"name": "语言",
"value": [{
"n": "全部",
"v": ""
}, {
"n": "国语",
"v": "国语"
}, {
"n": "英语",
"v": "英语"
},
{
"n": "粤语",
"v": "粤语"
}, {
"n": "闽南语",
"v": "闽南语"
}, {
"n": "韩语",
"v": "韩语"
},
{
"n": "日语",
"v": "日语"
}, {
"n": "其它",
"v": "其它"
}
]
},
getLetterFilter()
];
const myFilters = {
"2": [{
key: "type",
"name": "类型",
value: [{
"n": "全部",
"v": "2"
},
{
"n": "国产剧",
"v": "13"
},
{
"n": "日韩剧",
"v": "15"
},
{
"n": "海外剧",
"v": "16"
},
]
},
{
"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": "其他"
}
]
},
...OtherFilters
],
"1": [{
"key": "type",
"name": "类型",
value: [{
"n": "全部",
"v": "1"
},
{
"n": "动作片",
"v": "6"
},
{
"n": "喜剧片",
"v": "7"
},
{
"n": "恐怖片",
"v": "8"
},
{
"n": "科幻片",
"v": "9"
},
{
"n": "爱情片",
"v": "10"
},
{
"n": "剧情片",
"v": "11"
}
]
},
{
"key": "class",
"name": "剧情",
"value": [{
"n": "全部",
"v": ""
},
{
"n": "喜剧",
"v": "喜剧"
},
{
"n": "爱情",
"v": "爱情"
},
{
"n": "恐怖",
"v": "恐怖"
},
{
"n": "动作",
"v": "动作"
},
{
"n": "科幻",
"v": "科幻"
},
{
"n": "剧情",
"v": "剧情"
},
{
"n": "战争",
"v": "战争"
},
{
"n": "警匪",
"v": "警匪"
},
{
"n": "犯罪",
"v": "犯罪"
},
{
"n": "动画",
"v": "动画"
},
{
"n": "奇幻",
"v": "奇幻"
},
{
"n": "武侠",
"v": "武侠"
},
{
"n": "冒险",
"v": "冒险"
},
{
"n": "枪战",
"v": "枪战"
},
{
"n": "悬疑",
"v": "悬疑"
},
{
"n": "惊悚",
"v": "惊悚"
},
{
"n": "经典",
"v": "经典"
},
{
"n": "青春",
"v": "青春"
},
{
"n": "文艺",
"v": "文艺"
},
{
"n": "微电影",
"v": "微电影"
},
{
"n": "古装",
"v": "古装"
},
{
"n": "历史",
"v": "历史"
},
{
"n": "运动",
"v": "运动"
},
{
"n": "农村",
"v": "农村"
},
{
"n": "儿童",
"v": "儿童"
},
{
"n": "网络电影",
"v": "网络电影"
}
]
},
...OtherFilters
],
"4": [{
"key": "type",
"name": "类型",
"value": [{
"n": "全部",
"v": "4"
},
{
"n": "国产动漫",
"v": "25"
},
{
"n": "日韩动漫",
"v": "26"
},
]
},
{
"key": "class",
"name": "剧情",
"value": [{
"n": "全部",
"v": ""
},
{
"n": "情感",
"v": "情感"
},
{
"n": "科幻",
"v": "科幻"
},
{
"n": "热血",
"v": "热血"
},
{
"n": "推理",
"v": "推理"
},
{
"n": "搞笑",
"v": "搞笑"
},
{
"n": "冒险",
"v": "冒险"
},
{
"n": "萝莉",
"v": "萝莉"
},
{
"n": "校园",
"v": "校园"
},
{
"n": "动作",
"v": "动作"
},
{
"n": "机战",
"v": "机战"
},
{
"n": "运动",
"v": "运动"
},
{
"n": "战争",
"v": "战争"
},
{
"n": "少年",
"v": "少年"
},
{
"n": "少女",
"v": "少女"
},
{
"n": "社会",
"v": "社会"
},
{
"n": "原创",
"v": "原创"
},
{
"n": "亲子",
"v": "亲子"
},
{
"n": "益智",
"v": "益智"
},
{
"n": "励志",
"v": "励志"
},
{
"n": "其他",
"v": "其他"
}
]
},
...OtherFilters
],
"3": [{
"key": "type",
"name": "类型",
value: [{
"n": "全部",
"v": "3"
},
{
"n": "大陆综艺",
"v": "21"
},
{
"n": "日韩综艺",
"v": "22"
},
]
},
{
"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": "求职"
}
]
},
...OtherFilters
],
"5": [
getYearFilter(),
getLetterFilter()
],
};
async function home(filter) {
return JSON.stringify({
class: [{
type_id: "/label/qq",
type_name: "腾讯精选"
},
{
type_id: "/label/youku",
type_name: "优酷精选"
},
{
type_id: "/label/bli",
type_name: "哔哩精选"
},
{
type_id: "2",
type_name: "电视剧",
},
{
type_id: "1",
type_name: "电影"
},
{
type_id: "4",
type_name: "动漫"
},
{
type_id: "3",
type_name: "综艺"
},
{
type_id: "5",
type_name: "热门短剧"
}
],
filters: myFilters
});
}
async function category(tid, pg, filter, extend) {
pg = pg || 1;
let type = extend.type || tid;
const isLanel = tid.startsWith("/label");
let url = "";
const typePrefix = appConfig.siteUrl === 'https://www.gzwlr.com' ? "list" : "cupfox-list";
if (isLanel) {
url = appConfig.siteUrl + tid + `/page/${pg}.html`;
} else {
let classVal = extend.class || '';
let areaVal = extend.area || '';
let langVal = extend.lang || '';
let letterVal = extend.letter || '';
let orderVal = extend.orderBy || '';
let yearVal = extend.year || '';
url = `${appConfig.siteUrl}/${typePrefix}/${type}-${areaVal}-${''}-${classVal}-${langVal}-${letterVal}-${orderVal}-${''}-${pg}-${''}-${''}-${yearVal}.html`;
}
const html = (await req(url)).content;
const $ = cheerio.load(html);
let list = [];
$(".public-list-div.public-list-bj").each(function(index, el) {
let vod_id = $(el).find("a.public-list-exp").attr("href");
let vod_name = $(el).find("a.public-list-exp").attr("title").trim();
let _4k = $(el).find(".public-prt-g").text().trim()
let vod_pic = $(el).find(".public-list-exp img").attr("data-src");
let upto = $(el).find(".ft2").text().trim();
let vod_remarks = _4k + ' ' + upto
list.push({
vod_id,
vod_name,
vod_pic,
vod_remarks
});
});
const pageStr = $('.page-tip').text().trim()
const pagecount = pageStr.match(/\d+\/(\d+)页/)?.[1] || 1
return JSON.stringify({
list,
pagecount
});
}
async function search(wd, quick, page) {
if (page >= 2) {
return JSON.stringify({
list: [],
pagecount: 1
});
}
try {
const searchPrefex = appConfig.siteUrl === 'https://www.gzwlr.com' ? "search" : "cupfox-search";
const url = `${appConfig.siteUrl}/${searchPrefex}/-------------.html?wd=${wd}`;
const html = (await req(url)).content;
const $ = cheerio.load(html);
let list = [];
$('.search-box').each((i, el) => {
const vod_id = $(el).find(".thumb-txt a").attr('href') || '';
const vod_name = $(el).find(".thumb-txt a").text().trim()
const vod_pic = $(el).find('.left img').attr('data-src') || '';
const vod_remarks = $(el).find('.public-list-prb').text().trim()
list.push({
vod_id,
vod_name,
vod_pic,
vod_remarks
});
})
return JSON.stringify({
list: list,
pagecount: 1
});
} catch (e) {
console.error("❌ search 遭遇内部崩溃 =", e.message);
return JSON.stringify({
list: []
});
}
}
async function detail(id) {
try {
const videoId = id;
const url = appConfig.siteUrl + videoId;
const response = await req(url);
const html = response ? response.content : '';
const $ = cheerio.load(html);
const vod_name = $('.slide-info-title').text().trim();
const imgSrc = $('.detail-pic img').attr("data-src") || '';
const vod_pic = imgSrc ? (imgSrc.startsWith('http') ? imgSrc : appConfig.siteUrl + imgSrc) : '';
const vod_actor = $('.detail-info .slide-info').eq(2).text().replace(/演员:\s*/, '').trim();
const vod_remarks = $('.detail-info .slide-info').eq(4).text().replace(/连载\s*:\s*/, '').trim();
const vod_content = ''+$('#height_limit').text().trim();
let rawLines = [];
let rawPlaylists = [];
$('.swiper-slide').each((i, el) => {
const lineName = $(el).clone().find('i, span').remove().end().text().trim();
rawLines.push(lineName);
});
$('.anthology-list-box').each((lineIndex, poolEl) => {
const episodes = [];
$(poolEl).find('a').each((episodeIndex, epEl) => {
const name = $(epEl).text().trim();
const href = $(epEl).attr('href') || '';
if (name && href) {
episodes.push(`${name}\$${href}`);
}
});
rawPlaylists.push(episodes);
});
let targetLineIdx = -1;
for (let i = 0; i < rawLines.length; i++) {
const name = rawLines[i];
const eps = rawPlaylists[i];
if (name.includes("至臻4k") && eps.length > 0) {
targetLineIdx = i;
break;
}
}
if (targetLineIdx === -1 && rawLines.length > 0) {
targetLineIdx = 0;
}
let finalLines = [];
let finalPlaylists = [];
if (targetLineIdx !== -1) {
finalLines.push("在线播放");
finalPlaylists.push(rawPlaylists[targetLineIdx]);
}
const {
vod_play_from,
vod_play_url
} = buildVodPlayData(finalLines, finalPlaylists, true);
const vod = {
vod_id: videoId,
vod_name,
vod_pic,
vod_actor,
vod_remarks,
vod_content,
vod_play_from,
vod_play_url
};
return JSON.stringify({
list: [vod]
});
} catch (error) {
console.error(`解析详情页异常 [ID: ${id}]:`, error);
return JSON.stringify({
list: []
});
}
}
function buildVodPlayData(lines, playlists, shouldReverse = true) {
const processedPlaylists = playlists.map(eps => {
if (shouldReverse) {
eps.reverse();
}
return eps.join('#');
});
return {
vod_play_from: lines.filter(Boolean).join('$$$'),
vod_play_url: processedPlaylists.join('$$$')
};
}
function isDirectUrl(url) {
return url.startsWith('http') || url.endsWith(".m3u8") || url.endsWith(".mp4");
}
async function parsePLayUrl(is2kLine, url) {
const parseApiUrl = is2kLine ? "https://zzrs.mfdyvip.com/player/" : "https://fgsrg.hzqingshan.com/player/"
try {
const html = (await req(`${parseApiUrl}?url=${url}`, {
method: 'GET',
headers: Headers
})).content
const $ = cheerio.load(html)
const token = $('#player-data').attr('data-te');
console.log("🚀 成功拿到 token:", token);
let playData = await req(`${parseApiUrl}/mplayer.php`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
data: {
url: url,
token: token,
}
}).content
playData = JSON.parse(playData)
return playData.url
} catch (e) {
console.error("❌ play encounters an internal crash =", e);
return "";
}
}
async function play(flag, id, flags) {
try {
const html = (await req(`${appConfig.siteUrl}${id}`)).content;
const url = getPlayUrl(html)
if (isDirectUrl(url)) {
return JSON.stringify({
parse: 0,
Header: {
"User-Agent": UA
},
url,
});
}
const is2kLine = flag.includes('2k')
const playUrl = await parsePLayUrl(is2kLine, url)
return JSON.stringify({
parse: 0,
Header: {
"User-Agent": UA
},
url: playUrl
});
} catch (e) {
console.error("❌ play 遭遇内部崩溃 =", e);
return JSON.stringify({
parse: 0,
url: ""
});
}
}
function getPlayUrl(html) {
const match = html.match(/var\s+player_aaaa[\s\S]*?"url"\s*:\s*"([^"]+)"/);
let url = match ? match[1] : '';
url = url.replace(/\\/g, '');
return url;
}
export default {
init,
home,
category,
detail,
search,
play
};
@@ -1,678 +0,0 @@
/**
title: "歪比巴卜",
author: "",
logo: "https://wbbb1.com/static/images/logo.png",
more: {
sourceTag: "在线影视"
}
*/
import { Crypto, load, _ } from 'assets://js/lib/cat.js';
let HOST = 'https://wbbb1.com';
let siteKey = "", siteType = "", sourceKey = "", ext = "";
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36';
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
sourceKey = cfg.sourceKey;
ext = cfg.ext;
if (ext && ext.startsWith('http')) {
HOST = ext;
}
}
async function home(filter) {
const classes = [
{ type_id: "1", type_name: "电影" },
{ type_id: "2", type_name: "剧集" },
{ type_id: "3", type_name: "动漫" },
{ type_id: "4", type_name: "综艺" }
];
const filterObj = {
"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: "冒险" },
{ n: "古装", v: "古装" },
{ n: "剧情", v: "剧情" }
]
},
{
key: "area",
name: "地区",
value: [
{ n: "全部", v: "" },
{ n: "大陆", v: "大陆" },
{ n: "香港", v: "香港" },
{ n: "台湾", v: "台湾" },
{ n: "美国", v: "美国" },
{ n: "日本", v: "日本" },
{ n: "韩国", v: "韩国" },
{ n: "英国", v: "英国" },
{ n: "法国", v: "法国" },
{ n: "印度", v: "印度" },
{ n: "泰国", v: "泰国" }
]
},
{
key: "lang",
name: "语言",
value: [
{ 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: "2022", v: "2022" },
{ n: "2021", v: "2021" },
{ n: "2020", v: "2020" },
{ n: "2019", v: "2019" },
{ n: "2018", v: "2018" }
]
},
{
key: "letter",
name: "字母",
value: [
{ n: "全部", v: "" },
{ n: "A", v: "A" },
{ n: "B", v: "B" },
{ n: "C", v: "C" },
{ n: "D", v: "D" },
{ n: "E", v: "E" },
{ n: "F", v: "F" },
{ n: "G", v: "G" },
{ n: "H", v: "H" },
{ n: "I", v: "I" },
{ n: "J", v: "J" },
{ n: "K", v: "K" },
{ n: "L", v: "L" },
{ n: "M", v: "M" },
{ n: "N", v: "N" },
{ n: "O", v: "O" },
{ n: "P", v: "P" },
{ n: "Q", v: "Q" },
{ n: "R", v: "R" },
{ n: "S", v: "S" },
{ n: "T", v: "T" },
{ n: "U", v: "U" },
{ n: "V", v: "V" },
{ n: "W", v: "W" },
{ n: "X", v: "X" },
{ n: "Y", v: "Y" },
{ n: "Z", v: "Z" },
{ n: "0-9", v: "0-9" }
]
},
{
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: "剧情" }
]
},
{
key: "area",
name: "地区",
value: [
{ n: "全部", v: "" },
{ n: "大陆", v: "大陆" },
{ n: "港台", v: "港台" },
{ n: "美国", v: "美国" },
{ n: "韩国", v: "韩国" },
{ n: "日本", v: "日本" },
{ n: "泰国", v: "泰国" }
]
},
{
key: "lang",
name: "语言",
value: [
{ 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: "2022", v: "2022" },
{ n: "2021", v: "2021" },
{ n: "2020", v: "2020" }
]
},
{
key: "letter",
name: "字母",
value: [
{ n: "全部", v: "" },
{ n: "A", v: "A" },
{ n: "B", v: "B" },
{ n: "C", v: "C" },
{ n: "D", v: "D" },
{ n: "E", v: "E" },
{ n: "F", v: "F" },
{ n: "G", v: "G" },
{ n: "H", v: "H" },
{ n: "I", v: "I" },
{ n: "J", v: "J" },
{ n: "K", v: "K" },
{ n: "L", v: "L" },
{ n: "M", v: "M" },
{ n: "N", v: "N" },
{ n: "O", v: "O" },
{ n: "P", v: "P" },
{ n: "Q", v: "Q" },
{ n: "R", v: "R" },
{ n: "S", v: "S" },
{ n: "T", v: "T" },
{ n: "U", v: "U" },
{ n: "V", v: "V" },
{ n: "W", v: "W" },
{ n: "X", v: "X" },
{ n: "Y", v: "Y" },
{ n: "Z", v: "Z" },
{ n: "0-9", v: "0-9" }
]
},
{
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: "欧美动漫" }
]
},
{
key: "year",
name: "年份",
value: [
{ n: "全部", v: "" },
{ n: "2025", v: "2025" },
{ n: "2024", v: "2024" },
{ n: "2023", v: "2023" }
]
},
{
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: "欧美综艺" }
]
},
{
key: "by",
name: "排序",
value: [
{ n: "时间排序", v: "time" },
{ n: "人气排序", v: "hits" },
{ n: "评分排序", v: "score" }
]
}
]
};
return JSON.stringify({
class: classes,
filters: filterObj
});
}
async function homeVod() {
try {
const res = await req(HOST, {
headers: { 'User-Agent': UA }
});
const $ = load(res.content);
const list = [];
$('.module-poster-item.module-item').each((_, item) => {
const it = $(item);
const href = it.attr('href');
const vod_id = href ? href.match(/\/detail\/(\d+)\.html/)?.[1] : '';
list.push({
vod_id: vod_id || href,
vod_name: it.attr('title') || '',
vod_pic: it.find('img.lazyload').attr('data-original') || '',
vod_remarks: it.find('.module-item-note').text().trim() || ''
});
});
return JSON.stringify({ list: list });
} catch (e) {
return JSON.stringify({ list: [] });
}
}
async function category(tid, pg, filter, extend) {
if (!pg || pg <= 0) pg = 1;
const area = extend.area || '';
const by = extend.by || 'time';
const cls = extend.class || '';
const lang = extend.lang || '';
const letter = extend.letter || '';
const year = extend.year || '';
const url = `${HOST}/show/${tid}-${area}-${by}-${cls}-${lang}-${letter}---${pg}---${year}.html`;
try {
const res = await req(url, {
headers: { 'User-Agent': UA }
});
const $ = load(res.content);
const list = [];
$('.module-poster-item.module-item').each((_, item) => {
const it = $(item);
const href = it.attr('href');
const vod_id = href ? href.match(/\/detail\/(\d+)\.html/)?.[1] : '';
list.push({
vod_id: vod_id || href,
vod_name: it.attr('title') || '',
vod_pic: it.find('img.lazyload').attr('data-original') || '',
vod_remarks: it.find('.module-item-note').text().trim() || ''
});
});
const hasNext = res.content.includes('title="下一页"') || res.content.includes('class="next"');
const pagecount = hasNext ? pg + 1 : pg;
return JSON.stringify({
page: pg,
pagecount: pagecount,
limit: 72,
total: list.length * (hasNext ? 2 : 1),
list: list
});
} catch (e) {
return JSON.stringify({
page: pg,
pagecount: pg,
limit: 0,
total: 0,
list: []
});
}
}
async function search(wd, pg) {
if (!pg || pg <= 0) pg = 1;
const url = `${HOST}/search/-------------.html?wd=${encodeURIComponent(wd)}&page=${pg}`;
try {
const res = await req(url, {
headers: { 'User-Agent': UA }
});
const $ = load(res.content);
const list = [];
$('.module-card-item.module-item').each((_, item) => {
const it = $(item);
const link = it.find('.module-card-item-poster');
const href = link.attr('href');
const vod_id = href ? href.match(/\/detail\/(\d+)\.html/)?.[1] : '';
list.push({
vod_id: vod_id || href,
vod_name: it.find('.module-card-item-title strong').text().trim() || '',
vod_pic: link.find('img.lazyload').attr('data-original') || '',
vod_remarks: link.find('.module-item-note').text().trim() || ''
});
});
const hasNext = list.length >= 20;
const pagecount = hasNext ? pg + 1 : pg;
return JSON.stringify({
page: pg,
pagecount: pagecount,
total: list.length,
list: list
});
} catch (e) {
return JSON.stringify({
page: pg,
pagecount: pg,
total: 0,
list: []
});
}
}
async function detail(id) {
try {
const res = await req(id.startsWith('http') ? id : `${HOST}/detail/${id}.html`, {
headers: { 'User-Agent': UA }
});
const $ = load(res.content);
const vod_name = $('h1').first().text().trim() || '';
const vod_pic = $('.module-info-poster img.lazyload').attr('data-original') || '';
let vod_year = '';
let vod_area = '';
let vod_type = '';
$('.module-info-tag-link a').each((_, el) => {
const text = $(el).text().trim();
if (/^\d{4}$/.test(text)) {
vod_year = text;
} else if (['大陆', '香港', '台湾', '美国', '日本', '韩国', '欧美', '港台'].includes(text)) {
vod_area = text;
} else if (!vod_type) {
vod_type = text;
}
});
let vod_director = '';
let vod_actor = '';
let vod_remarks = '';
$('.module-info-item').each((_, el) => {
const title = $(el).find('.module-info-item-title').text().trim();
const content = $(el).find('.module-info-item-content').text().trim();
if (title.includes('导演')) {
vod_director = content.replace(/\s+/g, ' ').trim();
} else if (title.includes('主演')) {
vod_actor = content.replace(/\s+/g, ' ').trim();
} else if (title.includes('备注') || title.includes('更新')) {
vod_remarks = content;
}
});
const vod_content = $('.module-info-introduction-content').text().trim() || '';
const playFrom = [];
const playUrls = [];
$('.module-tab-item.tab-item').each((i, el) => {
const from = $(el).find('span').text().trim() || `线路${i + 1}`;
const urls = [];
$('.module-play-list-content').eq(i).find('a.module-play-list-link').each((_, a) => {
const name = $(a).text().trim();
const href = $(a).attr('href');
const fullUrl = href && href.startsWith('http') ? href : `${HOST}${href}`;
if (name && fullUrl) {
urls.push(`${name}$${fullUrl}`);
}
});
if (urls.length > 0) {
playFrom.push(from);
playUrls.push(urls.join('#'));
}
});
const vod = {
vod_id: id,
vod_name: vod_name,
vod_pic: vod_pic,
vod_year: vod_year,
vod_area: vod_area,
vod_type: vod_type,
vod_remarks: vod_remarks,
vod_actor: vod_actor,
vod_director: vod_director,
vod_content: vod_content,
vod_play_from: playFrom.join('$$$'),
vod_play_url: playUrls.join('$$$')
};
return JSON.stringify({ list: [vod] });
} catch (e) {
return JSON.stringify({ list: [] });
}
}
// MD5 哈希函数
function md5X(str) {
return Crypto.MD5(str).toString();
}
// AES 解密函数
function aesX(mode, isEncrypt, data, isBase64, key, iv, isKeyBase64) {
try {
let keyWord = Crypto.enc.Utf8.parse(key);
let ivWord = Crypto.enc.Utf8.parse(iv);
let decrypted = Crypto.AES.decrypt(data, keyWord, {
iv: ivWord,
mode: Crypto.mode.CBC,
padding: Crypto.pad.Pkcs7
});
return decrypted.toString(Crypto.enc.Utf8);
} catch (e) {
return '';
}
}
// RC4 加密
function rc4Encrypt(data, key) {
const keyWord = Crypto.enc.Utf8.parse(key);
const encrypted = Crypto.RC4.encrypt(data, keyWord);
return encrypted.toString();
}
// RC4 解密
function rc4Decrypt(base64Data, key) {
const keyWord = Crypto.enc.Utf8.parse(key);
const decrypted = Crypto.RC4.decrypt(base64Data, keyWord);
return decrypted.toString(Crypto.enc.Utf8);
}
async function play(flag, id, flags) {
try {
// 获取播放页面
const res = await req(id, {
headers: {
'User-Agent': UA,
'Referer': HOST
}
});
const html = res.content;
// 提取 player_aaaa 配置
const configMatch = html.match(/player_aaaa\s*=\s*(\{[\s\S]+?})(?=\s*;\s*|\s*<\/script>)/);
if (!configMatch) {
return JSON.stringify({ parse: 1, url: id });
}
const player_aaaa = JSON.parse(configMatch[1]);
let videoUrl = player_aaaa.url;
if (!videoUrl) {
return JSON.stringify({ parse: 1, url: id });
}
// 解密 URL(如果需要)
const encrypt = String(player_aaaa.encrypt || '0');
if (encrypt === '1') {
videoUrl = decodeURIComponent(videoUrl);
} else if (encrypt === '2') {
videoUrl = Crypto.enc.Base64.parse(videoUrl).toString(Crypto.enc.Utf8);
videoUrl = decodeURIComponent(videoUrl);
}
// 如果已经是直链,直接返回
if (videoUrl && /\.(m3u8|mp4|flv|mkv)(\?|$)/i.test(videoUrl)) {
return JSON.stringify({
parse: 0,
url: videoUrl,
header: {
'User-Agent': UA,
'Referer': HOST
}
});
}
// 准备 API 请求参数
const hostName = 'xn--qvr2v.850088.xyz';
const rc4Key = (md5X(videoUrl) + ' P').slice(-22);
const rc4KeyHex = Crypto.enc.Utf8.parse(rc4Key);
const currentTime = Math.floor(Date.now() / 1000);
// 计算各种加密参数
let keyValue = rc4Encrypt(md5X(videoUrl + 'stray'), rc4Key);
let vkeyValue = rc4Encrypt(currentTime + md5X(rc4Key + 'stray'), rc4Key);
let ckeyValue = rc4Encrypt(md5X(hostName + 'stray'), rc4Key);
// 发送 API 请求获取真实地址
const apiRes = await req(`https://${hostName}/player/api.php`, {
method: 'POST',
postType: 'form',
headers: {
'User-Agent': UA,
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Origin': `https://${hostName}`,
'X-Requested-With': 'XMLHttpRequest',
'Referer': `https://${hostName}/`
},
data: {
'url': videoUrl,
'key': keyValue,
'vkey': vkeyValue,
'ckey': ckeyValue
}
});
const json = JSON.parse(apiRes.content);
if (json.code === 200 || json.code === '200') {
// 解密 AES key 和 iv
const aesKey = rc4Decrypt(json.aes_key, rc4Key);
const aesIv = rc4Decrypt(json.aes_iv, rc4Key);
// 解密真实视频地址
const realUrl = aesX('AES/CBC/PKCS7', false, json.url, true, aesKey, aesIv, false);
if (realUrl && realUrl.startsWith('http')) {
return JSON.stringify({
parse: 0,
url: realUrl,
header: {
'User-Agent': UA,
'Referer': HOST
}
});
}
}
return JSON.stringify({ parse: 1, url: videoUrl });
} catch (e) {
return JSON.stringify({ parse: 1, url: id });
}
}
export function __jsEvalReturn() {
return {
init,
home,
homeVod,
category,
detail,
search,
play
};
}
Binary file not shown.
@@ -1,39 +0,0 @@
var rule = {
title:'奇珍异兽',
host:'https://www.iqiyi.com',
homeUrl:'',
// detailUrl:'https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid=fyid&size=2000&page=1',
detailUrl:'https://pcw-api.iqiyi.com/video/video/videoinfowithuser/fyid?agent_type=1&authcookie=&subkey=fyid&subscribe=1',
searchUrl:'https://search.video.iqiyi.com/o?if=html5&key=**&pageNum=fypage&pos=1&pageSize=24&site=iqiyi',
searchable:2,
multi:1,
filterable:1,
filter:{'1': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': 'three_category_id', 'name': '地区', 'value': [{'n': '全部', 'v': ''}, {'n': '华语', 'v': 1}, {'n': '香港地区', 'v': 28997}, {'n': '美国', 'v': 2}, {'n': '欧洲', 'v': 3}, {'n': '韩国', 'v': 4}, {'n': '日本', 'v': 308}, {'n': '泰国', 'v': 1115}, {'n': '印度', 'v': 28999}, {'n': '其它', 'v': 5}]}, {'key': '18001', 'name': '类型', 'value': [{'n': '全部', 'v': ''}, {'n': '喜剧', 'v': 8}, {'n': '爱情', 'v': 6}, {'n': '动作', 'v': 11}, {'n': '枪战', 'v': 131}, {'n': '犯罪', 'v': 291}, {'n': '惊悚', 'v': 128}, {'n': '恐怖', 'v': 10}, {'n': '悬疑', 'v': 289}, {'n': '动画', 'v': 12}, {'n': '家庭', 'v': 27356}, {'n': '奇幻', 'v': 1284}, {'n': '魔幻', 'v': 129}, {'n': '科幻', 'v': 9}, {'n': '战争', 'v': 7}, {'n': '青春', 'v': 130}]}, {'key': '27396', 'name': '规格', 'value': [{'n': '全部', 'v': ''}, {'n': '巨制', 'v': 27397}, {'n': '院线', 'v': 27815}, {'n': '独播', 'v': 30149}, {'n': '网络电影', 'v': 27401}]}], '2': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': 'three_category_id', 'name': '地区', 'value': [{'n': '全部', 'v': ''}, {'n': '内地', 'v': 15}, {'n': '港剧', 'v': 16}, {'n': '韩剧', 'v': 17}, {'n': '美剧', 'v': 18}, {'n': '日剧', 'v': 309}, {'n': '泰剧', 'v': 1114}, {'n': '台湾地区', 'v': 1117}, {'n': '英剧', 'v': 28916}, {'n': '其它', 'v': 19}]}, {'key': '18003', 'name': '类型', 'value': [{'n': '全部', 'v': ''}, {'n': '自制', 'v': 11992}, {'n': '古装', 'v': 24}, {'n': '言情', 'v': 20}, {'n': '武侠', 'v': 23}, {'n': '偶像', 'v': 30}, {'n': '家庭', 'v': 1654}, {'n': '青春', 'v': 1653}, {'n': '都市', 'v': 24064}, {'n': '喜剧', 'v': 135}, {'n': '战争', 'v': 27916}, {'n': '军旅', 'v': 1655}, {'n': '谍战', 'v': 290}, {'n': '悬疑', 'v': 32}, {'n': '罪案', 'v': 149}, {'n': '穿越', 'v': 148}, {'n': '宫廷', 'v': 139}, {'n': '历史', 'v': 21}, {'n': '神话', 'v': 145}, {'n': '科幻', 'v': 34}, {'n': '年代', 'v': 27}, {'n': '农村', 'v': 29}, {'n': '商战', 'v': 140}, {'n': '剧情', 'v': 24063}, {'n': '奇幻', 'v': 27881}, {'n': '网剧', 'v': 24065}, {'n': '竖短片', 'v': 32839}]}], '3': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': 'three_category_id', 'name': '地区', 'value': [{'n': '全部', 'v': ''}, {'n': '国内', 'v': 20323}, {'n': '国外', 'v': 20324}]}, {'key': '18004', 'name': '类型', 'value': [{'n': '全部', 'v': ''}, {'n': '人文', 'v': 70}, {'n': '美食', 'v': 33908}, {'n': '医疗', 'v': 33924}, {'n': '自然', 'v': 33933}, {'n': '萌宠', 'v': 33945}, {'n': '财经', 'v': 33953}, {'n': '罪案', 'v': 33960}, {'n': '竞技', 'v': 33967}, {'n': '灾难', 'v': 33974}, {'n': '军事', 'v': 72}, {'n': '历史', 'v': 74}, {'n': '探险', 'v': 73}, {'n': '社会', 'v': 71}, {'n': '科技', 'v': 28119}, {'n': '旅游', 'v': 310}]}, {'key': '28467', 'name': '出品方', 'value': [{'n': '全部', 'v': ''}, {'n': 'BBC', 'v': 28468}, {'n': '美国历史频道', 'v': 28470}, {'n': '探索频道', 'v': 28471}, {'n': '央视记录', 'v': 28472}, {'n': '北京纪实频道', 'v': 28473}, {'n': '上海纪实频道', 'v': 28474}, {'n': '朗思文化', 'v': 28476}, {'n': 'CNEX', 'v': 28477}, {'n': '五星传奇', 'v': 28478}, {'n': 'IMG', 'v': 28479}, {'n': 'NHK', 'v': 28480}, {'n': '爱奇艺出品', 'v': 31283}, {'n': 'Netflix', 'v': 31286}]}, {'key': '29076', 'name': '片种', 'value': [{'n': '全部', 'v': ''}, {'n': '纪录电影', 'v': 29077}, {'n': '系列纪录片', 'v': 29078}, {'n': '网络纪录片', 'v': 29082}, {'n': '纪实栏目', 'v': 29083}]}, {'key': '31294', 'name': '时长', 'value': [{'n': '全部', 'v': ''}, {'n': '微纪录', 'v': 29079}, {'n': '长纪录', 'v': 29080}, {'n': '短纪录', 'v': 29081}]}], '4': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': 'three_category_id', 'name': '地区', 'value': [{'n': '全部', 'v': ''}, {'n': '中国大陆', 'v': 37}, {'n': '日本', 'v': 38}, {'n': '韩国', 'v': 1106}, {'n': '欧美', 'v': 30218}, {'n': '其它', 'v': 40}]}, {'key': '30219', 'name': '版本', 'value': [{'n': '全部', 'v': ''}, {'n': '动画', 'v': 30220}, {'n': '特摄', 'v': 30223}, {'n': '布袋戏', 'v': 30224}, {'n': '特别篇', 'v': 32782}, {'n': '动态漫画', 'v': 32783}, {'n': '动画电影', 'v': 32784}, {'n': '竖版视频', 'v': 32785}, {'n': '轻动画', 'v': 33482}, {'n': '短剧', 'v': 33483}]}, {'key': '30225', 'name': '风格', 'value': [{'n': '全部', 'v': ''}, {'n': '搞笑', 'v': 30230}, {'n': '热血', 'v': 30232}, {'n': '催泪', 'v': 30233}, {'n': '治愈', 'v': 30234}, {'n': '励志', 'v': 30237}, {'n': '机战', 'v': 30241}, {'n': '恋爱', 'v': 30243}, {'n': '科幻', 'v': 30245}, {'n': '奇幻', 'v': 30247}, {'n': '推理', 'v': 30248}, {'n': '校园', 'v': 30249}, {'n': '日常', 'v': 30252}, {'n': '历史', 'v': 30254}, {'n': '美食', 'v': 30255}, {'n': '职场', 'v': 30256}, {'n': '偶像', 'v': 30258}, {'n': '泡面', 'v': 30265}, {'n': '冒险', 'v': 30267}, {'n': '竞技', 'v': 30268}, {'n': '合家欢', 'v': 30270}, {'n': '武侠', 'v': 32792}, {'n': '玄幻', 'v': 32793}]}, {'key': '32795', 'name': '新类型', 'value': [{'n': '全部', 'v': ''}, {'n': '轻小说改编', 'v': 32796}, {'n': '漫画改编', 'v': 32797}, {'n': '游戏改编', 'v': 32798}, {'n': '原创', 'v': 32799}]}], '6': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': 'three_category_id', 'name': '地区', 'value': [{'n': '全部', 'v': ''}, {'n': '内地', 'v': 151}, {'n': '港台', 'v': 152}, {'n': '韩国', 'v': 33306}, {'n': '欧美', 'v': 154}, {'n': '其它', 'v': 1113}]}, {'key': '18014', 'name': '类型', 'value': [{'n': '全部', 'v': ''}, {'n': '播报', 'v': 155}, {'n': '访谈', 'v': 156}, {'n': '游戏', 'v': 158}, {'n': '晚会', 'v': 292}, {'n': '曲艺', 'v': 293}, {'n': '脱口秀', 'v': 2118}, {'n': '真人秀', 'v': 2224}, {'n': '竞技', 'v': 30278}, {'n': '爱奇艺出品', 'v': 30279}, {'n': '竞演', 'v': 33860}]}, {'key': '33162', 'name': '题材', 'value': [{'n': '全部', 'v': ''}, {'n': '音乐', 'v': 33163}, {'n': '舞蹈', 'v': 33172}, {'n': '文化', 'v': 33173}, {'n': '美食', 'v': 33182}, {'n': '伦理', 'v': 33184}, {'n': '相亲', 'v': 33193}, {'n': '纪实', 'v': 33195}, {'n': '生活', 'v': 33196}, {'n': '亲子', 'v': 33197}, {'n': '少儿', 'v': 33198}, {'n': '财经', 'v': 33199}, {'n': '健康', 'v': 33200}, {'n': '时尚', 'v': 33203}, {'n': '旅游', 'v': 33205}, {'n': '教育', 'v': 33206}, {'n': '其它', 'v': 33220}, {'n': '爱情', 'v': 33316}, {'n': '搞笑', 'v': 33317}, {'n': '益智', 'v': 33318}, {'n': '职场', 'v': 33319}, {'n': '语言', 'v': 33530}, {'n': '辩论', 'v': 33531}, {'n': '演讲', 'v': 33843}]}], '5': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': 'three_category_id', 'name': '地区', 'value': [{'n': '全部', 'v': ''}, {'n': '内地', 'v': 221}, {'n': '港台', 'v': 220}, {'n': '欧美', 'v': 219}, {'n': '日韩', 'v': 218}, {'n': '拉美', 'v': 217}, {'n': '亚洲地区', 'v': 216}, {'n': '非洲', 'v': 215}]}, {'key': '18009', 'name': '语种', 'value': [{'n': '全部', 'v': ''}, {'n': '普通话', 'v': 91}, {'n': '粤语', 'v': 92}, {'n': '闽南语', 'v': 93}, {'n': '英语', 'v': 94}, {'n': '日语', 'v': 95}, {'n': '韩语', 'v': 96}, {'n': '其它', 'v': 97}]}, {'key': '23554', 'name': '音乐类型', 'value': [{'n': '全部', 'v': ''}, {'n': '单曲MV', 'v': 23556}, {'n': '单曲现场', 'v': 23557}, {'n': '演唱会', 'v': 23558}, {'n': '新闻', 'v': 23559}, {'n': '访谈', 'v': 23560}, {'n': '音乐记录', 'v': 23561}, {'n': '音乐周边', 'v': 23562}, {'n': '音乐节目', 'v': 23563}, {'n': '影视原声', 'v': 23564}, {'n': '音乐短片', 'v': 23565}, {'n': '其他', 'v': 23566}]}], '16': [{'key': 'mode', 'name': '综合排序', 'value': [{'n': '全部', 'v': ''}, {'n': '热播榜', 'v': 11}, {'n': '好评榜', 'v': 8}, {'n': '新上线', 'v': 4}]}, {'key': 'year', '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': '2018', 'v': 2018}, {'n': '2017', 'v': 2017}, {'n': '2016-2011', 'v': '2011_2016'}, {'n': '2010-2000', 'v': '2000_2010'}, {'n': '90年代', 'v': '1990_1999'}, {'n': '80年代', 'v': '1980_1989'}, {'n': '更早', 'v': '1964_1979'}]}, {'key': 'is_purchase', 'name': '全部资费', 'value': [{'n': '全部', 'v': ''}, {'n': '免费', 'v': 0}, {'n': '会员', 'v': 1}, {'n': '付费', 'v': 2}]}, {'key': '18061', 'name': '类型', 'value': [{'n': '全部', 'v': ''}, {'n': '喜剧', 'v': 1296}, {'n': '爱情', 'v': 1297}, {'n': '动作', 'v': 1298}, {'n': '奇幻', 'v': 1299}, {'n': '惊悚', 'v': 1300}, {'n': '悬疑', 'v': 1301}, {'n': '青春', 'v': 1302}]}]},
// url:'https://pcw-api.iqiyi.com/search/recommend/list?channel_id=fyclass&data_type=1&is_purchase=&mode=24&page_id=fypage&ret_num=48&three_category_id=',
url:'https://pcw-api.iqiyi.com/search/recommend/list?channel_id=fyclass&data_type=1&page_id=fypage&ret_num=48',
filter_url:'is_purchase={{fl.is_purchase}}&mode={{fl.mode}}&three_category_id={{fl.three_category_id}}&market_release_date_level={{fl.year}}',
// url:'https://pcw-api.iqiyi.com/search/video/videolists?channel_id=fyclass&pageNum=fypage&pageSize=24&data_type=1&site=iqiyi',
headers:{
'User-Agent':'MOBILE_UA'
},
timeout:5000,
class_name:'电影&电视剧&纪录片&动漫&综艺&音乐&网络电影',
class_url:'1&2&3&4&6&5&16',
limit:20,
// play_parse:true,
// 手动调用解析请求json的url,此lazy不方便
lazy:'js:input=""+input.split("?")[0];log(input);let html=JSON.parse(request(input));log(html);input=html.url||input',
// 推荐:'.list_item;img&&alt;img&&src;a&&Text;a&&data-float',
// 一级:'json:.data.list;.name;.imageUrl;.latestOrder;.albumId',
推荐:'',
// 推荐:'js:let d=[];fetch_params.headers["user-agent"]=PC_UA;pdfh=jsp.pdfh;pdfa=jsp.pdfa;pd=jsp.pd;let html=fetch(HOST,fetch_params);let lists=pdfa(html,".qy-mod-li");lists.forEach(function(it){try{let title=pdfh(it,"p.sub&&title");let desc=pdfh(it,".qy-mod-label&&Text");let pic_url=pd(it,"img&&src");d.push({title:title,desc:desc,img:pic_url})}catch(e){}});res=setResult(d);',
一级:'js:let d=[];if(MY_CATE==="16"){input=input.replace("channel_id=16","channel_id=1").split("three_category_id")[0];input+="three_category_id=27401"}else if(MY_CATE==="5"){input=input.replace("data_type=1","data_type=2")}let html=request(input);let json=JSON.parse(html);if(json.code==="A00003"){fetch_params.headers["user-agent"]=PC_UA;json=JSON.parse(fetch(input,fetch_params))}json.data.list.forEach(function(data){if(data.channelId===1){desc=data.hasOwnProperty("score")?data.score+"分\\t":""}else if(data.channelId===2||data.channelId===4){if(data.latestOrder===data.videoCount){desc=(data.hasOwnProperty("score")?data.score+"分\\t":"")+data.latestOrder+"集全"}else{if(data.videoCount){desc=(data.hasOwnProperty("score")?data.score+"分\\t":"")+data.latestOrder+"/"+data.videoCount+"集"}else{desc="更新至 "+data.latestOrder+"集"}}}else if(data.channelId===6){desc=data.period+"期"}else if(data.channelId===5){desc=data.focus}else{if(data.latestOrder){desc="更新至 第"+data.latestOrder+"期"}else if(data.period){desc=data.period}else{desc=data.focus}}url=MY_CATE+"$"+data.albumId;d.push({url:url,title:data.name,desc:desc,pic_url:data.imageUrl.replace(".jpg","_390_520.jpg?caplist=jpg,webp")})});setResult(d);',
// 一级:'js:let d=[];if(MY_CATE==="16"){input=input.replace("channel_id=16","channel_id=1").split("three_category_id")[0];input+="three_category_id=27401"}else if(MY_CATE==="5"){input=input.replace("data_type=1","data_type=2")}let html=fetch(input,fetch_params);let json=JSON.parse(html);if(json.code==="A00003"){fetch_params.headers["user-agent"]=PC_UA;json=JSON.parse(fetch(input,fetch_params))}json.data.list.forEach(function(data){if(data.channelId===1){desc=data.hasOwnProperty("score")?data.score+"分\\t":""}else if(data.channelId===2||data.channelId===4){if(data.latestOrder===data.videoCount){desc=(data.hasOwnProperty("score")?data.score+"分\\t":"")+data.latestOrder+"集全"}else{if(data.videoCount){desc=(data.hasOwnProperty("score")?data.score+"分\\t":"")+data.latestOrder+"/"+data.videoCount+"集"}else{desc="更新至 "+data.latestOrder+"集"}}}else if(data.channelId===6){desc=data.period+"期"}else if(data.channelId===5){desc=data.focus}else{if(data.latestOrder){desc="更新至 第"+data.latestOrder+"期"}else if(data.period){desc=data.period}else{desc=data.focus}}url=MY_CATE+"$"+data.albumId;d.push({url:url,title:data.name,desc:desc,pic_url:data.imageUrl.replace(".jpg","_390_520.jpg?caplist=jpg,webp")})});setResult(d);',
// 一级:'json:.data.list;.name;.imageUrl;.playUrl;.latestOrder',
// 二级:{is_json:1,"title":"data.title;data.moviecategory[0]+data.moviecategory[1]","img":"data.cdncover","desc":"data.area[0];data.director[0]","content":"data.description","tabs":"data.playlink_sites;data.playlinksdetail.#idv.quality","lists":"data.playlinksdetail.#idv.default_url"},
// 二级:{is_json:1,"title":"data.name+data.subtitle;data.latestOrder","img":"data.imageUrl","desc":"data.categories;data.areas","content":"data.description","tabs":"data.name","lists":"data.playlinksdetail.#idv.default_url"},
二级:'',
二级:'js:let d=[];let html=request(input);let json=JSON.parse(html).data;VOD={vod_id:"",vod_url:input,vod_name:"",type_name:"",vod_actor:"",vod_year:"",vod_director:"",vod_area:"",vod_content:"",vod_remarks:"",vod_pic:""};VOD.vod_name=json.name;try{if(json.latestOrder){VOD.vod_remarks="类型: "+(json.categories[0].name||"")+"\\t"+(json.categories[1].name||"")+"\\t"+(json.categories[2].name||"")+"\\t"+"评分:"+(json.score||"")+"\\n更新至:第"+json.latestOrder+"集(期)/共"+json.videoCount+"集(期)"}else{VOD.vod_remarks="类型: "+(json.categories[0].name||"")+"\\t"+(json.categories[1].name||"")+"\\t"+(json.categories[2].name||"")+"\\t"+"评分:"+(json.score||"")+json.period}}catch(e){VOD.vod_remarks=json.subtitle}VOD.vod_area=(json.focus||"")+"\\n资费:"+(json.payMark===1?"VIP":"免费")+"\\n地区:"+(json.areas||"");let vsize="579_772";try{vsize=json.imageSize[12]}catch(e){}VOD.vod_pic=json.imageUrl.replace(".jpg","_"+vsize+".jpg?caplist=jpg,webp");VOD.type_name=json.categories.map(function(it){return it.name}).join(",");if(json.people.main_charactor){let vod_actors=[];json.people.main_charactor.forEach(function(it){vod_actors.push(it.name)});VOD.vod_actor=vod_actors.join(",")}VOD.vod_content=json.description;let playlists=[];if(json.channelId===1||json.channelId===5){playlists=[{playUrl:json.playUrl,imageUrl:json.imageUrl,shortTitle:json.shortTitle,focus:json.focus,period:json.period}]}else{if(json.channelId===6){let qs=json.period.split("-")[0];let listUrl="https://pcw-api.iqiyi.com/album/source/svlistinfo?cid=6&sourceid="+json.albumId+"&timelist="+qs;let playData=JSON.parse(request(listUrl)).data[qs];playData.forEach(function(it){playlists.push({playUrl:it.playUrl,imageUrl:it.imageUrl,shortTitle:it.shortTitle,focus:it.focus,period:it.period})})}else{let listUrl="https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid="+json.albumId+"&size=200&page=1";let data=JSON.parse(request(listUrl)).data;let total=data.total;playlists=data.epsodelist;if(total>200){for(let i=2;i<total/200+1;i++){let listUrl="https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid="+json.albumId+"&size=200&page="+i;let data=JSON.parse(request(listUrl)).data;playlists=playlists.concat(data.epsodelist)}}}}playlists.forEach(function(it){d.push({title:it.shortTitle||"第"+it.order+"集",desc:it.subtitle||it.focus||it.period,img:it.imageUrl.replace(".jpg","_480_270.jpg?caplist=jpg,webp"),url:it.playUrl})});VOD.vod_play_from="qiyi";VOD.vod_play_url=d.map(function(it){return it.title+"$"+it.url}).join("#");',
// 二级:'js:let d=[];let html=request(input);let json=JSON.parse(html).data;vod={vod_id:"",vod_url:input,vod_name:"",type_name:"",vod_actor:"",vod_year:"",vod_director:"",vod_area:"",vod_content:"",vod_remarks:"",vod_pic:""};vod.vod_name=json.name;try{if(json.latestOrder){vod.vod_remarks="类型: "+(json.categories[0].name||"")+"\\t"+(json.categories[1].name||"")+"\\t"+(json.categories[2].name||"")+"\\t"+"评分:"+(json.score||"")+"\\n更新至:第"+json.latestOrder+"集(期)/共"+json.videoCount+"集(期)"}else{vod.vod_remarks="类型: "+(json.categories[0].name||"")+"\\t"+(json.categories[1].name||"")+"\\t"+(json.categories[2].name||"")+"\\t"+"评分:"+(json.score||"")+json.period}}catch(e){vod.vod_remarks=json.subtitle}vod.vod_area=(json.focus||"")+"\\n资费:"+(json.payMark===1?"VIP":"免费")+"\\n地区:"+(json.areas||"");let vsize="579_772";try{vsize=json.imageSize[12]}catch(e){}vod.vod_pic=json.imageUrl.replace(".jpg","_"+vsize+".jpg?caplist=jpg,webp");vod.type_name=json.categories.map(function(it){return it.name}).join(",");if(json.people.main_charactor){vod_actors=[];json.people.main_charactor.forEach(function(it){vod_actors.push(it.name)});vod.vod_actor=vod_actors.join(",")}vod.vod_content=json.description;let playlists=[];if(json.channelId===1||json.channelId===5){playlists=[{playUrl:json.playUrl,imageUrl:json.imageUrl,shortTitle:json.shortTitle,focus:json.focus,period:json.period}]}else{if(json.channelId===6){let qs=json.period.split("-")[0];let listUrl="https://pcw-api.iqiyi.com/album/source/svlistinfo?cid=6&sourceid="+json.albumId+"&timelist="+qs;let playData=JSON.parse(request(listUrl)).data[qs];playData.forEach(function(it){playlists.push({playUrl:it.playUrl,imageUrl:it.imageUrl,shortTitle:it.shortTitle,focus:it.focus,period:it.period})})}else{let listUrl="https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid="+json.albumId+"&size=200&page=1";let data=JSON.parse(request(listUrl)).data;let total=data.total;playlists=data.epsodelist;if(total>200){for(let i=2;i<total/200+1;i++){let listUrl="https://pcw-api.iqiyi.com/albums/album/avlistinfo?aid="+json.albumId+"&size=200&page="+i;let data=JSON.parse(request(listUrl)).data;playlists=playlists.concat(data.epsodelist)}}}}playlists.forEach(function(it){d.push({title:it.shortTitle||"第"+it.order+"集",desc:it.subtitle||it.focus||it.period,img:it.imageUrl.replace(".jpg","_480_270.jpg?caplist=jpg,webp"),url:it.playUrl})});vod.vod_play_from="qiyi";vod.vod_play_url=d.map(function(it){return it.title+"$"+it.url}).join("#");',
搜索:'json:.data.docinfos;.albumDocInfo.albumTitle;.albumDocInfo.albumVImage;.albumDocInfo.channel;.albumDocInfo.albumId;.albumDocInfo.tvFocus',
}
-178
Melihat File
@@ -1,178 +0,0 @@
# -*- coding: utf-8 -*-
# 本资源来源于互联网公开渠道,仅可用于个人学习及爬虫技术交流。
# 严禁将其用于任何商业用途,下载后请于 24 小时内删除,搜索结果均来自源站,本人不承担任何责任。
"""
{
"key": "皮皮虾",
"name": "🔰皮皮虾|4K线路",
"type": 3,
"api": "./py/皮皮虾1.py",
"ext": "http://38.55.237.41:8762",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7InVzZXJfY2hlY2siOiI4ZTEyNDE1Y2UyOGQzMGM4MWE3MDBiNWYxMDgzZTU2OCIsInVzZXJfaWQiOjM0NTYsInVzZXJfbmFtZSI6IjEwMTAxMiJ9LCJleHAiOjE4MDQ3MzkyODAuNjA4MTA4MywiaWF0IjoxNzczMjAzMjgxLCJpc3MiOiJBcHBUbyIsImp0aSI6ImZmZDMyYjk4N2VkMTg1ZjNiNGQ5Zjc5NzU2YWRjNGQ5IiwibmJmIjoxNzczMjAzMjgxLCJzdWIiOiJBcHBUbyJ9.tDhURwWVzsPy0-yXvo_d3bgsmoq9Ri5n0Y4fQsvxKy0"
}
"""
import re,sys,uuid
from base.spider import Spider
sys.path.append('..')
class Spider(Spider):
host,config,local_uuid,parsing_config = '','','',[]
# 头部添加token认证
headers = {
'User-Agent': "Dart/2.19 (dart:io)",
'Accept-Encoding': "gzip",
'appto-local-uuid': local_uuid,
'token': "eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7InVzZXJfY2hlY2siOiI4ZTEyNDE1Y2UyOGQzMGM4MWE3MDBiNWYxMDgzZTU2OCIsInVzZXJfaWQiOjM0NTYsInVzZXJfbmFtZSI6IjEwMTAxMiJ9LCJleHAiOjE4MDQ3MzkyODAuNjA4MTA4MywiaWF0IjoxNzczMjAzMjgxLCJpc3MiOiJBcHBUbyIsImp0aSI6ImZmZDMyYjk4N2VkMTg1ZjNiNGQ5Zjc5NzU2YWRjNGQ5IiwibmJmIjoxNzczMjAzMjgxLCJzdWIiOiJBcHBUbyJ9.tDhURwWVzsPy0-yXvo_d3bgsmoq9Ri5n0Y4fQsvxKy0"
}
def init(self, extend=''):
try:
host = extend.strip()
if not host.startswith('http'):
return {}
if not re.match(r'^https?://[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:\d+)?/?$', host):
host_=self.fetch(host).json()
self.host = host_['domain']
else:
self.host = host
self.local_uuid = str(uuid.uuid4())
# 动态更新headers中的uuid(避免初始化时uuid为空)
self.headers['appto-local-uuid'] = self.local_uuid
response = self.fetch(f'{self.host}/apptov5/v1/config/get?p=android&__platform=android', headers=self.headers).json()
config = response['data']
self.config = config
parsing_conf = config['get_parsing']['lists']
parsing_config = {}
for i in parsing_conf:
if len(i['config']) != 0:
label = []
for j in i['config']:
if j['type'] == 'json':
label.append(j['label'])
parsing_config.update({i['key']:label})
self.parsing_config = parsing_config
return None
except Exception as e:
print(f'初始化异常:{e}')
return {}
def detailContent(self, ids):
response = self.fetch(f"{self.host}/apptov5/v1/vod/getVod?id={ids[0]}",headers=self.headers).json()
data3 = response['data']
videos = []
vod_play_url = ''
vod_play_from = ''
for i in data3['vod_play_list']:
play_url = ''
for j in i['urls']:
play_url += f"{j['name']}${i['player_info']['from']}@{j['url']}#"
vod_play_from += i['player_info']['show'] + '$$$'
vod_play_url += play_url.rstrip('#') + '$$$'
vod_play_url = vod_play_url.rstrip('$$$')
vod_play_from = vod_play_from.rstrip('$$$')
videos.append({
'vod_id': data3.get('vod_id'),
'vod_name': data3.get('vod_name'),
'vod_content': data3.get('vod_content'),
'vod_remarks': data3.get('vod_remarks'),
'vod_director': data3.get('vod_director'),
'vod_actor': data3.get('vod_actor'),
'vod_year': data3.get('vod_year'),
'vod_area': data3.get('vod_area'),
'vod_play_from': vod_play_from,
'vod_play_url': vod_play_url
})
return {'list': videos}
def searchContent(self, key, quick, pg='1'):
url = f"{self.host}/apptov5/v1/search/lists?wd={key}&page={pg}&type=&__platform=android"
response = self.fetch(url, headers=self.headers).json()
data = response['data']['data']
for i in data:
if i.get('vod_pic').startswith('mac://'):
i['vod_pic'] = i['vod_pic'].replace('mac://', 'http://', 1)
return {'list': data, 'page': pg, 'total': response['data']['total']}
def playerContent(self, flag, id, vipflags):
default_ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
parsing_config = self.parsing_config
parts = id.split('@')
if len(parts) != 2:
return {'parse': 0, 'url': id, 'header': {'User-Agent': default_ua}}
playfrom, rawurl = parts
label_list = parsing_config.get(playfrom)
if not label_list:
return {'parse': 0, 'url': rawurl, 'header': {'User-Agent': default_ua}}
result = {'parse': 1, 'url': rawurl, 'header': {'User-Agent': default_ua}}
for label in label_list:
payload = {
'play_url': rawurl,
'label': label,
'key': playfrom
}
try:
response = self.post(
f"{self.host}/apptov5/v1/parsing/proxy?__platform=android",
data=payload,
headers=self.headers
).json()
except Exception as e:
print(f"请求异常: {e}")
continue
if not isinstance(response, dict):
continue
if response.get('code') == 422:
continue
data = response.get('data')
if not isinstance(data, dict):
continue
url = data.get('url')
if not url:
continue
ua = data.get('UA') or data.get('UserAgent') or default_ua
result = {
'parse': 0,
'url': url,
'header': {'User-Agent': ua}
}
break
return result
def homeContent(self, filter):
config = self.config
if not config:
return {}
home_cate = config['get_home_cate']
classes = []
for i in home_cate:
if isinstance(i.get('extend', []),dict):
classes.append({'type_id': i['cate'], 'type_name': i['title']})
return {'class': classes}
def homeVideoContent(self):
response = self.fetch(f'{self.host}/apptov5/v1/home/data?id=1&mold=1&__platform=android',headers=self.headers).json()
data = response['data']
vod_list = []
for i in data['sections']:
for j in i['items']:
vod_pic = j.get('vod_pic')
if vod_pic.startswith('mac://'):
vod_pic = vod_pic.replace('mac://', 'http://', 1)
vod_list.append({
"vod_id": j.get('vod_id'),
"vod_name": j.get('vod_name'),
"vod_pic": vod_pic,
"vod_remarks": j.get('vod_remarks')
})
return {'list': vod_list}
def categoryContent(self, tid, pg, filter, extend):
response = self.fetch(f"{self.host}/apptov5/v1/vod/lists?area={extend.get('area','')}&lang={extend.get('lang','')}&year={extend.get('year','')}&order={extend.get('sort','time')}&type_id={tid}&type_name=&page={pg}&pageSize=21&__platform=android", headers=self.headers).json()
data = response['data']
data2 = data['data']
for i in data['data']:
if i.get('vod_pic','').startswith('mac://'):
i['vod_pic'] = i['vod_pic'].replace('mac://', 'http://', 1)
return {'list': data2, 'page': pg, 'total': data['total']}
def getName(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
def localProxy(self, param):
pass
@@ -1,275 +0,0 @@
var rule = {
title: '小心儿悠悠',
host: 'https://v.qq.com',
homeUrl: '/x/bu/pagesheet/list?_all=1&append=1&channel=cartoon&listpage=1&offset=0&pagesize=21&iarea=-1&sort=18',
detailUrl: 'https://node.video.qq.com/x/api/float_vinfo2?cid=fyid',
searchUrl: '**',
searchable: 1,
filterable: 1,
multi: 1,
url: '/x/bu/pagesheet/list?_all=1&append=1&channel=fyclass&listpage=1&offset=((fypage-1)*21)&pagesize=21&iarea=-1',
filter_url: 'sort={{fl.sort or 75}}&iyear={{fl.iyear}}&year={{fl.year}}&itype={{fl.type}}&ifeature={{fl.feature}}&iarea={{fl.area}}&itrailer={{fl.itrailer}}&gender={{fl.sex}}',
filter: 'H4sIAAAAAAAAA+1YW08TWxR+92fMMySdFlrwEY3RnOT4YnzQ8DDBOaERqamVHGJIWksvXFIoYvEcSuViDxVpKYpYprb+mdl7Zv6Fe9rurrXdqE2OlRd4mvnW7L3u31r0mTIxGQpO6MrV+8+Uh/qsclV5EgpHlAFlWnvEUIVm1oixwt5ntKmn7c+mXTgfteJlF2YvgWFlbqCL01y1g4/4ujgpNuyjeY6ryty4K2krDM7qWhg0krMTs74naSSJkhMvdW4YZDcMXGkLvB6vvwO3HrFgGARgI3sZAnwI4z7AfRj3Au7FuAq4inEP4B6Eq6NdnD0ifATwEYwHAA9gHBxW/RgHf9kji/H4gBKZ6UtuA6Pn59a1B+X2L12LPA3roNM6rpPCUg/ZbeNW+pjGE/xuULnyxt7jMGSEPj+0ctkODAl04g1Se96BId+kckoM7ie4SXJ5srDfgSG65udtUkxx70Fl+T+zuc0LGy5JbtINbiCEim7F7eoSdwdKw9l6S7INjiP3M1VSKXAcebS1Rl8VOQ4uWcsZMFIFn6z9LDmroxRx/F2BLkY5HkB659H3I/1t18tuhW59FJoJXigZR2Yf/49uXTyyGgdyoy0eky8bUrcKjaZ62B8q5HjZ3okimR+0CF3eOgfZEfnClX2vCZhIRcwRW6XRHJZ5kPkla104h0KcfmUaC1gfZFjgl9Y5qArmuGgnqlTWwd/YCXcKdNOSIVLMJMnKe3wnyOxozFpI4XNQDnbxC2QTwZUqabwUT7n9gYrlkgn6xwQzWjioR2b7wgVukC4Z/ffkcUILR0Kh6YvkdC2sayi9+SpZNnrmdJJMsBPSBkY3ijR/KG9gh/tWMyNxCUmcmnVOr0O/cODgPQVNAcz0UGAieSLrkmvOP28loxm30xwfWygDqwXrMCsHJLbEho+0HzrldTDlO4sXqlFxtgVwuEmtJi92dHuHbHZnDLo//9o0DLTA8e8zJWs1KS+O4uxAkayvkETtx/l0x+glm/wmNpkMTj3ozz90aHHBXPLNyH+i/430RfdJ+l3vVFL8QMq8z1ATr38C2Nsn5vLhVjqPucSS/klFO815WvnYsyWeQR95H5McHxr0AwyWBAZHAQa7VQ9DzXrRrC3KG3aiJFjVpqBWxTwITYT6UzAijwcjYS04peM4pQzyIkZzZz3HaWzsmhQkstlwF+l8FXgL/L45dpvHSUV2/nnzDzm/LYZzdrNO7IXE0rfu3OX3DPsQG2d2rZNd4QzTA+rvXb8BMPSPnWjalSM7dUDSpzJlk9W02cjTvEELvMf851fh8K8blMwYa/5Uih+b1c7e6+6CD/ibpvn5X6kE2UihuZRstDA8UP9tmsaSlAg2nGH0AT/aJ7ts2MiTieUAhjP+SaNxQHfSUibFXzTQYrKRoDBAW/09PvcVk1nUEv4UAAA=',
headers: {
'User-Agent': 'PC_UA'
},
timeout: 5000,
cate_exclude: '会员|游戏|全部',
class_name: '电影&电视剧&综艺&动漫&少儿&纪录片',
class_url: 'movie&tv&variety&cartoon&child&doco',
limit: 20,
play_parse: true,
lazy: $js.toString(() => {
let d = [];
let url1 = JSON.parse(request("" + input)).url;
function isEncrypted(url) {
return url.includes('baidu.con/') && url.length > 16;
}
let url;
if (isEncrypted(url1)) {
console.log("");
var withoutDomain = url1.replace(/^https:\/\/baidu\.con\//, '');
var first16Chars = withoutDomain.substring(0, 16);
var remainingString = withoutDomain.substring(16);
var key = CryptoJS.enc.Utf8.parse(first16Chars);
var iv = key;
function AES_Decrypt(word) {
var srcs = word;
var decrypt = CryptoJS.AES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypt.toString(CryptoJS.enc.Utf8);
};
url = AES_Decrypt(remainingString);
} else {
console.log("");
url = url1;
}
input = {
url: url,
parse: 0,
header: rule.headers
}
setResult(d);
}),
推荐: '.list_item;img&&alt;img&&src;a&&Text;a&&data-float',
一级: '.list_item;img&&alt;img&&src;a&&Text;a&&data-float',
二级: $js.toString(() => {
VOD = {};
let d = [];
let video_list = [];
let video_lists = [];
let QZOutputJson;
let html = fetch(input, fetch_params);
let sourceId = /get_playsource/.test(input) ? input.match(/id=(\d*?)&/)[1] : input.split("cid=")[1];
let cid = sourceId;
let detailUrl = "https://v.qq.com/detail/m/" + cid + ".html";
try {
let json = JSON.parse(html);
VOD = {
vod_url: input,
vod_name: json.c.title,
type_name: json.typ.join(","),
vod_actor: json.nam.join(","),
vod_year: json.c.year,
vod_content: json.c.description,
vod_remarks: json.rec,
vod_pic: urljoin2(input, json.c.pic)
}
} catch (e) {}
if (/get_playsource/.test(input)) {
eval(html);
let indexList = QZOutputJson.PlaylistItem.indexList;
indexList.forEach(function(it) {
let dataUrl = "https://s.video.qq.com/get_playsource?id=" + sourceId + "&plat=2&type=4&data_type=3&range=" + it + "&video_type=10&plname=qq&otype=json";
eval(fetch(dataUrl, fetch_params));
let vdata = QZOutputJson.PlaylistItem.videoPlayList;
vdata.forEach(function(item) {
d.push({
title: item.title,
pic_url: item.pic,
url: item.playUrl
})
});
video_lists = video_lists.concat(vdata)
})
} else {
let json = JSON.parse(html);
video_lists = json.c.video_ids;
let url = "https://v.qq.com/x/cover/" + sourceId + ".html";
if (video_lists.length === 1) {
let vid = video_lists[0];
let o_url = "https://union.video.qq.com/fcgi-bin/data?otype=json&tid=1804&appid=20001238&appkey=6c03bbe9658448a4&union_platform=1&idlist=" + vid;
let o_html = fetch(o_url, fetch_params);
eval(o_html);
if (QZOutputJson.results && QZOutputJson.results.length > 0) {
let it1 = QZOutputJson.results[0].fields;
url = "https://v.qq.com/x/cover/" + cid + "/" + vid + ".html";
d.push({
title: it1.title,
url: url
})
} else {
url = "https://v.qq.com/x/cover/" + cid + "/" + vid + ".html";
d.push({
title: "正片播放",
url: url
})
}
} else if (video_lists.length > 1) {
for (let i = 0; i < video_lists.length; i += 30) {
video_list.push(video_lists.slice(i, i + 30))
}
video_list.forEach(function(it, idex) {
let o_url = "https://union.video.qq.com/fcgi-bin/data?otype=json&tid=1804&appid=20001238&appkey=6c03bbe9658448a4&union_platform=1&idlist=" + it.join(",");
let o_html = fetch(o_url, fetch_params);
eval(o_html);
QZOutputJson.results.forEach(function(it1) {
it1 = it1.fields;
let url = "https://v.qq.com/x/cover/" + cid + "/" + it1.vid + ".html";
d.push({
title: it1.title,
pic_url: it1.pic160x90.replace("/160", ""),
desc: it1.video_checkup_time,
url: url,
type: it1.category_map && it1.category_map.length > 1 ? it1.category_map[1] : ""
})
})
})
}
}
let playFrom = [];
let playUrl = [];
let ygKeywords = ["预告", "花絮", "片花", "特辑", "幕后", "采访", "制作", "MV", "主题曲"];
let yg = d.filter(function(it) {
return it.type && ygKeywords.some(keyword => it.type.includes(keyword));
});
let zp = d.filter(function(it) {
return !(it.type && ygKeywords.some(keyword => it.type.includes(keyword)));
});
if (zp.length > 0) {
playFrom.push("正片");
playUrl.push(zp.map(it => it.title + "$" + it.url).join("#"));
}
if (yg.length > 0) {
let 预告 = yg.filter(it => it.type && it.type.includes("预告"));
let 花絮片花 = yg.filter(it => it.type && (it.type.includes("花絮") || it.type.includes("片花")));
let 特辑 = yg.filter(it => it.type && (it.type.includes("特辑") || it.type.includes("幕后")));
if (预告.length > 0) {
playFrom.push("预告");
playUrl.push(预告.map(it => it.title + "$" + it.url).join("#"));
}
if (花絮片花.length > 0) {
playFrom.push("花絮片花");
playUrl.push(花絮片花.map(it => it.title + "$" + it.url).join("#"));
}
if (特辑.length > 0) {
playFrom.push("特辑");
playUrl.push(特辑.map(it => it.title + "$" + it.url).join("#"));
}
}
VOD.vod_play_from = playFrom.join("$$$");
VOD.vod_play_url = playUrl.join("$$$");
}),
搜索: $js.toString(() => {
let d = [],
keyword = input.split("/")[3];
let seenIds = new Set();
function vodSearch(keyword, page = 0) {
return request('https://pbaccess.video.qq.com/trpc.videosearch.mobile_search.MultiTerminalSearch/MbSearch?vplatform=2', {
body: JSON.stringify({
version: "25042201",
clientType: 1,
filterValue: "",
uuid: "B1E50847-D25F-4C4B-BBA0-36F0093487F6",
retry: 0,
query: keyword,
pagenum: page,
isPrefetch: true,
pagesize: 30,
queryFrom: 0,
isneedQc: true,
extraInfo: {
isNewMarkLabel: "1",
multi_terminal_pc: "1",
themeType: "1"
}
}),
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.139 Safari/537.36',
'Content-Type': 'application/json',
'Origin': 'https://v.qq.com',
'Referer': 'https://v.qq.com/'
},
method: 'POST'
});
}
const nonMainContentKeywords = [
'', '#', '特辑', '“', '剪辑', '片花', '独家', '专访', '纯享',
'制作', '幕后', '宣传', '看点', '主题曲', '插曲', '彩蛋',
'精彩', '集锦', '盘点', '回顾', '解说', '评测', '反应', 'reaction'
];
function isMainContent(title) {
if (!title) return false;
if (title.includes('<em>') || title.includes('</em>')) return false;
return !nonMainContentKeywords.some(keyword => title.includes(keyword));
}
try {
let html = vodSearch(keyword, 0);
let json = JSON.parse(html);
function processItemList(itemList) {
if (!itemList) return;
itemList.forEach(it => {
if (it.doc && it.doc.id && it.videoInfo && isMainContent(it.videoInfo.title)) {
const itemId = it.doc.id;
if (!seenIds.has(itemId)) {
seenIds.add(itemId);
d.push({
title: it.videoInfo.title,
img: it.videoInfo.imgUrl || "",
url: itemId,
desc: it.videoInfo.secondLine || ""
});
}
}
});
}
if (json.data && json.data.normalList) {
processItemList(json.data.normalList.itemList);
}
if (json.data && json.data.areaBoxList) {
json.data.areaBoxList.forEach(box => {
processItemList(box.itemList);
});
}
} catch (e) {
log("搜索出错: " + e.message);
}
setResult(d);
})
};
@@ -1,850 +0,0 @@
var rule = {
title: '百忙无果[官]',
host: 'https://pianku.api.%6d%67%74%76.com',
homeUrl: '',
searchUrl: 'https://mobileso.bz.%6d%67%74%76.com/msite/search/v2?q=**&pn=fypage&pc=10',
detailUrl: 'https://pcweb.api.mgtv.com/episode/list?page=1&size=50&video_id=fyid',
searchable: 2,
quickSearch: 0,
filterable: 1,
multi: 1,
url: '/rider/list/pcweb/v3?platform=pcweb&channelId=fyclass&pn=fypage&pc=80&hudong=1&_support=10000000&kind=a1&area=a1',
filter_url: 'year={{fl.year or "all"}}&sort={{fl.sort or "all"}}&chargeInfo={{fl.chargeInfo or "all"}}',
headers: {
'User-Agent': 'PC_UA'
},
timeout: 5000,
class_name: '电影&电视剧&综艺&动漫&纪录片&教育&少儿',
class_url: '3&2&1&50&51&115&10',
filter: {
"1": [{
"key": "chargeInfo",
"name": "付费类型",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "免费",
"v": "b1"
}, {
"n": "vip",
"v": "b2"
}, {
"n": "VIP用券",
"v": "b3"
}, {
"n": "付费点播",
"v": "b4"
}]
}, {
"key": "sort",
"name": "排序",
"value": [{
"n": "最新",
"v": "c1"
}, {
"n": "最热",
"v": "c2"
}, {
"n": "知乎高分",
"v": "c4"
}]
}, {
"key": "year",
"name": "年代",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}, {
"n": "2014",
"v": "2014"
}, {
"n": "2013",
"v": "2013"
}, {
"n": "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"
}]
}],
"2": [{
"key": "chargeInfo",
"name": "付费类型",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "免费",
"v": "b1"
}, {
"n": "vip",
"v": "b2"
}, {
"n": "VIP用券",
"v": "b3"
}, {
"n": "付费点播",
"v": "b4"
}]
}, {
"key": "sort",
"name": "排序",
"value": [{
"n": "最新",
"v": "c1"
}, {
"n": "最热",
"v": "c2"
}, {
"n": "知乎高分",
"v": "c4"
}]
}, {
"key": "year",
"name": "年代",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}, {
"n": "2014",
"v": "2014"
}, {
"n": "2013",
"v": "2013"
}, {
"n": "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"
}]
}],
"3": [{
"key": "chargeInfo",
"name": "付费类型",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "免费",
"v": "b1"
}, {
"n": "vip",
"v": "b2"
}, {
"n": "VIP用券",
"v": "b3"
}, {
"n": "付费点播",
"v": "b4"
}]
}, {
"key": "sort",
"name": "排序",
"value": [{
"n": "最新",
"v": "c1"
}, {
"n": "最热",
"v": "c2"
}, {
"n": "知乎高分",
"v": "c4"
}]
}, {
"key": "year",
"name": "年代",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}, {
"n": "2014",
"v": "2014"
}, {
"n": "2013",
"v": "2013"
}, {
"n": "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"
}]
}],
"50": [{
"key": "chargeInfo",
"name": "付费类型",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "免费",
"v": "b1"
}, {
"n": "vip",
"v": "b2"
}, {
"n": "VIP用券",
"v": "b3"
}, {
"n": "付费点播",
"v": "b4"
}]
}, {
"key": "sort",
"name": "排序",
"value": [{
"n": "最新",
"v": "c1"
}, {
"n": "最热",
"v": "c2"
}, {
"n": "知乎高分",
"v": "c4"
}]
}, {
"key": "year",
"name": "年代",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}, {
"n": "2014",
"v": "2014"
}, {
"n": "2013",
"v": "2013"
}, {
"n": "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"
}]
}],
"51": [{
"key": "chargeInfo",
"name": "付费类型",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "免费",
"v": "b1"
}, {
"n": "vip",
"v": "b2"
}, {
"n": "VIP用券",
"v": "b3"
}, {
"n": "付费点播",
"v": "b4"
}]
}, {
"key": "sort",
"name": "排序",
"value": [{
"n": "最新",
"v": "c1"
}, {
"n": "最热",
"v": "c2"
}, {
"n": "知乎高分",
"v": "c4"
}]
}, {
"key": "year",
"name": "年代",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}, {
"n": "2014",
"v": "2014"
}, {
"n": "2013",
"v": "2013"
}, {
"n": "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"
}]
}],
"115": [{
"key": "chargeInfo",
"name": "付费类型",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "免费",
"v": "b1"
}, {
"n": "vip",
"v": "b2"
}, {
"n": "VIP用券",
"v": "b3"
}, {
"n": "付费点播",
"v": "b4"
}]
}, {
"key": "sort",
"name": "排序",
"value": [{
"n": "最新",
"v": "c1"
}, {
"n": "最热",
"v": "c2"
}, {
"n": "知乎高分",
"v": "c4"
}]
}, {
"key": "year",
"name": "年代",
"value": [{
"n": "全部",
"v": "all"
}, {
"n": "2025",
"v": "2025"
}, {
"n": "2024",
"v": "2024"
}, {
"n": "2023",
"v": "2023"
}, {
"n": "2022",
"v": "2022"
}, {
"n": "2021",
"v": "2021"
}, {
"n": "2020",
"v": "2020"
}, {
"n": "2019",
"v": "2019"
}, {
"n": "2018",
"v": "2018"
}, {
"n": "2017",
"v": "2017"
}, {
"n": "2016",
"v": "2016"
}, {
"n": "2015",
"v": "2015"
}, {
"n": "2014",
"v": "2014"
}, {
"n": "2013",
"v": "2013"
}, {
"n": "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"
}]
}]
},
limit: 20,
play_parse: true,
lazy: $js.toString(() => {
try {
let api = "" + input.split("?")[0];
console.log(api);
let response = fetch(api, {
method: 'get',
headers: {
'User-Agent': 'okhttp/3.14.9',
'Content-Type': 'application/x-www-form-urlencoded'
}
});
let bata = JSON.parse(response);
log(bata)
if (bata.url.includes("http")) {
input = {
header: {
'User-Agent': ""
},
parse: 0,
url: bata.url,
jx: 0,
danmaku: 'http://127.0.0.1:9978/proxy?do=danmu&url='+input.split("?")[0]
};
} else {
input = {
header: {
'User-Agent': ''
},
parse: 0,
url: input.split("?")[0],
jx: 1,
danmaku: 'http://127.0.0.1:9978/proxy?do=danmu&url='+input.split("?")[0]
};
}
} catch {
input = {
header: {
'User-Agent': ''
},
parse: 0,
url: input.split("?")[0],
jx: 1,
danmaku: 'http://127.0.0.1:9978/proxy?do=danmu&url='+input.split("?")[0]
};
}
}),
// 手动调用解析请求json的url,此lazy不方便
// lazy:'js:print(input);fetch_params.headers["user-agent"]=MOBILE_UA;let html=request(input);let rurl=html.match(/window\\.open\\(\'(.*?)\',/)[1];rurl=urlDeal(rurl);input={parse:1,url:rurl};',
// 推荐:'.list_item;img&&alt;img&&src;a&&Text;a&&data-float',
一级: 'json:data.hitDocs;title;img;updateInfo||rightCorner.text;playPartId',
// 一级:'json:data.hitDocs;title;img;updateInfo;playPartId',
二级: $js.toString(() => {
fetch_params.headers.Referer = "https://www.mgtv.com";
fetch_params.headers["User-Agent"] = MOBILE_UA;
pdfh = jsp.pdfh;
pdfa = jsp.pdfa;
pd = jsp.pd;
VOD = {};
let d = [];
let html = request(input);
let json = JSON.parse(html);
let host = "https://www.mgtv.com";
let ourl = json.data.list.length > 0 ? json.data.list[0].url : json.data.series[0].url;
if (!/^http/.test(ourl)) {
ourl = host + ourl
}
fetch_params.headers["User-Agent"] = MOBILE_UA;
html = request(ourl);
if (html.includes("window.location =")) {
print("开始获取ourl");
ourl = pdfh(html, "meta[http-equiv=refresh]&&content").split("url=")[1];
print("获取到ourl:" + ourl);
html = request(ourl)
}
try {
let details = pdfh(html, ".m-details&&Html").replace(/h1>/, "h6>").replace(/div/g, "br");
print(details);
let actor = "",
director = "",
time = "";
if (/播出时间/.test(details)) {
actor = pdfh(html, "p:eq(5)&&Text").substr(0, 25);
director = pdfh(html, "p:eq(4)&&Text");
time = pdfh(html, "p:eq(3)&&Text")
} else {
actor = pdfh(html, "p:eq(4)&&Text").substr(0, 25);
director = pdfh(html, "p:eq(3)&&Text");
time = "已完结"
}
let _img = pd(html, ".video-img&&img&&src");
let JJ = pdfh(html, ".desc&&Text").split("简介:")[1];
let _desc = time;
VOD.vod_name = pdfh(html, ".vt-txt&&Text");
VOD.type_name = pdfh(html, "p:eq(0)&&Text").substr(0, 6);
VOD.vod_area = pdfh(html, "p:eq(1)&&Text");
VOD.vod_actor = actor;
VOD.vod_director = director;
VOD.vod_remarks = _desc;
VOD.vod_pic = _img;
VOD.vod_content = JJ;
if (!VOD.vod_name) {
VOD.vod_name = VOD.type_name;
}
} catch (e) {
log("获取影片信息发生错误:" + e.message)
}
function getRjpg(imgUrl, xs) {
xs = xs || 3;
let picSize = /jpg_/.test(imgUrl) ? imgUrl.split("jpg_")[1].split(".")[0] : false;
let rjpg = false;
if (picSize) {
let a = parseInt(picSize.split("x")[0]) * xs;
let b = parseInt(picSize.split("x")[1]) * xs;
rjpg = a + "x" + b + ".jpg"
}
let img = /jpg_/.test(imgUrl) && rjpg ? imgUrl.replace(imgUrl.split("jpg_")[1], rjpg) : imgUrl;
return img
}
if (json.data.total === 1 && json.data.list.length === 1) {
let data = json.data.list[0];
let url = "https://www.mgtv.com" + data.url;
d.push({
title: data.t4,
desc: data.t2,
pic_url: getRjpg(data.img),
url: url
})
} else if (json.data.list.length > 1) {
for (let i = 1; i <= json.data.total_page; i++) {
if (i > 1) {
json = JSON.parse(fetch(input.replace("page=1", "page=" + i), {}))
}
json.data.list.forEach(function(data) {
let url = "https://www.mgtv.com" + data.url;
if (data.isIntact == "1") {
d.push({
title: data.t4,
desc: data.t2,
pic_url: getRjpg(data.img),
url: url
})
}
})
}
} else {
print(input + "暂无片源")
}
VOD.vod_play_from = "mgtv";
VOD.vod_play_url = d.map(function(it) {
return it.title + "$" + it.url
}).join("#");
setResult(d);
}),
搜索: $js.toString(() => {
fetch_params.headers.Referer = "https://www.mgtv.com";
fetch_params.headers["User-Agent"] = MOBILE_UA;
let d = [];
let html = request(input);
let json = JSON.parse(html);
json.data.contents.forEach(function(data) {
if (data.type && data.type == 'media') {
let item = data.data[0];
let desc = item.desc.join(',');
let fyclass = '';
if (item.source === "imgo") {
let img = item.img ? item.img : '';
try {
fyclass = item.rpt.match(/idx=(.*?)&/)[1] + '$';
} catch (e) {
log(e.message);
fyclass = '';
}
log(fyclass);
d.push({
title: item.title.replace(/<B>|<\/B>/g, ''),
img: img,
content: '',
desc: desc,
url: fyclass + item.url.match(/.*\/(.*?)\.html/)[1]
})
}
}
});
setResult(d);
}),
}
@@ -1,533 +0,0 @@
import cheerio from 'assets://js/lib/cheerio.min.js';
const appConfig = {
siteName: "虫虫影视",
siteUrl: "https://www.chongliski.net"
}
const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
const Headers = {
"User-Agent": UA,
"Referer": appConfig.siteUrl + "/",
}
const parseApi4k = "https://fgsrg.hzqingshan.com/player/?url=";
const parseApi2k = "https://zzrs.mfdyvip.com/player/?url=";
async function init(ext) {
console.log("初始化爬虫:", appConfig.siteName);
}
function getYearFilter() {
let years = [{ "n": "全部", "v": "" }];
const currentYear = new Date().getFullYear().toString();
for (let y = currentYear; y >= currentYear - 22; y--) {
years.push({ "n": String(y), "v": String(y) });
}
return { "key": "year", "name": "年份", "value": years };
}
function getLetterFilter() {
return {
"key": "letter", "name": "字母", "value": [
{ "n": "全部", "v": "" },
{ "n": "A", "v": "A" }, { "n": "B", "v": "B" }, { "n": "C", "v": "C" }, { "n": "D", "v": "D" },
{ "n": "E", "v": "E" }, { "n": "F", "v": "F" }, { "n": "G", "v": "G" }, { "n": "H", "v": "H" },
{ "n": "I", "v": "I" }, { "n": "J", "v": "J" }, { "n": "K", "v": "K" }, { "n": "L", "v": "L" },
{ "n": "M", "v": "M" }, { "n": "N", "v": "N" }, { "n": "O", "v": "O" }, { "n": "P", "v": "P" },
{ "n": "Q", "v": "Q" }, { "n": "R", "v": "R" }, { "n": "S", "v": "S" }, { "n": "T", "v": "T" },
{ "n": "U", "v": "U" }, { "n": "V", "v": "V" }, { "n": "W", "v": "W" }, { "n": "X", "v": "X" },
{ "n": "Y", "v": "Y" }, { "n": "Z", "v": "Z" }, { "n": "0-9", "v": "0-9" }
]
}
}
function getOrderFilter() {
return {
"key": "orderBy", "name": "排序", "value": [
{ "n": "时间", "v": "time" },
{ "n": "人气", "v": "hits" },
{ "n": "评分", "v": "score" }
]
}
}
const CommonFilters = [
{
"key": "area", "name": "地区", "value": [
{ "n": "全部", "v": "" }, { "n": "大陆", "v": "大陆" }, { "n": "香港", "v": "香港" },
{ "n": "台湾", "v": "台湾" }, { "n": "美国", "v": "美国" }, { "n": "韩国", "v": "韩国" },
{ "n": "日本", "v": "日本" }, { "n": "泰国", "v": "泰国" }, { "n": "新加坡", "v": "新加坡" },
{ "n": "马来西亚", "v": "马来西亚" }, { "n": "印度", "v": "印度" }, { "n": "英国", "v": "英国" },
{ "n": "法国", "v": "法国" }, { "n": "加拿大", "v": "加拿大" }, { "n": "西班牙", "v": "西班牙" },
{ "n": "俄罗斯", "v": "俄罗斯" }, { "n": "其它", "v": "其它" }
]
},
{
"key": "lang", "name": "语言", "value": [
{ "n": "全部", "v": "" }, { "n": "国语", "v": "国语" }, { "n": "英语", "v": "英语" },
{ "n": "粤语", "v": "粤语" }, { "n": "闽南语", "v": "闽南语" }, { "n": "韩语", "v": "韩语" },
{ "n": "日语", "v": "日语" }, { "n": "其它", "v": "其它" }
]
},
getYearFilter(),
getLetterFilter(),
getOrderFilter()
];
const myFilters = {
"2": [
{
key: "type", "name": "类型", value: [
{ "n": "全部", "v": "2" },
{ "n": "国产剧", "v": "13" },
{ "n": "日韩剧", "v": "15" },
{ "n": "海外剧", "v": "16" },
]
},
{
"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": "其他" }
]
},
...CommonFilters
],
"1": [
{
"key": "type", "name": "类型", value: [
{ "n": "全部", "v": "1" },
{ "n": "动作片", "v": "6" },
{ "n": "喜剧片", "v": "7" },
{ "n": "恐怖片", "v": "8" },
{ "n": "科幻片", "v": "9" },
{ "n": "爱情片", "v": "10" },
{ "n": "剧情片", "v": "11" },
{ "n": "战争片", "v": "12" },
{ "n": "纪录片", "v": "20" }
]
},
{
"key": "class", "name": "剧情", "value": [
{ "n": "全部", "v": "" },
{ "n": "喜剧", "v": "喜剧" },
{ "n": "爱情", "v": "爱情" },
{ "n": "恐怖", "v": "恐怖" },
{ "n": "动作", "v": "动作" },
{ "n": "科幻", "v": "科幻" },
{ "n": "剧情", "v": "剧情" },
{ "n": "战争", "v": "战争" },
{ "n": "警匪", "v": "警匪" },
{ "n": "犯罪", "v": "犯罪" },
{ "n": "动画", "v": "动画" },
{ "n": "奇幻", "v": "奇幻" },
{ "n": "武侠", "v": "武侠" },
{ "n": "冒险", "v": "冒险" },
{ "n": "枪战", "v": "枪战" },
{ "n": "悬疑", "v": "悬疑" },
{ "n": "惊悚", "v": "惊悚" },
{ "n": "经典", "v": "经典" },
{ "n": "青春", "v": "青春" },
{ "n": "文艺", "v": "文艺" },
{ "n": "微电影", "v": "微电影" },
{ "n": "古装", "v": "古装" },
{ "n": "历史", "v": "历史" },
{ "n": "运动", "v": "运动" },
{ "n": "农村", "v": "农村" },
{ "n": "儿童", "v": "儿童" },
{ "n": "网络电影", "v": "网络电影" }
]
},
...CommonFilters
],
"4": [
{
"key": "type", "name": "类型", value: [
{ "n": "全部", "v": "4" },
{ "n": "国产动漫", "v": "25" },
{ "n": "日韩动漫", "v": "26" },
{ "n": "欧美动漫", "v": "27" },
{ "n": "港台动漫", "v": "28" }
]
},
{
"key": "class", "name": "剧情", "value": [
{ "n": "全部", "v": "" },
{ "n": "情感", "v": "情感" },
{ "n": "科幻", "v": "科幻" },
{ "n": "热血", "v": "热血" },
{ "n": "推理", "v": "推理" },
{ "n": "搞笑", "v": "搞笑" },
{ "n": "冒险", "v": "冒险" },
{ "n": "萝莉", "v": "萝莉" },
{ "n": "校园", "v": "校园" },
{ "n": "动作", "v": "动作" },
{ "n": "机战", "v": "机战" },
{ "n": "运动", "v": "运动" },
{ "n": "战争", "v": "战争" },
{ "n": "少年", "v": "少年" },
{ "n": "少女", "v": "少女" },
{ "n": "社会", "v": "社会" },
{ "n": "原创", "v": "原创" },
{ "n": "亲子", "v": "亲子" },
{ "n": "益智", "v": "益智" },
{ "n": "励志", "v": "励志" },
{ "n": "其他", "v": "其他" }
]
},
...CommonFilters
],
"3": [
{
"key": "type", "name": "类型", value: [
{ "n": "全部", "v": "3" },
{ "n": "大陆综艺", "v": "21" },
{ "n": "日韩综艺", "v": "22" },
{ "n": "欧美综艺", "v": "23" },
{ "n": "港台综艺", "v": "24" }
]
},
{
"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": "求职" }
]
},
...CommonFilters
],
"5": [
getYearFilter(),
getLetterFilter(),
getOrderFilter()
],
};
async function home(filter) {
return JSON.stringify({
class: [
{ type_id: "2", type_name: "电视剧" },
{ type_id: "1", type_name: "电影" },
{ type_id: "4", type_name: "动漫" },
{ type_id: "3", type_name: "综艺" },
{ type_id: "5", type_name: "短剧" }
],
filters: myFilters
});
}
async function category(tid, pg, filter, extend) {
pg = pg || 1;
let type = extend.type || tid;
const isLabel = tid.startsWith("/label");
let url = "";
if (isLabel) {
url = appConfig.siteUrl + tid + `/page/${pg}.html`;
} else {
let classVal = extend.class || '';
let areaVal = extend.area || '';
let langVal = extend.lang || '';
let letterVal = extend.letter || '';
let orderVal = extend.orderBy || '';
let yearVal = extend.year || '';
url = `${appConfig.siteUrl}/cupfox-list/${type}-${areaVal}-${''}-${classVal}-${langVal}-${letterVal}-${orderVal}-${''}-${pg}-${''}-${''}-${yearVal}.html`;
}
try {
const html = (await req(url)).content;
const $ = cheerio.load(html);
let list = [];
$(".module-poster-item.module-item").each(function (index, el) {
let vod_id = $(el).attr("href");
let vod_name = $(el).attr("title");
if (vod_name) vod_name = vod_name.trim();
let vod_pic = $(el).find(".module-item-pic img").attr("data-src");
let tag = $(el).find(".module-item-version-right").text().trim();
let note = $(el).find(".module-item-note").text().trim();
let vod_remarks = tag + (tag && note ? ' ' : '') + note;
list.push({
vod_id,
vod_name,
vod_pic,
vod_remarks
});
});
let pagecount = 1;
const lastPageLink = $("#page a[title='尾页']").attr("href");
if (lastPageLink) {
const parts = lastPageLink.replace('.html', '').split('-');
for (let i = parts.length - 1; i >= 0; i--) {
const num = parseInt(parts[i]);
if (num > 0) {
pagecount = num;
break;
}
}
}
return JSON.stringify({
list,
pagecount
});
} catch (e) {
console.error("分类列表获取失败:", e.message);
return JSON.stringify({ list: [], pagecount: 0 });
}
}
async function search(wd, quick, page) {
if (page >= 2) {
return JSON.stringify({ list: [], pagecount: 1 });
}
try {
const url = `${appConfig.siteUrl}/cupfox-search/-------------.html?wd=${wd}&submit=`;
const html = (await req(url)).content;
const $ = cheerio.load(html);
let list = [];
$('.module-card-item.module-item').each((i, el) => {
const vod_id = $(el).find(".module-card-item-poster").attr('href') || '';
const vod_name = $(el).find(".module-card-item-title a strong").text().trim();
const vod_pic = $(el).find('.module-item-pic img').attr('data-src') || '';
const vod_remarks = $(el).find('.module-item-note').text().trim();
list.push({
vod_id,
vod_name,
vod_pic,
vod_remarks
});
});
return JSON.stringify({
list: list,
pagecount: 1
});
} catch (e) {
console.error("搜索失败:", e.message);
return JSON.stringify({ list: [] });
}
}
async function detail(id) {
try {
const videoId = id;
const url = appConfig.siteUrl + videoId;
const response = await req(url);
const html = response ? response.content : '';
const $ = cheerio.load(html);
const vod_name = $('.module-info-heading h1').text().trim();
const imgSrc = $('.module-item-pic img').attr("data-src") || '';
const vod_pic = imgSrc ? (imgSrc.startsWith('http') ? imgSrc : appConfig.siteUrl + imgSrc) : '';
let vod_actor = '';
let vod_remarks = '';
$('.module-info-item').each((i, el) => {
const title = $(el).find('.module-info-item-title').text().trim();
const content = $(el).find('.module-info-item-content').text().trim();
if (title.includes('主演')) {
vod_actor = content;
} else if (title.includes('更新') || title.includes('状态') || title.includes('连载')) {
vod_remarks = content;
}
});
const vod_content = $('.module-info-introduction-content p').text().trim();
let rawLines = [];
let rawPlaylists = [];
$('.mx-anthology-tab-label').each((i, el) => {
const lineName = $(el).text().trim();
rawLines.push(lineName);
});
$('.mx-anthology-grid').each((lineIndex, poolEl) => {
const episodes = [];
$(poolEl).find('.mx-anthology-link').each((episodeIndex, epEl) => {
const name = $(epEl).text().trim();
const href = $(epEl).attr('href') || '';
if (name && href) {
episodes.push(`${name}$${href}`);
}
});
rawPlaylists.push(episodes);
});
let finalLines = [];
let finalPlaylists = [];
for (let i = 0; i < rawLines.length; i++) {
if (rawPlaylists[i] && rawPlaylists[i].length > 0) {
finalLines.push(rawLines[i]);
finalPlaylists.push(rawPlaylists[i]);
}
}
const { vod_play_from, vod_play_url } = buildVodPlayData(finalLines, finalPlaylists, true);
const vod = {
vod_id: videoId,
vod_name,
vod_pic,
vod_actor,
vod_remarks,
vod_content,
vod_play_from,
vod_play_url
};
return JSON.stringify({ list: [vod] });
} catch (error) {
console.error(`解析详情页异常 [ID: ${id}]:`, error);
return JSON.stringify({ list: [] });
}
}
function buildVodPlayData(lines, playlists, shouldReverse = true) {
const processedPlaylists = playlists.map(eps => {
if (shouldReverse) {
eps.reverse();
}
return eps.join('#');
});
return {
vod_play_from: lines.filter(Boolean).join('$$$'),
vod_play_url: processedPlaylists.join('$$$')
};
}
function isDirectUrl(url) {
return url.startsWith('http') || url.endsWith(".m3u8") || url.endsWith(".mp4");
}
function getPlayFrom(html) {
const match = html.match(/var\s+player_aaaa[\s\S]*?"from"\s*:\s*"([^"]+)"/);
return match ? match[1].replace(/\\/g, '') : '';
}
function getPlayUrl(html) {
const match = html.match(/var\s+player_aaaa[\s\S]*?"url"\s*:\s*"([^"]+)"/);
let url = match ? match[1] : '';
url = url.replace(/\\/g, '');
return url;
}
async function parsePlayUrl(parseApi, rawUrl) {
try {
const html = (await req(`${parseApi}${rawUrl}`, {
method: 'GET',
headers: Headers
})).content;
const $ = cheerio.load(html);
const token = $('#player-data').attr('data-te');
if (!token) {
const urlMatch = html.match(/"url"\s*:\s*"([^"]+)"/);
if (urlMatch) {
return urlMatch[1].replace(/\\/g, '');
}
return '';
}
let playData = (await req(`${parseApi.replace('?url=', '')}/mplayer.php`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
data: {
url: rawUrl,
token: token,
}
})).content;
playData = JSON.parse(playData);
return playData.url || '';
} catch (e) {
console.error("解析播放地址失败:", e.message);
return "";
}
}
function needParse(from) {
const parseLines = ['JD4K', 'YYNB', 'JD2K', 'qiyi', 'bilibili', 'qq', 'youku'];
return parseLines.indexOf(from) !== -1;
}
function getParseApi(from) {
if (from === 'JD4K' || from === 'JD2K') {
return parseApi4k;
}
return parseApi2k;
}
async function play(flag, id, flags) {
try {
const html = (await req(`${appConfig.siteUrl}${id}`)).content;
const url = getPlayUrl(html);
const from = getPlayFrom(html);
if (isDirectUrl(url)) {
return JSON.stringify({
parse: 0,
Header: {
"User-Agent": UA
},
url,
});
}
if (needParse(from) && url) {
const parseApi = getParseApi(from);
const realUrl = await parsePlayUrl(parseApi, url);
if (realUrl) {
return JSON.stringify({
parse: 0,
Header: {
"User-Agent": UA,
"Referer": parseApi
},
url: realUrl
});
}
}
return JSON.stringify({
parse: 0,
Header: {
"User-Agent": UA
},
url: url
});
} catch (e) {
console.error("播放失败:", e);
return JSON.stringify({ parse: 0, url: "" });
}
}
export default {
init,
home,
category,
detail,
search,
play
};
-279
Melihat File
@@ -1,279 +0,0 @@
{
"sites": [
{
"key": "枫叶",
"name": "枫叶影院",
"type": 3,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/枫叶.js",
"searchable": 1,
"quickSearch": 1,
"filterable": 1,
"changeable": 1,
"playable": 1
},
{
"key": "追光",
"name": "追光影视",
"type": 4,
"api": "http://8.134.205.252:39466/shenma/zg.php",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{
"key": "CO4K",
"name": "C O 影视",
"type": 4,
"api": "http://8.134.205.252:39466/pz/co4k.php/api.php/provide/vod/?ac=list",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{
"key": "歪比巴卜",
"name": "歪比巴卜",
"type": 3,
"changeable": 0,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/歪比巴卜.js",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{"key":"咕噜","name":"咕噜咕噜","type":4,"api":"http://211.101.247.26:99/proxy.php?code=9999&target=f5eb11c746869fd90c06","searchable":1,"quickSearch":1,"filterable":1,"changeable":0,"ext":""},
{
"key": "布布",
"name": "布布影视",
"type": 3,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/布布影视.js"
},
{
"key": "腾讯",
"name": "腾讯视频",
"type": 3,
"jar": "http://125.208.22.184:6019/uploads/tvbox/jar/xywp.jar;md5;8ad5c036e8ab4df4f3873780c586e7c1",
"api": "csp_Tencent",
"ext": "/ZE6FY7TFUnOGwjVo+fPIyHKqEMai+KWYLN9iLjSSSh4S0FKDSvRwwG8mr+TGYcPbokCBkpT7Mke6Tf4wJ41mg==",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{
"key": "芒果",
"name": "芒果视频",
"type": 3,
"jar": "http://125.208.22.184:6019/uploads/tvbox/jar/xywp.jar;md5;8ad5c036e8ab4df4f3873780c586e7c1",
"api": "csp_Mango",
"ext": "/ZE6FY7TFUnOGwjVo+fPI5QppjJcram+LYJBroPBjA3nbrRjT1GVNGOxBDpHR4wkiZ0fAyB4s01lJYdFHOZtGA==",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{"key":"bili","name":"哔哩哔哩","type":4,"api":"http://211.101.247.26:99/proxy.php?code=9999&target=f064a77443204ab4568d","searchable":1,"quickSearch":1,"changeable":0},
{
"key": "爱奇艺",
"name": "奇艺视频",
"type": 3,
"searchable": 1,
"quickSearch": 1,
"changeable": 1,
"api": "https://gitee.com/monosodium-glutamate/wjwj/raw/master/lib/drpy2.min.js",
"ext": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/爱奇艺.js"
},
{
"key": "优酷",
"name": "优酷视频",
"type": 3,
"searchable": 1,
"quickSearch": 1,
"changeable": 1,
"api": "https://gitee.com/monosodium-glutamate/wjwj/raw/master/lib/drpy2.min.js",
"ext": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/优酷视频.js"
},
{
"key": "山楂影视",
"name": "山楂影视",
"type": 3,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/山楂影视.py",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{
"key": "虫虫",
"name": "虫虫影视",
"type": 3,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/虫虫影视.js",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{
"key": "星空",
"name": "星空影视",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/潇洒.jar",
"searchable": 1,
"changeable": 1,
"api": "csp_AppGet",
"ext": {
"url": "http://23.148.228.37:6090",
"dataKey": "106jkcdnkldzckjk",
"dataIv": "106jkcdnkldzckjk"
}
},
{
"key": "四叶草",
"name": "叶草影视",
"type": 3,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-Qiji.py",
"searchable": 1,
"changeable": 1,
"ext": {
"site": "https://yzysap.oss-cn-hangzhou.aliyuncs.com/kkk.txt",
"dataKey": "8eeObuwrmS3lRDEs",
"dataIv": "8eeObuwrmS3lRDEs",
"ua": "okhttp/3.10.0",
"api": 2
}
},
{
"key": "秒看",
"name": "秒看视频",
"type": 3,
"api": "https://10402.kstore.vip/ycsk/qf.py",
"ext": {
"site": "https://mk1080.top",
"dataKey": "c60d88b2eep53za8",
"dataIv": "c60d88b2eep53za8",
"token": "b008fad37a80ead49addf97984b154387fddd3fe42a81a79671281b6082bcd80",
"ua": "okhttp/3.14.9"
}
},
{
"key": "魔方",
"name": "魔方视频",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/潇洒.jar",
"searchable": 1,
"changeable": 1,
"api": "csp_AppGet",
"ext": {
"url": "https://www.alibaba31casaq.top",
"dataKey": "1234567887654321",
"dataIv": "1234567887654321"
}
},
{
"key": "快映",
"name": "快映视频",
"type": 3,
"changeable": 0,
"api": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/AppFox.js",
"ext": {
"host": "https://www.kanzurm65ak.top/",
"ver": 3
}
},
{
"key": "hohai",
"name": " E M B Y ",
"type": 4,
"api": "http://8.134.205.252:39466/mmcb/zc1.php/api.php/provide/vod/?ac=list",
"searchable": 1,
"quickSearch": 1,
"filterable": 1
},
{"key":"wanou_sites","name":"网盘聚合","type":4,"api":"http://211.101.247.26:99/proxy.php?code=9999&target=5657e709a4c79e8b5e4b","searchable":1,"quickSearch":1,"filterable":1},
{
"key": "mihdr",
"name": "小米网盘",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-wp.jar",
"api": "csp_ZC4K",
"ext": "YUhSMGNEb3ZMekUyTUM0eU1ESXVNak00TGpNNU9qTTNNekU1TDJGd2FTNXdhSEEvYzJsMFpUMXRhV2hrY2lNakkyMXBhR1J5"
},
{
"key": "ouge",
"name": "讴歌网盘",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-wp.jar",
"api": "csp_ZC4K",
"ext": "YUhSMGNEb3ZMekUyTUM0eU1ESXVNak00TGpNNU9qTTNNekU1TDJGd2FTNXdhSEEvYzJsMFpUMXZkV2RsSXlNamIzVm5aUT09"
},
{
"key": "mogg",
"name": "木偶网盘",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-wp.jar",
"api": "csp_ZC4K",
"ext": "YUhSMGNEb3ZMekUyTUM0eU1ESXVNak00TGpNNU9qTTNNekU1TDJGd2FTNXdhSEEvYzJsMFpUMXRiMmRuSXlNamJXOW5adz09"
},
{
"key": "wogg",
"name": "玩偶网盘",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-wp.jar",
"api": "csp_ZC4K",
"ext": "YUhSMGNEb3ZMekUyTUM0eU1ESXVNak00TGpNNU9qTTNNekU1TDJGd2FTNXdhSEEvYzJsMFpUMTNiMmRuSXlNamQyOW5adz09"
},
{
"key": "huban",
"name": "虎斑网盘",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-wp.jar",
"api": "csp_ZC4K",
"ext": "YUhSMGNEb3ZMekUyTUM0eU1ESXVNak00TGpNNU9qTTNNekU1TDJGd2FTNXdhSEEvYzJsMFpUMW9kV0poYmlNakkyaDFZbUZ1"
},
{
"key": "erxiao",
"name": "小二网盘",
"type": 3,
"jar": "https://gitee.com/Ye-11X115490/PsyDuck/raw/master/lib/PsyDuck-wp.jar",
"api": "csp_ZC4K",
"ext": "YUhSMGNEb3ZMekUyTUM0eU1ESXVNak00TGpNNU9qTTNNekU1TDJGd2FTNXdhSEEvYzJsMFpUMWxjbmhwWVc4akl5TmxjbmhwWVc4PQ=="
}
],
"parses": [
{
"name": "4K",
"type": 1,
"url": "http://8.134.205.252:39466/ceshi/cs.php?key=udk&url=",
"ext": {
"flag": [
"1080P+",
"超清4K",
"qiyi",
"爱奇艺",
"奇艺",
"youku",
"优酷",
"mgtv",
"芒果",
"bilibili"
]
}
},
{
"name": "网盘",
"type": 1,
"url": "http://8.134.205.252:39466/ceshi/ss.php?key=ysj&url=",
"ext": {
"flag": [
"baidu",
"baidu2",
"abaidu",
"a123",
"a189",
"a115",
"ali",
"臻彩",
"臻彩2",
"原彩",
"真彩",
"清秋",
"明月"
]
}
}
]
}