Sync all projects

This commit is contained in:
github-actions[bot]
2026-07-17 18:37:52 +00:00
parent 905ba2547a
commit 7e3499177e
12 changed files with 5148 additions and 4294 deletions
+357
View File
@@ -0,0 +1,357 @@
# coding=utf-8
import sys
import os
import json
import time
import base64
import random
import hashlib
import hmac
import requests
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Hash import SHA1, SHA256
sys.path.append('..')
from base.spider import Spider
class Spider(Spider):
def __init__(self):
self.name = "花子动漫"
self.base = 'https://www.huazidm.com'
self.ua = 'okhttp/5.3.2'
self.session = requests.Session()
self.session.headers.update({
'User-Agent': self.ua
})
self.aes_key = None
self.client_id = None
self.session_id = None
self.types = {}
self._home_cache = None
self._home_cache_time = 0
# 不在__init__里握手,延迟到第一次请求时
def getName(self):
return self.name
def init(self, extend=''):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
# ==================== 加密通信 ====================
def _b64u_encode(self, data):
return base64.urlsafe_b64encode(data).decode().rstrip('=')
def _b64u_decode(self, s):
padding = 4 - len(s) % 4
if padding != 4:
s += '=' * padding
return base64.urlsafe_b64decode(s)
def _aes_gcm_encrypt(self, key, plaintext):
iv = os.urandom(12)
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode())
return {
'iv': self._b64u_encode(iv),
'data': self._b64u_encode(ciphertext),
'tag': self._b64u_encode(tag)
}
def _aes_gcm_decrypt(self, key, data):
iv = self._b64u_decode(data['iv'])
ciphertext = self._b64u_decode(data['data'])
tag = self._b64u_decode(data['tag'])
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
return cipher.decrypt_and_verify(ciphertext, tag).decode()
def _init_api(self):
try:
r = self.session.get(self.base + '/api/public/config', timeout=15)
config = r.json()['data']
pub_key = config['public_key']
self.aes_key = os.urandom(32)
self.client_id = os.urandom(16).hex()
rsa_key = RSA.import_key(pub_key)
cipher_rsa = PKCS1_OAEP.new(rsa_key, hashAlgo=SHA1)
encrypted_key = base64.b64encode(cipher_rsa.encrypt(self.aes_key)).decode()
handshake_data = {
'client_id': self.client_id,
'encrypted_key': encrypted_key,
'fingerprint': self.session.headers.get('User-Agent', '')
}
r2 = self.session.post(
self.base + '/api/public/handshake',
headers={'Content-Type': 'application/json'},
json=handshake_data,
timeout=15
)
result = r2.json()
if result.get('code') == 1:
self.session_id = result['data']['session_id']
else:
raise Exception('handshake failed: ' + result.get('msg', ''))
except Exception as e:
print(f'_init_api error: {e}')
def _req(self, path, data=None, retry=True):
if data is None:
data = {}
if not self.aes_key or not self.session_id:
self._init_api()
if not self.aes_key or not self.session_id:
return None
try:
payload = self._aes_gcm_encrypt(self.aes_key, json.dumps(data, ensure_ascii=False))
ts = str(int(time.time()))
nonce = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=20))
sign = hmac.new(
self.aes_key,
f'{payload["data"]}|{ts}|{nonce}'.encode(),
SHA256
).hexdigest()
body = {
'client_id': self.client_id,
'session_id': self.session_id,
'ts': ts,
'nonce': nonce,
'sign': sign,
'payload': payload
}
headers = {
'Content-Type': 'application/json',
'X-Client-Id': self.client_id,
'X-Session-Id': self.session_id
}
r = self.session.post(self.base + path, headers=headers, json=body, timeout=15)
rd = r.json()
if rd.get('code') != 1:
# session失效时重新握手
if retry and ('失效' in str(rd.get('msg', '')) or '过期' in str(rd.get('msg', '')) or rd.get('code') == 401):
self._init_api()
return self._req(path, data, retry=False)
return None
pd = rd['data']['payload']
decrypted = self._aes_gcm_decrypt(self.aes_key, pd)
return json.loads(decrypted)
except Exception as e:
print(f'_req {path} error: {e}')
return None
# ==================== TVBox 接口 ====================
def _get_home(self):
# 缓存home数据5分钟,避免重复请求
now = time.time()
if self._home_cache and now - self._home_cache_time < 300:
return self._home_cache
data = self._req('/api/site/home')
if data:
self._home_cache = data
self._home_cache_time = now
return data
def homeContent(self, filter):
result = {'class': [], 'filters': {}, 'list': [], 'parse': 0, 'jx': 0}
try:
data = self._get_home()
if not data:
return result
types = data.get('types', [])
for t in types:
tid = str(t['type_id'])
name = t['type_name']
result['class'].append({'type_id': tid, 'type_name': name})
self.types[tid] = t
# 精简筛选 - 只保留排序,减少初始化时间
result['filters'][tid] = [{
'key': 'sort', 'name': '排序', 'value': [
{'n': '最新', 'v': 'latest'},
{'n': '最热', 'v': 'hits'},
{'n': '评分', 'v': 'score'},
]
}]
# 首页推荐
for item in data.get('recommend', []):
result['list'].append({
'vod_id': str(item['id']),
'vod_name': item.get('name', ''),
'vod_pic': item.get('poster', ''),
'vod_remarks': item.get('remark', '')
})
except Exception as e:
print(f'homeContent error: {e}')
return result
def homeVideoContent(self):
videos = []
try:
data = self._req('/api/site/home')
if data:
for item in data.get('latest', []):
videos.append({
'vod_id': str(item['id']),
'vod_name': item.get('name', ''),
'vod_pic': item.get('poster', ''),
'vod_remarks': item.get('remark', '')
})
except Exception as e:
print(f'homeVideoContent error: {e}')
return {'list': videos, 'parse': 0, 'jx': 0}
def categoryContent(self, tid, pg, filter, extend):
result = {'list': [], 'parse': 0, 'jx': 0}
page = int(pg) if pg else 1
try:
params = {'keyword': '', 'category_id': int(tid), 'page': page, 'limit': 20}
if extend:
if extend.get('class'):
params['genre'] = extend['class']
if extend.get('year'):
params['year'] = extend['year']
if extend.get('area'):
params['area'] = extend['area']
if extend.get('sort'):
sort_map = {'latest': 'updated_at', 'hits': 'hits', 'score': 'score'}
params['sort'] = sort_map.get(extend['sort'], extend['sort'])
data = self._req('/api/site/search', params)
if data:
for item in data.get('list', []):
result['list'].append({
'vod_id': str(item['id']),
'vod_name': item.get('name', ''),
'vod_pic': item.get('poster', ''),
'vod_remarks': item.get('remark', '')
})
total = int(data.get('total', 0))
result['page'] = page
result['pagecount'] = (total + 19) // 20 if total > 0 else page
result['limit'] = 20
result['total'] = total
except Exception as e:
print(f'categoryContent error: {e}')
return result
def detailContent(self, ids):
result = {'list': [], 'parse': 0, 'jx': 0}
vid = str(ids[0]) if ids else ''
if not vid:
return result
try:
data = self._req('/api/site/detail', {'id': int(vid)})
if not data or 'detail' not in data:
return result
detail = data['detail']
play_sources = detail.get('play_sources', [])
play_from = []
play_urls = []
for src in play_sources:
src_code = src.get('code', '')
src_name = src.get('name', '')
if not src_code or not src_name:
continue
episodes = src.get('episodes', [])
ep_list = []
for idx, ep in enumerate(episodes):
ep_name = ep.get('name', f'{idx+1}')
# 用base64编码避免特殊字符问题
play_data = f'{vid}|{src_code}|{idx}'
play_id = base64.b64encode(play_data.encode()).decode()
ep_list.append(f'{ep_name}${play_id}')
if ep_list:
play_from.append(src_name)
play_urls.append('#'.join(ep_list))
vod = {
'vod_id': vid,
'vod_name': detail.get('name', ''),
'vod_pic': detail.get('poster', ''),
'type_name': detail.get('genre', ''),
'vod_year': str(detail.get('year', '')),
'vod_area': detail.get('area', ''),
'vod_remarks': detail.get('remark', ''),
'vod_actor': detail.get('actor', ''),
'vod_director': detail.get('director', ''),
'vod_content': detail.get('content_text', ''),
'vod_play_from': '$$$'.join(play_from),
'vod_play_url': '$$$'.join(play_urls)
}
result['list'].append(vod)
except Exception as e:
print(f'detailContent error: {e}')
return result
def searchContent(self, key, quick, pg='1'):
result = {'list': [], 'parse': 0, 'jx': 0}
page = int(pg) if pg else 1
try:
data = self._req('/api/site/search', {
'keyword': key,
'page': page,
'limit': 20
})
if data:
for item in data.get('list', []):
result['list'].append({
'vod_id': str(item['id']),
'vod_name': item.get('name', ''),
'vod_pic': item.get('poster', ''),
'vod_remarks': item.get('remark', '')
})
total = int(data.get('total', 0))
result['page'] = page
result['pagecount'] = (total + 19) // 20 if total > 0 else page
result['limit'] = 20
result['total'] = total
except Exception as e:
print(f'searchContent error: {e}')
return result
def playerContent(self, flag, id, vipFlags):
try:
# id 是 base64 编码的 vod_id|source_code|episode_index
try:
decoded = base64.b64decode(id).decode()
except:
decoded = id
parts = decoded.split('|')
if len(parts) < 3:
return {'parse': 0, 'jx': 0, 'url': ''}
vod_id = int(parts[0])
source_code = parts[1]
episode_index = int(parts[2])
data = self._req('/api/site/play-resolve', {
'id': vod_id,
'source': source_code,
'episode': episode_index
})
if data and data.get('play_url'):
url = data['play_url']
headers = {'User-Agent': self.ua}
ua = data.get('user_agent', '')
if ua:
headers['User-Agent'] = ua
return {
'parse': 0,
'jx': 0,
'url': url,
'header': headers,
'danmaku': 'http://127.0.0.1:9978/proxy?do=diydanmu'
}
except Exception as e:
print(f'playerContent error: {e}')
return {'parse': 0, 'jx': 0, 'url': ''}
def localProxy(self, params):
return [200, "video/MP2T", {}, ""]
+491
View File
@@ -0,0 +1,491 @@
#coding=utf-8
import sys
import re
import json
import requests
sys.path.append('..')
from base.spider import Spider
class Spider(Spider):
def __init__(self):
super().__init__()
self.site = 'https://www.dazhongs.com'
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': 'https://www.dazhongs.com/'
})
self.cateManual = {
'电影': '1',
'电视剧': '2',
'综艺': '3',
'动漫': '4',
'短剧': '30',
}
def init(self, extend=''):
pass
def getName(self):
return '大众影视'
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def _clean(self, text):
if not text:
return ''
text = re.sub(r'<[^>]+>', '', text)
text = text.replace('&nbsp;', ' ').replace('&amp;', '&').replace('\u3000', ' ')
text = ' '.join(text.split())
return text.strip()
def _get(self, url):
try:
r = self.session.get(url, timeout=15)
r.encoding = 'utf-8'
return r.text
except Exception as e:
print(f'_get error: {e}')
return ''
def _getVid(self, url):
if not url:
return ''
m = re.search(r'/voddetail/(\d+)\.html', url)
if m:
return m.group(1)
m = re.search(r'/vodplay/(\d+)-', url)
if m:
return m.group(1)
return ''
def _fixUrl(self, url):
if not url:
return ''
url = url.replace('&amp;', '&')
if url.startswith('//'):
return 'https:' + url
if url.startswith('/'):
return self.site + url
if not url.startswith('http'):
return self.site + '/' + url
return url
def homeContent(self, filter):
result = {'class': [], 'filters': {}, 'list': [], 'parse': 0, 'jx': 0}
for k, v in self.cateManual.items():
result['class'].append({'type_id': str(v), 'type_name': k})
return result
def homeVideoContent(self):
videos = []
try:
html = self._get(self.site)
if not html:
return {'list': videos, 'parse': 0, 'jx': 0}
seen = set()
# 首页列表项: <li class="vodlist_item">...</li>
for m in re.finditer(r'<li\s+class="vodlist_item[^"]*"[^>]*>(.*?)</li>', html, re.DOTALL):
block = m.group(1)
# 标题和链接
tm = re.search(r'href="(/voddetail/\d+\.html)"[^>]*title="([^"]*)"', block)
if not tm:
continue
href = tm.group(1)
title = tm.group(2)
vid = self._getVid(href)
if not vid or vid in seen:
continue
seen.add(vid)
# 封面
pic = ''
pm = re.search(r'data-original="([^"]+)"', block)
if pm:
pic = self._fixUrl(pm.group(1))
# 备注
note = ''
nm = re.search(r'class="pic_text[^"]*"[^>]*>([^<]*)<', block)
if nm:
note = nm.group(1).strip()
if title:
videos.append({
'vod_id': vid,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
except Exception as e:
print(f'homeVideoContent error: {e}')
return {'list': videos, 'parse': 0, 'jx': 0}
def categoryContent(self, tid, pg, filter, extend):
result = {'list': [], 'parse': 0, 'jx': 0}
page = int(pg) if pg else 1
try:
if page == 1:
url = f'{self.site}/vodtype/{tid}.html'
else:
url = f'{self.site}/vodtype/{tid}-{page}.html'
html = self._get(url)
if not html:
return result
seen = set()
for m in re.finditer(r'<li\s+class="vodlist_item[^"]*"[^>]*>(.*?)</li>', html, re.DOTALL):
block = m.group(1)
tm = re.search(r'href="(/voddetail/\d+\.html)"[^>]*title="([^"]*)"', block)
if not tm:
continue
href = tm.group(1)
title = tm.group(2)
vid = self._getVid(href)
if not vid or vid in seen:
continue
seen.add(vid)
pic = ''
pm = re.search(r'data-original="([^"]+)"', block)
if pm:
pic = self._fixUrl(pm.group(1))
note = ''
nm = re.search(r'class="pic_text[^"]*"[^>]*>([^<]*)<', block)
if nm:
note = nm.group(1).strip()
if title:
result['list'].append({
'vod_id': vid,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
except Exception as e:
print(f'categoryContent error: {e}')
result['page'] = page
result['pagecount'] = page + 1 if len(result['list']) > 0 else page
result['limit'] = len(result['list'])
result['total'] = len(result['list'])
return result
def detailContent(self, ids):
result = {'list': [], 'parse': 0, 'jx': 0}
vid = ids[0] if ids else ''
if not vid:
return result
try:
html = self._get(f'{self.site}/voddetail/{vid}.html')
if not html:
return result
# 标题
title = ''
tm = re.search(r'<h2\s+class="title[^"]*"[^>]*>([^<]+)<', html)
if tm:
title = self._clean(tm.group(1))
if not title:
tm = re.search(r'<title>([^<]+)', html)
if tm:
title = self._clean(tm.group(1))
# 封面
pic = ''
pm = re.search(r'class="vodlist_thumb[^"]*"[^>]*data-original="([^"]+)"', html)
if pm:
pic = self._fixUrl(pm.group(1))
# 备注(状态)
remarks = ''
rm = re.search(r'class="data_style[^"]*"[^>]*>([^<]*)<', html)
if rm:
remarks = rm.group(1).strip()
# 简介
desc = ''
dm = re.search(r'class="desc[^"]*"[^>]*>(.*?)</li>', html, re.DOTALL)
if dm:
desc = self._clean(dm.group(1))
desc = re.sub(r'^简介:\s*', '', desc).strip()
if not desc:
dm2 = re.search(r'<meta\s+name="description"\s+content="([^"]*)"', html)
if dm2:
desc = dm2.group(1).strip()
# 年份/地区/类型/主演/导演
vod_year = ''
vod_area = ''
type_name = ''
vod_actor = ''
vod_director = ''
data_items = re.findall(r'<li\s+class="data[^"]*"[^>]*>(.*?)</li>', html, re.DOTALL)
if len(data_items) >= 1:
first = data_items[0]
ym = re.search(r'年份:</span><a[^>]*>([^<]+)', first)
if ym:
vod_year = ym.group(1).strip()
am = re.search(r'地区:</span><a[^>]*>([^<]+)', first)
if am:
vod_area = am.group(1).strip()
tm2 = re.search(r'类型:</span><a[^>]*>([^<]+)', first)
if tm2:
type_name = tm2.group(1).strip()
if len(data_items) >= 3:
actor_block = data_items[2]
actor_m = re.search(r'主演:(.*)', actor_block, re.DOTALL)
if actor_m:
vod_actor = self._clean(actor_m.group(1))
if len(data_items) >= 4:
dir_block = data_items[3]
dir_m = re.search(r'导演:(.*)', dir_block, re.DOTALL)
if dir_m:
vod_director = self._clean(dir_m.group(1))
# 线路和播放列表
play_from = []
play_url = []
# 线路名称: #NumTab 下的 <a alt="线路名">
tab_block = re.search(r'id="NumTab"[^>]*>(.*?)</div>', html, re.DOTALL)
tabs = []
if tab_block:
tabs = re.findall(r'<a[^>]*alt="([^"]*)"[^>]*>', tab_block.group(1))
# 播放列表: 每个 .play_list_box 内的 content_playlist
panels = re.findall(r'class="play_list_box[^"]*"[^>]*>(.*?)</div>\s*</div>', html, re.DOTALL)
for i, tab_name in enumerate(tabs):
play_from.append(tab_name)
episodes = []
if i < len(panels):
for em in re.finditer(r'<a[^>]*href="(/vodplay/[^"]+)"[^>]*>([^<]+)<', panels[i]):
ep_href = em.group(1)
ep_name = em.group(2).strip()
if ep_name and ep_href:
episodes.append(f'{ep_name}${ep_href}')
play_url.append('#'.join(episodes))
# 兜底: 如果没找到线路tab但有播放列表 (单线路情况)
if not tabs and panels:
play_from.append('默认线路')
episodes = []
for em in re.finditer(r'<a[^>]*href="(/vodplay/[^"]+)"[^>]*>([^<]+)<', panels[0]):
ep_href = em.group(1)
ep_name = em.group(2).strip()
if ep_name and ep_href:
episodes.append(f'{ep_name}${ep_href}')
play_url.append('#'.join(episodes))
vod = {
'vod_id': vid,
'vod_name': title,
'vod_pic': pic,
'type_name': type_name,
'vod_year': vod_year,
'vod_area': vod_area,
'vod_remarks': remarks,
'vod_actor': vod_actor,
'vod_director': vod_director,
'vod_content': desc,
'vod_play_from': '$$$'.join(play_from) if play_from else '',
'vod_play_url': '$$$'.join(play_url) if play_url else ''
}
result['list'].append(vod)
except Exception as e:
print(f'detailContent error: {e}')
return result
def playerContent(self, flag, id, vipFlags):
result = {}
danmaku = 'http://127.0.0.1:9978/proxy?do=diydanmu'
try:
play_url = id
if id and not id.startswith('http'):
play_url = self.site + id
html = self._get(play_url)
# 优先从 player_aaaa JSON 提取 m3u8 直链
m = re.search(r'player_aaaa\s*=\s*(\{.+?\})\s*<', html)
if m:
try:
data = json.loads(m.group(1))
m3u8 = data.get('url', '')
if m3u8 and '.m3u8' in m3u8:
result['parse'] = 0
result['url'] = m3u8
result['jx'] = 0
result['header'] = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': self.site + '/'
}
result['danmaku'] = danmaku
return result
except:
pass
# 备用: 从页面找 m3u8 链接
m = re.search(r'url["\s:]+(https?://[^"\s]*\.m3u8[^"\s]*)', html)
if m:
result['parse'] = 0
result['url'] = m.group(1).replace('\\/', '/')
result['jx'] = 0
result['header'] = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': self.site + '/'
}
result['danmaku'] = danmaku
return result
# 备用: iframe 嗅探
m = re.search(r'<iframe[^>]+src="([^"]+)"', html)
if m:
result['parse'] = 1
result['url'] = m.group(1)
result['jx'] = 0
result['header'] = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': self.site + '/'
}
result['danmaku'] = danmaku
else:
# 最终兜底: 嗅探模式
result['parse'] = 1
result['url'] = play_url
result['jx'] = 0
result['header'] = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': self.site + '/'
}
result['danmaku'] = danmaku
except Exception as e:
print(f'playerContent error: {e}')
result['parse'] = 1
result['url'] = id
result['jx'] = 0
result['header'] = {}
result['danmaku'] = danmaku
return result
def searchContent(self, key, quick, pg='1'):
result = {'list': [], 'parse': 0, 'jx': 0}
page = int(pg) if pg else 1
try:
url = f'{self.site}/vodsearch/-------------.html'
params = {'wd': key}
if page > 1:
params['page'] = page
r = self.session.get(url, params=params, timeout=15)
r.encoding = 'utf-8'
html = r.text
if not html:
return result
seen = set()
# 搜索结果用 .searchlist_item
for m in re.finditer(r'<li\s+class="searchlist_item[^"]*"[^>]*>(.*?)</li>', html, re.DOTALL):
block = m.group(1)
tm = re.search(r'href="(/voddetail/\d+\.html)"[^>]*title="([^"]*)"', block)
if not tm:
continue
href = tm.group(1)
title = tm.group(2)
vid = self._getVid(href)
if not vid or vid in seen:
continue
seen.add(vid)
# 封面
pic = ''
pm = re.search(r'data-original="([^"]+)"', block)
if pm:
pic = self._fixUrl(pm.group(1))
# 备注
note = ''
nm = re.search(r'class="pic_text[^"]*"[^>]*>([^<]*)<', block)
if nm:
note = nm.group(1).strip()
if title:
result['list'].append({
'vod_id': vid,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
except Exception as e:
print(f'searchContent error: {e}')
return result
def localProxy(self, params):
return [200, "video/MP2T", {}, ""]
if __name__ == '__main__':
spider = Spider()
print('=' * 60)
print('测试 homeContent ...')
home = spider.homeContent(True)
print(f"分类数量: {len(home['class'])}")
for c in home['class']:
print(f" {c['type_id']}: {c['type_name']}")
print()
print('=' * 60)
print('测试 homeVideoContent ...')
hv = spider.homeVideoContent()
print(f"首页列表数量: {len(hv['list'])}")
for item in hv['list'][:5]:
print(f" {item['vod_name']} | {item['vod_id']} | {item['vod_remarks']}")
print()
print('=' * 60)
print('测试 categoryContent (电影, 第1页) ...')
cat = spider.categoryContent('1', '1', True, {})
print(f"分类列表数量: {len(cat['list'])}")
for item in cat['list'][:3]:
print(f" {item['vod_name']} | {item['vod_id']}")
print()
print('=' * 60)
print('测试 searchContent (家业) ...')
search = spider.searchContent('家业', False, '1')
print(f"搜索结果数量: {len(search['list'])}")
for item in search['list'][:3]:
print(f" {item['vod_name']} | {item['vod_id']}")
print()
print('=' * 60)
test_id = '102577'
print(f'测试 detailContent (vod_id={test_id}) ...')
detail = spider.detailContent([test_id])
if detail['list']:
info = detail['list'][0]
print(f" 标题: {info['vod_name']}")
print(f" 年份: {info['vod_year']}")
print(f" 地区: {info['vod_area']}")
print(f" 类型: {info['type_name']}")
print(f" 主演: {info['vod_actor']}")
print(f" 导演: {info['vod_director']}")
print(f" 备注: {info['vod_remarks']}")
print(f" 封面: {info['vod_pic']}")
print(f" 简介: {info['vod_content'][:80]}...")
print(f" 线路: {info['vod_play_from']}")
play_urls = info['vod_play_url'].split('$$$')
for i, pu in enumerate(play_urls):
eps = pu.split('#')
print(f" 线路{i+1}: 共{len(eps)}集, 前3集名: {[e.split('$')[0] for e in eps[:3]]}")
print()
print('=' * 60)
print('测试 playerContent ...')
player = spider.playerContent('稳定线路①', f'/vodplay/102577-1-1.html', '')
print(f" parse: {player.get('parse')}")
print(f" url: {player.get('url', '')[:100]}...")
print(f" jx: {player.get('jx')}")
print()
print('全部测试完成!')
+16 -10
View File
@@ -4,16 +4,22 @@
"wallpaper": "https://gitlab.com/tenrecha/recha/-/raw/main/background.jpg",
"notice": "115.07.18_Ver.2 最終階段測試",
"sites": [
{
"key" : "威視.py",
"name" : "待測|威視",
"type" : 3,
"api" : "./py/威视TV.py",
"searchable" : 1,
"quickSearch": 1,
"filterable" : 0,
"changeable" : 0
},
{
"key": "大眾",
"name": "大眾影視|1080P",
"type": 3,
"api": "./py/大众.py",
"searchable": 1,
"quickSearch": 1
},
{
"key": "花子",
"name": "花子動漫|1080P",
"type": 3,
"api": "./py/huazi.py",
"searchable": 1,
"quickSearch": 1
},
{
"key": "豆瓣",
"name": "🇹🇼|熱播排行榜|自動切換",