Sync all projects
This commit is contained in:
@@ -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}}
|
||||
@@ -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
|
||||
@@ -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
|
||||
TEMPAT SAMPAH
Binary file not shown.
File diff suppressed because one or more lines are too long
-3201
@@ -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
|
||||
};
|
||||
TEMPAT SAMPAH
Binary file not shown.
|
Before Width: | Height: | Ukuran: 1.2 MiB |
@@ -1 +0,0 @@
|
||||
__pus=12fd6f406097e6ad7b59ce2b94da18e1AATYn5CsxNOBdy5gdD9AOGUj+hyODyKfX5CYOF7FT/2msT18L+WvAzPTEdh29MVktlv2eMnFu29JO2hYkHt/L1/R;
|
||||
@@ -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¶ms=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
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
TEMPAT SAMPAH
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',
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -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",
|
||||
"原彩",
|
||||
"真彩",
|
||||
"清秋",
|
||||
"明月"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user