Add files via upload
This commit is contained in:
parent
cb2a3d20a5
commit
f8e325de0e
148
py/py_hitv.py
Normal file
148
py/py_hitv.py
Normal file
@ -0,0 +1,148 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# 嗷呜
|
||||
import sys
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import requests
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
return "hitv"
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
# "直播": "live",
|
||||
'排行榜': 'rank',
|
||||
"电影": "1",
|
||||
"剧集": "2",
|
||||
"综艺": "3",
|
||||
"动画": "4",
|
||||
"短片": "5"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
return result
|
||||
|
||||
host = "https://wys.upfuhn.com"
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/80.0.3987.149 Safari/537.36"
|
||||
}
|
||||
|
||||
def list(self, list):
|
||||
videos = []
|
||||
for it in list:
|
||||
videos.append({
|
||||
"vod_id": it['video_site_id'],
|
||||
"vod_name": it['video_name'],
|
||||
"vod_pic": it['video_horizontal_url'] or it['video_vertical_url'],
|
||||
"vod_remarks": it['newest_series_num'],
|
||||
"vod_year": it['years'],
|
||||
})
|
||||
return videos
|
||||
|
||||
def homeVideoContent(self):
|
||||
url = f'{self.host}/v1/ys_video_sites/hot?t=1'
|
||||
data = requests.get(url, headers=self.headers).json()
|
||||
videos = self.list(data['data']['data'])
|
||||
result = {'list': videos}
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
path = f'/v1/ys_video_sites?t={tid}&s_t=0&a&y&o=0&ps=21&pn={pg}'
|
||||
rank = False
|
||||
if tid == 'rank':
|
||||
if pg == 1:
|
||||
path = f'/v1/ys_video_sites/ranking'
|
||||
rank = True
|
||||
else:
|
||||
path = ''
|
||||
# elif tid == 'live' and pg == 1:
|
||||
# path = f'/v1/ys_live_tvs'
|
||||
videos = []
|
||||
result = {}
|
||||
try:
|
||||
data = requests.get(self.host + path, headers=self.headers).json()
|
||||
if rank:
|
||||
for video in data['data']:
|
||||
videos.extend(data['data'][video])
|
||||
else:
|
||||
videos = data['data']['data']
|
||||
result = {}
|
||||
result['list'] = self.list(videos)
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
except:
|
||||
result['list'] = []
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
tid = ids[0]
|
||||
url = f'{self.host}/v1/ys_video_series/by_vid/{tid}'
|
||||
data = requests.get(url, headers=self.headers).json()
|
||||
data1 = data['data']['ys_video_site']
|
||||
urls = []
|
||||
for it in data['data']['data']:
|
||||
urls.append(it['series_num'] + '$' + it['video_url'])
|
||||
vod = {
|
||||
'vod_name': data1['video_name'],
|
||||
'type_name': data1['tag'],
|
||||
'vod_year': data1['years'],
|
||||
'vod_area': data1['area'],
|
||||
'vod_director': data1['main_actor'],
|
||||
'vod_content': data1['video_desc'],
|
||||
'vod_play_from': '嗷呜在线',
|
||||
'vod_play_url': '#'.join(urls),
|
||||
}
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg=1):
|
||||
url = f'{self.host}/v1/ys_video_sites/search?s={key}&o=0&ps=200&pn={pg}'
|
||||
data = requests.get(url, headers=self.headers).json()
|
||||
videos = data['data']['video_sites']
|
||||
if data['data']['first_video_series'] is not None:
|
||||
videos = [data['data']['first_video_series']] + videos
|
||||
result = {}
|
||||
result['list'] = self.list(videos)
|
||||
result['page'] = pg
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
result = {
|
||||
'url': id,
|
||||
'parse': 0,
|
||||
'header': self.headers
|
||||
}
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
213
py/py_lav.py
Normal file
213
py/py_lav.py
Normal file
@ -0,0 +1,213 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# 嗷呜
|
||||
import sys
|
||||
from base64 import b64encode, b64decode
|
||||
from Crypto.Hash import MD5, SHA256
|
||||
sys.path.append("..")
|
||||
from base.spider import Spider
|
||||
from Crypto.Cipher import AES
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def getName(self):
|
||||
return "lav"
|
||||
|
||||
def init(self, extend=""):
|
||||
self.id = self.ms(str(int(time.time() * 1000)))[:16]
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def action(self, action):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host = "http://sir_new.tiansexyl.tv"
|
||||
t = str(int(time.time() * 1000))
|
||||
headers = {'User-Agent': 'okhttp-okgo/jeasonlzy', 'Connection': 'Keep-Alive',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
|
||||
def homeContent(self, filter):
|
||||
cateManual = {"演员": "actor", "分类": "avsearch", }
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({'type_name': k, 'type_id': cateManual[k]})
|
||||
j = {'code': 'homePage', 'mod': 'down', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
|
||||
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
|
||||
'oauth_id': self.id}
|
||||
|
||||
body = self.aes(j)
|
||||
data = self.post(f'{self.host}/api.php?t={str(int(time.time() * 1000))}', data=body, headers=self.headers).json()['data']
|
||||
data1 = self.aes(data, False)['data']
|
||||
self.r = data1['r']
|
||||
for i, d in enumerate(data1['avTag']):
|
||||
# if i == 4:
|
||||
# break
|
||||
classes.append({'type_name': d['name'], 'type_id': d['tag']})
|
||||
resutl = {}
|
||||
resutl["class"] = classes
|
||||
return resutl
|
||||
|
||||
def homeVideoContent(self):
|
||||
pass
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
id = tid.split("@@")
|
||||
result = {}
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
if id[0] == 'avsearch':
|
||||
if pg == '1':
|
||||
j = {'code': 'avsearch', 'mod': 'search', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
|
||||
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
|
||||
'oauth_id': self.id}
|
||||
if len(id) > 1:
|
||||
j = {'code': 'find', 'mod': 'tag', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
|
||||
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
|
||||
'oauth_id': self.id, 'type': 'av', 'dis': 'new', 'page': str(pg), 'tag': id[1]}
|
||||
elif id[0] == 'actor':
|
||||
j = {'mod': 'actor', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv', 'app_type': 'rn',
|
||||
'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn', 'oauth_id': self.id,
|
||||
'page': str(pg), 'filter': ''}
|
||||
if len(id) > 1:
|
||||
j = {'code': 'eq', 'mod': 'actor', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
|
||||
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
|
||||
'oauth_id': self.id, 'page': str(pg), 'id': id[1], 'actor': id[2]}
|
||||
else:
|
||||
j = {'code': 'search', 'mod': 'av', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
|
||||
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
|
||||
'oauth_id': self.id, 'page': str(pg), 'tag': id[0]}
|
||||
|
||||
body = self.aes(j)
|
||||
data = self.post(f'{self.host}/api.php?t={str(int(time.time() * 1000))}', data=body, headers=self.headers).json()['data']
|
||||
data1 = self.aes(data, False)['data']
|
||||
videos = []
|
||||
if tid == 'avsearch' and len(id) == 1:
|
||||
for item in data1:
|
||||
videos.append({"vod_id": id[0] + "@@" + str(item.get('tags')), 'vod_name': item.get('name'),
|
||||
'vod_pic': self.imgs(item.get('ico')), 'vod_tag': 'folder',
|
||||
'style': {"type": "rect", "ratio": 1.33}})
|
||||
elif tid == 'actor' and len(id) == 1:
|
||||
for item in data1:
|
||||
videos.append({"vod_id": id[0] + "@@" + str(item.get('id')) + "@@" + item.get('name'),
|
||||
'vod_name': item.get('name'), 'vod_pic': self.imgs(item.get('cover')),
|
||||
'vod_tag': 'folder', 'style': {"type": "oval"}})
|
||||
else:
|
||||
for item in data1:
|
||||
if item.get('_id'):
|
||||
videos.append({"vod_id": str(item.get('id')), 'vod_name': item.get('title'),
|
||||
'vod_pic': self.imgs(item.get('cover_thumb') or item.get('cover_full')),
|
||||
'vod_remarks': item.get('good'), 'style': {"type": "rect", "ratio": 1.33}})
|
||||
result["list"] = videos
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
id = ids[0]
|
||||
j = {'code': 'detail', 'mod': 'av', 'channel': 'self', 'via': 'agent', 'bundleId': 'com.tvlutv',
|
||||
'app_type': 'rn', 'os_version': '12.0.5', 'version': '3.2.3', 'oauth_type': 'android_rn',
|
||||
'oauth_id': self.id, 'id': id}
|
||||
body = self.aes(j)
|
||||
data = self.post(f'{self.host}/api.php?t={str(int(time.time() * 1000))}', data=body, headers=self.headers).json()['data']
|
||||
data1 = self.aes(data, False)['line']
|
||||
vod = {}
|
||||
play = []
|
||||
for itt in data1:
|
||||
a = itt['line'].get('s720')
|
||||
if a:
|
||||
b = a.split('.')
|
||||
b[0] = 'https://m3u8'
|
||||
a = '.'.join(b)
|
||||
play.append(itt['info']['tips'] + "$" + a)
|
||||
break
|
||||
vod["vod_play_from"] = 'LAV'
|
||||
vod["vod_play_url"] = "#".join(play)
|
||||
result = {"list": [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
pass
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
url = self.getProxyUrl() + "&url=" + b64encode(id.encode('utf-8')).decode('utf-8') + "&type=m3u8"
|
||||
self.hh = {'User-Agent': 'dd', 'Connection': 'Keep-Alive', 'Referer': self.r}
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["url"] = url
|
||||
result["header"] = self.hh
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
url = param["url"]
|
||||
if param.get('type') == "m3u8":
|
||||
return self.vod(b64decode(url).decode('utf-8'))
|
||||
else:
|
||||
return self.img(url)
|
||||
|
||||
def vod(self, url):
|
||||
data = self.fetch(url, headers=self.hh).text
|
||||
key = bytes.fromhex("13d47399bda541b85e55830528d4e66f1791585b2d2216f23215c4c63ebace31")
|
||||
iv = bytes.fromhex(data[:32])
|
||||
data = data[32:]
|
||||
cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
|
||||
data_bytes = bytes.fromhex(data)
|
||||
decrypted = cipher.decrypt(data_bytes)
|
||||
encoded = decrypted.decode("utf-8").replace("\x08", "")
|
||||
return [200, "application/vnd.apple.mpegur", encoded]
|
||||
|
||||
def imgs(self, url):
|
||||
return self.getProxyUrl() + '&url=' + url
|
||||
|
||||
def img(self, url):
|
||||
type = url.split('.')[-1]
|
||||
data = self.fetch(url).text
|
||||
key = bytes.fromhex("ba78f184208d775e1553550f2037f4af22cdcf1d263a65b4d5c74536f084a4b2")
|
||||
iv = bytes.fromhex(data[:32])
|
||||
data = data[32:]
|
||||
cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
|
||||
data_bytes = bytes.fromhex(data)
|
||||
decrypted = cipher.decrypt(data_bytes)
|
||||
return [200, f"image/{type}", decrypted]
|
||||
|
||||
def ms(self, data, m=False):
|
||||
h = MD5.new()
|
||||
if m:
|
||||
h = SHA256.new()
|
||||
h.update(data.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
|
||||
def aes(self, data, operation=True):
|
||||
key = bytes.fromhex("620f15cfdb5c79c34b3940537b21eda072e22f5d7151456dec3932d7a2b22c53")
|
||||
t = str(int(time.time()))
|
||||
ivt = self.ms(t)
|
||||
if operation:
|
||||
data = json.dumps(data, separators=(',', ':'))
|
||||
iv = bytes.fromhex(ivt)
|
||||
else:
|
||||
iv = bytes.fromhex(data[:32])
|
||||
data = data[32:]
|
||||
cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
|
||||
if operation:
|
||||
data_bytes = data.encode('utf-8')
|
||||
encrypted = cipher.encrypt(data_bytes)
|
||||
ep = f'{ivt}{encrypted.hex()}'
|
||||
edata = f"data={ep}×tamp={t}0d27dfacef1338483561a46b246bf36d"
|
||||
sign = self.ms(self.ms(edata, True))
|
||||
edata = f"timestamp={t}&data={ep}&sign={sign}"
|
||||
return edata
|
||||
else:
|
||||
data_bytes = bytes.fromhex(data)
|
||||
decrypted = cipher.decrypt(data_bytes)
|
||||
return json.loads(decrypted.decode('utf-8'))
|
||||
|
94
py/py_mp.py
Normal file
94
py/py_mp.py
Normal file
@ -0,0 +1,94 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import sys
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "mp"
|
||||
|
||||
def init(self, extend=""):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host = 'https://g.c494.com'
|
||||
|
||||
header = {
|
||||
'User-Agent': 'Dart/2.10 (dart:io)',
|
||||
'platform_version': 'RP1A.200720.011',
|
||||
'version': '2.2.3',
|
||||
'copyright': 'xiaogui',
|
||||
'platform': 'android',
|
||||
'client_name': '576O5p+P5b2x6KeG',
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(f'{self.host}/api.php/app/nav?token=', headers=self.header).json()
|
||||
dy = {"class": "类型", "area": "地区", "lang": "语言", "year": "年份", "letter": "字母", "by": "排序",
|
||||
"sort": "排序"}
|
||||
filters = {}
|
||||
classes = []
|
||||
json_data = data["list"]
|
||||
for item in json_data:
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = item["type_extend"]
|
||||
classes.append({"type_name": item["type_name"], "type_id": str(item["type_id"])})
|
||||
for key in dy:
|
||||
if key in jsontype_extend and jsontype_extend[key].strip() != "":
|
||||
has_non_empty_field = True
|
||||
break
|
||||
if has_non_empty_field:
|
||||
filters[str(item["type_id"])] = []
|
||||
for dkey in jsontype_extend:
|
||||
if dkey in dy and jsontype_extend[dkey].strip() != "":
|
||||
values = jsontype_extend[dkey].split(",")
|
||||
value_array = [{"n": value.strip(), "v": value.strip()} for value in values if
|
||||
value.strip() != ""]
|
||||
filters[str(item["type_id"])].append({"key": dkey, "name": dy[dkey], "value": value_array})
|
||||
result = {}
|
||||
result["class"] = classes
|
||||
result["filters"] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
rsp = self.fetch(f"{self.host}/api.php/app/index_video?token=", headers=self.header)
|
||||
root = rsp.json()['list']
|
||||
videos = [item for vodd in root for item in vodd['vlist']]
|
||||
return {'list': videos}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
parms = {"pg": pg, "tid": tid, "class": extend.get("class", ""), "area": extend.get("area", ""),
|
||||
"lang": extend.get("lang", ""), "year": extend.get("year", ""), "token": ""}
|
||||
data = self.fetch(f'{self.host}/api.php/app/video', params=parms, headers=self.header).json()
|
||||
return data
|
||||
|
||||
def detailContent(self, ids):
|
||||
parms = {"id": ids[0], "token": ""}
|
||||
data = self.fetch(f'{self.host}/api.php/app/video_detail', params=parms, headers=self.header).json()
|
||||
vod = data['data']
|
||||
vod.pop('pause_advert_list', None)
|
||||
vod.pop('init_advert_list', None)
|
||||
vod.pop('vod_url_with_player', None)
|
||||
return {"list": [vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg='1'):
|
||||
parms = {'pg': pg, 'text': key, 'token': ''}
|
||||
data = self.fetch(f'{self.host}/api.php/app/search', params=parms, headers=self.header).json()
|
||||
return data
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
return {"parse": 0, "url": id, "header": {'User-Agent': 'User-Agent: Lavf/58.12.100'}}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
172
py/py_xpg.py
Normal file
172
py/py_xpg.py
Normal file
@ -0,0 +1,172 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import sys
|
||||
|
||||
sys.path.append('')
|
||||
from base.spider import Spider
|
||||
from urllib.parse import quote
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "xpg"
|
||||
|
||||
def init(self, extend=""):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(
|
||||
"{0}/api.php/v2.vod/androidtypes".format(self.host),
|
||||
headers=self.header,
|
||||
).json()
|
||||
dy = {
|
||||
"classes": "类型",
|
||||
"areas": "地区",
|
||||
"years": "年份",
|
||||
"sortby": "排序",
|
||||
}
|
||||
filters = {}
|
||||
classes = []
|
||||
for item in data['data']:
|
||||
has_non_empty_field = False
|
||||
item['soryby'] = ['updatetime', 'hits', 'score']
|
||||
demos = ['时间', '人气', '评分']
|
||||
classes.append({"type_name": item["type_name"], "type_id": str(item["type_id"])})
|
||||
for key in dy:
|
||||
if key in item and len(item[key]) > 1:
|
||||
has_non_empty_field = True
|
||||
break
|
||||
if has_non_empty_field:
|
||||
filters[str(item["type_id"])] = []
|
||||
for dkey in item:
|
||||
if dkey in dy and len(item[dkey]) > 1:
|
||||
values = item[dkey]
|
||||
value_array = [
|
||||
{"n": demos[idx] if dkey == "sortby" else value.strip(), "v": value.strip()}
|
||||
for idx, value in enumerate(values)
|
||||
if value.strip() != ""
|
||||
]
|
||||
filters[str(item["type_id"])].append(
|
||||
{"key": dkey, "name": dy[dkey], "value": value_array}
|
||||
)
|
||||
result = {}
|
||||
result["class"] = classes
|
||||
result["filters"] = filters
|
||||
return result
|
||||
|
||||
host = "http://item.xpgtv.com"
|
||||
header = {
|
||||
'User-Agent': 'okhttp/3.12.11',
|
||||
'token': 'ElEDlwCVgXcFHFhddiq2JKteHofExRBUrfNlmHrWetU3VVkxnzJAodl52N9EUFS+Dig2A/fBa/V9RuoOZRBjYvI+GW8kx3+xMlRecaZuECdb/3AdGkYpkjW3wCnpMQxf8vVeCz5zQLDr8l8bUChJiLLJLGsI+yiNskiJTZz9HiGBZhZuWh1mV1QgYah5CLTbSz8=',
|
||||
'token2': 'a0kEsBKRgTkBZ29NZ3WcNKN/C4T00RN/hNkmmGa5JMBeEENnqydLoetm/t8=',
|
||||
'user_id': 'XPGBOX',
|
||||
'version': 'XPGBOX com.phoenix.tv1.5.3',
|
||||
'timestamp': '1732286435',
|
||||
'hash': 'd9ab',
|
||||
}
|
||||
|
||||
def homeVideoContent(self):
|
||||
rsp = self.fetch("{0}/api.php/v2.main/androidhome".format(self.host), headers=self.header)
|
||||
root = rsp.json()['data']['list']
|
||||
videos = []
|
||||
for vodd in root:
|
||||
for vod in vodd['list']:
|
||||
videos.append({
|
||||
"vod_id": vod['id'],
|
||||
"vod_name": vod['name'],
|
||||
"vod_pic": vod['pic'],
|
||||
"vod_remarks": vod['score']
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
parms = []
|
||||
parms.append(f"page={pg}")
|
||||
parms.append(f"type={tid}")
|
||||
if extend.get('areas'):
|
||||
parms.append(f"area={quote(extend['areaes'])}")
|
||||
if extend.get('years'):
|
||||
parms.append(f"year={quote(extend['yeares'])}")
|
||||
if extend.get('sortby'):
|
||||
parms.append(f"sortby={extend['sortby']}")
|
||||
if extend.get('classes'):
|
||||
parms.append(f"class={quote(extend['classes'])}")
|
||||
parms = "&".join(parms)
|
||||
result = {}
|
||||
url = '{0}/api.php/v2.vod/androidfilter10086?{1}'.format(self.host, parms)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
root = rsp.json()['data']
|
||||
videos = []
|
||||
for vod in root:
|
||||
videos.append({
|
||||
"vod_id": vod['id'],
|
||||
"vod_name": vod['name'],
|
||||
"vod_pic": vod['pic'],
|
||||
"vod_remarks": vod['score']
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
id = ids[0]
|
||||
url = '{0}/api.php/v3.vod/androiddetail2?vod_id={1}'.format(self.host, id)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
root = rsp.json()['data']
|
||||
node = root['urls']
|
||||
d = [it['key'] + "$" + f"http://c.xpgtv.net/m3u8/{it['url']}.m3u8" for it in node]
|
||||
vod = {
|
||||
"vod_name": root['name'],
|
||||
'vod_play_from': '小苹果',
|
||||
'vod_play_url': '#'.join(d),
|
||||
}
|
||||
print(vod)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg='1'):
|
||||
url = '{0}/api.php/v2.vod/androidsearch10086?page={1}&wd={2}'.format(self.host, pg, key)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
root = rsp.json()['data']
|
||||
videos = []
|
||||
for vod in root:
|
||||
videos.append({
|
||||
"vod_id": vod['id'],
|
||||
"vod_name": vod['name'],
|
||||
"vod_pic": vod['pic'],
|
||||
"vod_remarks": vod['score']
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["url"] = id
|
||||
result["header"] = self.header
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
|
195
py/py_光速.py
Normal file
195
py/py_光速.py
Normal file
@ -0,0 +1,195 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import re
|
||||
import sys
|
||||
from urllib.parse import quote
|
||||
|
||||
from Crypto.Hash import MD5
|
||||
|
||||
sys.path.append("..")
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
from base64 import b64encode, b64decode
|
||||
import json
|
||||
import time
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def getName(self):
|
||||
return "光速"
|
||||
|
||||
def init(self, extend=""):
|
||||
self.host = self.gethost()
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def action(self, action):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.getdata("/api.php/getappapi.index/initV119")
|
||||
dy = {"class": "类型", "area": "地区", "lang": "语言", "year": "年份", "letter": "字母", "by": "排序",
|
||||
"sort": "排序", }
|
||||
filters = {}
|
||||
classes = []
|
||||
json_data = data["type_list"]
|
||||
homedata = data["banner_list"]
|
||||
for item in json_data:
|
||||
if item["type_name"] == "全部":
|
||||
continue
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = json.loads(item["type_extend"])
|
||||
homedata.extend(item["recommend_list"])
|
||||
jsontype_extend["sort"] = "最新,最热,最赞"
|
||||
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
|
||||
for key in dy:
|
||||
if key in jsontype_extend and jsontype_extend[key].strip() != "":
|
||||
has_non_empty_field = True
|
||||
break
|
||||
if has_non_empty_field:
|
||||
filters[str(item["type_id"])] = []
|
||||
for dkey in jsontype_extend:
|
||||
if dkey in dy and jsontype_extend[dkey].strip() != "":
|
||||
values = jsontype_extend[dkey].split(",")
|
||||
value_array = [{"n": value.strip(), "v": value.strip()} for value in values if
|
||||
value.strip() != ""]
|
||||
filters[str(item["type_id"])].append({"key": dkey, "name": dy[dkey], "value": value_array})
|
||||
result = {}
|
||||
result["class"] = classes
|
||||
result["filters"] = filters
|
||||
result["list"] = homedata
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
pass
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
body = {"area": extend.get('area', '全部'), "year": extend.get('year', '全部'), "type_id": tid, "page": pg,
|
||||
"sort": extend.get('sort', '最新'), "lang": extend.get('lang', '全部'),
|
||||
"class": extend.get('class', '全部')}
|
||||
result = {}
|
||||
data = self.getdata("/api.php/getappapi.index/typeFilterVodList", body)
|
||||
result["list"] = data["recommend_list"]
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
body = f"vod_id={ids[0]}"
|
||||
data = self.getdata("/api.php/getappapi.index/vodDetail", body)
|
||||
vod = data["vod"]
|
||||
|
||||
play = []
|
||||
names = []
|
||||
for itt in data["vod_play_list"]:
|
||||
a = []
|
||||
names.append(itt["player_info"]["show"])
|
||||
parse = itt["player_info"]["parse"]
|
||||
ua = ''
|
||||
if itt["player_info"].get("user_agent", ''):
|
||||
ua = b64encode(itt["player_info"]["user_agent"].encode('utf-8')).decode('utf-8')
|
||||
for it in itt["urls"]:
|
||||
url = it["url"]
|
||||
if not re.search(r'\.m3u8|\.mp4', url):
|
||||
url = parse + '@@' + url
|
||||
url = b64encode(url.encode('utf-8')).decode('utf-8')
|
||||
a.append(f"{it['name']}${url}|||{ua}|||{it['token']}")
|
||||
play.append("#".join(a))
|
||||
vod["vod_play_from"] = "$$$".join(names)
|
||||
vod["vod_play_url"] = "$$$".join(play)
|
||||
result = {"list": [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
body = f"keywords={key}&type_id=0&page={pg}"
|
||||
data = self.getdata("/api.php/getappapi.index/searchList", body)
|
||||
result = {"list": data["search_list"], "page": pg}
|
||||
return result
|
||||
|
||||
phend = {
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
ids = id.split("|||")
|
||||
if ids[1]: self.phend['User-Agent'] = b64decode(ids[1]).decode('utf-8')
|
||||
url = b64decode(ids[0]).decode('utf-8')
|
||||
if not re.search(r'\.m3u8|\.mp4', url):
|
||||
a = url.split("@@")
|
||||
body = f"parse_api={a[0]}&url={quote(self.aes('encrypt', a[1]))}&token={ids[-1]}"
|
||||
jd = self.getdata("/api.php/getappapi.index/vodParse", body)['json']
|
||||
url = json.loads(jd)['url']
|
||||
# if '.mp4' not in url:
|
||||
# l=self.fetch(url, headers=self.phend,allow_redirects=False)
|
||||
# if l.status_code == 200 and l.headers.get('Location',''):
|
||||
# url=l.headers['Location']
|
||||
if '.jpg' in url or '.png' in url or '.jpeg' in url:
|
||||
url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["url"] = url
|
||||
result["header"] = self.phend
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
url = b64decode(param["url"]).decode('utf-8')
|
||||
durl = url[:url.rfind('/')]
|
||||
data = self.fetch(url, headers=self.phend).content.decode("utf-8")
|
||||
inde = None
|
||||
pd = True
|
||||
lines = data.strip().split('\n')
|
||||
for index, string in enumerate(lines):
|
||||
# if '#EXT-X-DISCONTINUITY' in string and pd:
|
||||
# pd = False
|
||||
# inde = index
|
||||
if '#EXT' not in string and 'http' not in string:
|
||||
lines[index] = durl + ('' if string.startswith('/') else '/') + string
|
||||
if inde:
|
||||
del lines[inde:inde + 4]
|
||||
data = '\n'.join(lines)
|
||||
return [200, "application/vnd.apple.mpegur", data]
|
||||
|
||||
def gethost(self):
|
||||
host = self.fetch('https://jingyu-1312635929.cos.ap-nanjing.myqcloud.com/1.json').text.strip()
|
||||
return host
|
||||
|
||||
def aes(self, operation, text):
|
||||
key = "4d83b87c4c5ea111".encode("utf-8")
|
||||
iv = key
|
||||
if operation == "encrypt":
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size))
|
||||
ct = b64encode(ct_bytes).decode("utf-8")
|
||||
return ct
|
||||
elif operation == "decrypt":
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
|
||||
return pt.decode("utf-8")
|
||||
|
||||
def header(self):
|
||||
t = str(int(time.time()))
|
||||
md5_hash = MD5.new()
|
||||
md5_hash.update(t.encode('utf-8'))
|
||||
signature_md5 = md5_hash.hexdigest()
|
||||
header = {"User-Agent": "okhttp/3.14.9", "app-version-code": "300", "app-ui-mode": "light",
|
||||
"app-user-device-id": signature_md5, "app-api-verify-time": t,
|
||||
"app-api-verify-sign": self.aes("encrypt", t), "Content-Type": "application/x-www-form-urlencoded"}
|
||||
return header
|
||||
|
||||
def getdata(self, path, data=None):
|
||||
# data = self.post(self.host + path, headers=self.header(), data=data).text
|
||||
data = self.post(self.host + path, headers=self.header(), data=data, verify=False).json()["data"]
|
||||
data1 = self.aes("decrypt", data)
|
||||
return json.loads(data1)
|
269
py/py_剧多短剧.py
Normal file
269
py/py_剧多短剧.py
Normal file
@ -0,0 +1,269 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import base64
|
||||
import binascii
|
||||
import json
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
from base64 import b64decode, b64encode
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import MD5
|
||||
from Crypto.Util.Padding import unpad, pad
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.did=self.random_str(16)
|
||||
self.ntid=self.random_str(24)
|
||||
self.sign= {'token':None, 'uid':None}
|
||||
_ = self.gettoken()
|
||||
# self.phost, self.phz,self.mphost=self.getpic()
|
||||
self.phost, self.phz,self.mphost = ('https://dbtp.tgydy.com','.log','https://dplay.nbzsmc.com')
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host='http://192.151.245.34:8089'
|
||||
|
||||
def md5(self, text):
|
||||
h = MD5.new()
|
||||
h.update(text.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
|
||||
def uuid(self):
|
||||
return str(uuid.uuid4())
|
||||
|
||||
def aes(self, text, bool=True):
|
||||
key = b64decode('c0k4N1RfKTY1U1cjJERFRA==')
|
||||
iv = b64decode('VzIjQWRDVkdZSGFzSEdEVA==')
|
||||
if bool:
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size))
|
||||
ct = b64encode(ct_bytes).decode("utf-8")
|
||||
return ct
|
||||
else:
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
|
||||
ptt=json.loads(pt.decode("utf-8"))
|
||||
return ptt
|
||||
|
||||
def random_str(self,length=24):
|
||||
hex_chars = '0123456789abcdef'
|
||||
return ''.join(random.choice(hex_chars) for _ in range(length))
|
||||
|
||||
def gettoken(self):
|
||||
params={"deviceId":self.did,"deviceModel":"8848钛晶手机","devicePlatform":"1","tenantId":self.ntid}
|
||||
data=self.getdata('/supports/anonyLogin',params)
|
||||
self.sign['token']=data['data']['token']
|
||||
self.sign['uid'] = data['data']['userId']
|
||||
return 666
|
||||
|
||||
def getdata(self,path,params=None):
|
||||
t = int(time.time())
|
||||
n=self.md5(f'{self.uuid()}{t*1000}')
|
||||
if params:
|
||||
ct=self.aes(json.dumps(params))
|
||||
else:
|
||||
ct=f'{t}{n}'
|
||||
s=self.md5(f'{ct}8j@78m.367HGDF')
|
||||
headers = {
|
||||
'User-Agent': 'okhttp-okgo/jeasonlzy',
|
||||
'Connection': 'Keep-Alive',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.8',
|
||||
'tenantId': self.ntid,
|
||||
'n': n,
|
||||
't': str(t),
|
||||
's': s,
|
||||
# 'Content-Type': 'application/json; charset=utf-8',
|
||||
}
|
||||
if self.sign['token']:
|
||||
headers['ta-token'] = self.sign['token']
|
||||
headers['userId'] = self.sign['uid']
|
||||
if params:
|
||||
params={'ct':ct.replace('=','\u003d')}
|
||||
response = self.post(f'{self.host}{path}', headers=headers, json=params).text
|
||||
else:
|
||||
response = self.fetch(f'{self.host}{path}', headers=headers).text
|
||||
data=self.aes(response[1:-1],False)
|
||||
return data
|
||||
|
||||
def getpic(self):
|
||||
data=self.getdata(f'/supports/configs?tenantId={self.ntid}')
|
||||
oic=['','','']
|
||||
for i in data['data']:
|
||||
if i['name']=='image_cdn':
|
||||
oic[0]=i['records'][0]['value']
|
||||
if i['name']=='image_cdn_path':
|
||||
oic[1]=i['records'][0]['value']
|
||||
if i['name']=='cdn-domain':
|
||||
oic[1]=i['records'][0]['value'].split('#')[0]
|
||||
return (oic[0],oic[1],oic[2])
|
||||
|
||||
def getlist(self,data):
|
||||
vod=[]
|
||||
for i in data:
|
||||
vod.append({
|
||||
'vod_id': f'{i.get("movieId")}@{i.get("entryNum")}',
|
||||
'vod_name': i.get('title'),
|
||||
'vod_pic': f'{self.getProxyUrl()}&path={i.get("thumbnail")}',
|
||||
'vod_year': i.get('score'),
|
||||
'vod_remarks': f'{i.get("entryNum")}集'
|
||||
})
|
||||
return vod
|
||||
|
||||
def homeContent(self, filter):
|
||||
data=self.getdata('/movies/classifies')
|
||||
result = {}
|
||||
cateManual = {
|
||||
"榜单": "ranking/getTodayHotRank",
|
||||
"专辑": "getTMovieFolderPage",
|
||||
"剧场": "getClassMoviePage2",
|
||||
"演员": "follow/getRecommendActorPage",
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
filters = {}
|
||||
if data.get('data'):
|
||||
filters["getClassMoviePage2"] = [
|
||||
{
|
||||
"key": "type",
|
||||
"name": "分类",
|
||||
"value": [
|
||||
{"n": item["name"], "v": item["classifyId"]}
|
||||
for item in data["data"]
|
||||
]
|
||||
}
|
||||
]
|
||||
filters["ranking/getTodayHotRank"] = [
|
||||
{
|
||||
"key": "type",
|
||||
"name": "榜单",
|
||||
"value": [
|
||||
{"n": "播放榜", "v": "getWeekHotPlayRank"},
|
||||
{"n": "高赞榜", "v": "getWeekStarRank"},
|
||||
{"n": "追剧榜", "v": "getSubTMoviePage"},
|
||||
{"n": "高分榜", "v": "ranking/getScoreRank"}
|
||||
]
|
||||
}
|
||||
]
|
||||
filters["follow/getRecommendActorPage"] = [
|
||||
{
|
||||
"key": "type",
|
||||
"name": "性别",
|
||||
"value": [
|
||||
{"n": "男", "v": "0"},
|
||||
{"n": "女", "v": "1"}
|
||||
]
|
||||
}
|
||||
]
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
params = {"pageNo":"1","pageSize":"30","platform":"1","deviceId":self.did,"tenantId":self.ntid}
|
||||
data=self.getdata('/news/getRecommendTMoviePage',params)
|
||||
vod=self.getlist(data['data']['records'])
|
||||
return {'list':vod}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
params={}
|
||||
path = f'/news/{tid}'
|
||||
if tid=='getClassMoviePage2':
|
||||
parama={"pageNo":pg,"pageSize":"30","orderFlag":"0","haveActor":"-1","classifyId":extend.get('type','-1'),"tagId":""}
|
||||
elif 'rank' in tid:
|
||||
path=f'/news/{extend.get("type") or tid}'
|
||||
parama={"pageNo":pg,"pageSize":"30"}
|
||||
elif 'follow' in tid:
|
||||
parama={"pageNo":pg,"pageSize":"20"}
|
||||
if extend.get('type'):
|
||||
path=f'/news/getActorPage'
|
||||
parama={"pageNo":pg,"pageSize":"50","sex":extend.get('type')}
|
||||
elif tid=='getTMovieFolderPage':
|
||||
parama={"pageNo":pg,"pageSize":"20"}
|
||||
elif '@' in tid:
|
||||
path='/news/getActorTMoviePage'
|
||||
parama={"id":tid.split('@')[0],"pageNo":pg,"pageSize":"30"}
|
||||
params['platform'] = '1'
|
||||
params['deviceId'] = self.did
|
||||
params['tenantId'] = self.ntid
|
||||
data=self.getdata(path,parama)
|
||||
vods=[]
|
||||
if 'follow' in tid:
|
||||
for i in data['data']['records']:
|
||||
vods.append({
|
||||
'vod_id': f'{i.get("id")}@',
|
||||
'vod_name': i.get('name'),
|
||||
'vod_pic': f'{self.getProxyUrl()}&path={i.get("avatar")}',
|
||||
'vod_tag': 'folder',
|
||||
'vod_remarks': f'作品{i.get("movieNum")}',
|
||||
'style': {"type": "oval"}
|
||||
})
|
||||
else:
|
||||
vdata=data['data']['records']
|
||||
if tid=='getTMovieFolderPage':
|
||||
vdata=[j for i in data['data']['records'] for j in i['movieList']]
|
||||
vods=self.getlist(vdata)
|
||||
result = {}
|
||||
result['list'] = vods
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
ids=ids[0].split('@')
|
||||
params = {"pageNo": "1", "pageSize": ids[1], "movieId": ids[0], "platform": "1", "deviceId": self.did, "tenantId": self.ntid}
|
||||
data = self.getdata('/news/getEntryPage', params)
|
||||
print(data)
|
||||
plist=[f'第{i.get("entryNum")}集${i.get("mp4PlayAddress") or i.get("playAddress")}' for i in data['data']['records']]
|
||||
vod = {
|
||||
'vod_play_from': '嗷呜爱看短剧',
|
||||
'vod_play_url': '#'.join(plist),
|
||||
}
|
||||
return {'list':[vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
params = {"pageNo": pg, "pageSize": "20", "keyWord": key, "orderFlag": "0", "platform": "1", "deviceId": self.did, "tenantId": self.ntid}
|
||||
data = self.getdata('/news/searchTMoviePage', params)
|
||||
vod = self.getlist(data['data']['records'])
|
||||
return {'list':vod,'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
return {'parse': 0, 'url': f'{self.mphost}{id}', 'header': {'User-Agent':'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'}}
|
||||
|
||||
def localProxy(self, param):
|
||||
type=param.get('path').split('.')[-1]
|
||||
data=self.fetch(f'{self.phost}{param.get("path")}{self.phz}',headers={'User-Agent':'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'})
|
||||
def decrypt(encrypted_text):
|
||||
try:
|
||||
key = b64decode("iM41VipvCFtToAFFRExEXw==")
|
||||
iv = b64decode("0AXRTXzmMSrlRSemWb4sVQ==")
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted_padded = cipher.decrypt(encrypted_text)
|
||||
decrypted_data = unpad(decrypted_padded, AES.block_size)
|
||||
return decrypted_data
|
||||
except (binascii.Error, ValueError):
|
||||
return None
|
||||
return [200, f'image/{type}', decrypt(data.content)]
|
176
py/py_小红薯.py
Normal file
176
py/py_小红薯.py
Normal file
@ -0,0 +1,176 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import json
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from base64 import b64decode
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import MD5
|
||||
from Crypto.Util.Padding import unpad
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def getName(self):
|
||||
return "小红书"
|
||||
|
||||
def init(self, extend=""):
|
||||
self.did = self.random_str(32)
|
||||
self.token,self.phost = self.gettoken()
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def random_str(self,length=16):
|
||||
hex_chars = '0123456789abcdef'
|
||||
return ''.join(random.choice(hex_chars) for _ in range(length))
|
||||
|
||||
def md5(self, text: str) -> str:
|
||||
h = MD5.new()
|
||||
h.update(text.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(f'{self.host}/api/video/queryClassifyList?mark=4', headers=self.headers()).json()['encData']
|
||||
data1 = self.aes(data)
|
||||
result = {}
|
||||
classes = []
|
||||
for k in data1['data']:
|
||||
classes.append({'type_name': k['classifyTitle'], 'type_id': k['classifyId']})
|
||||
result['class'] = classes
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
pass
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
path=f'/api/short/video/getShortVideos?classifyId={tid}&videoMark=4&page={pg}&pageSize=20'
|
||||
result = {}
|
||||
videos = []
|
||||
data=self.fetch(f'{self.host}{path}', headers=self.headers()).json()['encData']
|
||||
vdata=self.aes(data)
|
||||
for k in vdata['data']:
|
||||
videos.append({"vod_id": k['videoId'], 'vod_name': k.get('title'), 'vod_pic': self.getProxyUrl() + '&url=' + k['coverImg'],
|
||||
'vod_remarks': self.dtim(k.get('playTime'))})
|
||||
result["list"] = videos
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
path = f'/api/video/getVideoById?videoId={ids[0]}'
|
||||
data = self.fetch(f'{self.host}{path}', headers=self.headers()).json()['encData']
|
||||
v = self.aes(data)
|
||||
d=f'{v["title"]}$auth_key={v["authKey"]}&path={v["videoUrl"]}'
|
||||
vod = {'vod_name': v["title"], 'type_name': ''.join(v.get('tagTitles',[])),'vod_play_from': v.get('nickName') or "小红书官方", 'vod_play_url': d}
|
||||
result = {"list": [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg='1'):
|
||||
pass
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
h=self.headers()
|
||||
h['Authorization'] = h.pop('aut')
|
||||
del h['deviceid']
|
||||
result = {"parse": 0, "url": f"{self.host}/api/m3u8/decode/authPath?{id}", "header": h}
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
return self.action(param)
|
||||
|
||||
def aes(self, word):
|
||||
key = b64decode("SmhiR2NpT2lKSVV6STFOaQ==")
|
||||
iv = key
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted = unpad(cipher.decrypt(b64decode(word)), AES.block_size)
|
||||
return json.loads(decrypted.decode('utf-8'))
|
||||
|
||||
def dtim(self, seconds):
|
||||
try:
|
||||
seconds = int(seconds)
|
||||
hours = seconds // 3600
|
||||
remaining_seconds = seconds % 3600
|
||||
minutes = remaining_seconds // 60
|
||||
remaining_seconds = remaining_seconds % 60
|
||||
|
||||
formatted_minutes = str(minutes).zfill(2)
|
||||
formatted_seconds = str(remaining_seconds).zfill(2)
|
||||
|
||||
if hours > 0:
|
||||
formatted_hours = str(hours).zfill(2)
|
||||
return f"{formatted_hours}:{formatted_minutes}:{formatted_seconds}"
|
||||
else:
|
||||
return f"{formatted_minutes}:{formatted_seconds}"
|
||||
except:
|
||||
return ''
|
||||
|
||||
def getsign(self):
|
||||
t=str(int(time.time() * 1000))
|
||||
return self.md5(t[3:8])
|
||||
|
||||
def gettoken(self):
|
||||
url = f'{self.host}/api/user/traveler'
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36;SuiRui/xhs/ver=1.2.6',
|
||||
'deviceid': self.did, 't': str(int(time.time() * 1000)), 's': self.getsign(), }
|
||||
data = {'deviceId': self.did, 'tt': 'U', 'code': '', 'chCode': 'dafe13'}
|
||||
data1 = self.post(url, json=data, headers=headers).json()
|
||||
data2 = data1['data']
|
||||
return data2['token'], data2['imgDomain']
|
||||
|
||||
host = 'https://jhfkdnov21vfd.fhoumpjjih.work'
|
||||
|
||||
def headers(self):
|
||||
henda = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36;SuiRui/xhs/ver=1.2.6',
|
||||
'deviceid': self.did, 't': str(int(time.time() * 1000)), 's': self.getsign(), 'aut': self.token}
|
||||
return henda
|
||||
|
||||
def action(self, param):
|
||||
headers = {
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'}
|
||||
data = self.fetch(f'{self.phost}{param["url"]}', headers=headers)
|
||||
type=data.headers.get('Content-Type').split(';')[0]
|
||||
base64_data = self.img(data.content, 100, '2020-zq3-888')
|
||||
return [200, type, base64_data]
|
||||
|
||||
def img(self, data: bytes, length: int, key: str):
|
||||
GIF = b'\x47\x49\x46'
|
||||
JPG = b'\xFF\xD8\xFF'
|
||||
PNG = b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'
|
||||
|
||||
def is_dont_need_decode_for_gif(data):
|
||||
return len(data) > 2 and data[:3] == GIF
|
||||
|
||||
def is_dont_need_decode_for_jpg(data):
|
||||
return len(data) > 7 and data[:3] == JPG
|
||||
|
||||
def is_dont_need_decode_for_png(data):
|
||||
return len(data) > 7 and data[1:8] == PNG[1:8]
|
||||
|
||||
if is_dont_need_decode_for_png(data):
|
||||
return data
|
||||
elif is_dont_need_decode_for_gif(data):
|
||||
return data
|
||||
elif is_dont_need_decode_for_jpg(data):
|
||||
return data
|
||||
else:
|
||||
key_bytes = key.encode('utf-8')
|
||||
result = bytearray(data)
|
||||
for i in range(length):
|
||||
result[i] ^= key_bytes[i % len(key_bytes)]
|
||||
return bytes(result)
|
217
py/py_推特.py
Normal file
217
py/py_推特.py
Normal file
@ -0,0 +1,217 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from base64 import b64decode
|
||||
from urllib.parse import quote
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import MD5
|
||||
from Crypto.Util.Padding import unpad
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def getName(self):
|
||||
return "tuit"
|
||||
|
||||
def init(self, extend=""):
|
||||
self.did = MD5.new((self.t).encode()).hexdigest()
|
||||
self.token = self.gettoken()
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def action(self, action):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def aes(self, word):
|
||||
key = b64decode("SmhiR2NpT2lKSVV6STFOaQ==")
|
||||
iv = key
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted = unpad(cipher.decrypt(b64decode(word)), AES.block_size)
|
||||
return json.loads(decrypted.decode('utf-8'))
|
||||
|
||||
def dtim(self, seconds):
|
||||
seconds = int(seconds)
|
||||
hours = seconds // 3600
|
||||
remaining_seconds = seconds % 3600
|
||||
minutes = remaining_seconds // 60
|
||||
remaining_seconds = remaining_seconds % 60
|
||||
|
||||
formatted_minutes = str(minutes).zfill(2)
|
||||
formatted_seconds = str(remaining_seconds).zfill(2)
|
||||
|
||||
if hours > 0:
|
||||
formatted_hours = str(hours).zfill(2)
|
||||
return f"{formatted_hours}:{formatted_minutes}:{formatted_seconds}"
|
||||
else:
|
||||
return f"{formatted_minutes}:{formatted_seconds}"
|
||||
|
||||
def gettoken(self):
|
||||
url = 'https://d1frehx187fm2c.cloudfront.net/api/user/traveler'
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36;SuiRui/twitter/ver=1.3.4',
|
||||
'deviceid': self.did, 't': self.t, 's': self.sign, }
|
||||
data = {'deviceId': self.did, 'tt': 'U', 'code': '', 'chCode': ''}
|
||||
data1 = self.post(url, json=data, headers=headers).json()
|
||||
token = data1['data']['token']
|
||||
return token
|
||||
|
||||
t = str(int(time.time() * 1000))
|
||||
sign = MD5.new((t[3:8]).encode()).hexdigest()
|
||||
host = 'https://api.wcyfhknomg.work'
|
||||
|
||||
def headers(self):
|
||||
henda = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36;SuiRui/twitter/ver=1.3.4',
|
||||
'deviceid': self.did, 't': self.t, 's': self.sign, 'aut': self.token}
|
||||
return henda
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(f'{self.host}/api/video/classifyList', headers=self.headers()).json()['encData']
|
||||
data1 = self.aes(data)
|
||||
result = {'filters': {"1": [{"key": "fl", "name": "分类",
|
||||
"value": [{"n": "最近更新", "v": "1"}, {"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}], "2": [{"key": "fl", "name": "分类",
|
||||
"value": [
|
||||
{"n": "最近更新", "v": "1"},
|
||||
{"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}],
|
||||
"3": [{"key": "fl", "name": "分类",
|
||||
"value": [{"n": "最近更新", "v": "1"}, {"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}], "4": [{"key": "fl", "name": "分类",
|
||||
"value": [
|
||||
{"n": "最近更新", "v": "1"},
|
||||
{"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}],
|
||||
"5": [{"key": "fl", "name": "分类",
|
||||
"value": [{"n": "最近更新", "v": "1"}, {"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}], "6": [{"key": "fl", "name": "分类",
|
||||
"value": [
|
||||
{"n": "最近更新", "v": "1"},
|
||||
{"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}],
|
||||
"7": [{"key": "fl", "name": "分类",
|
||||
"value": [{"n": "最近更新", "v": "1"}, {"n": "最多播放", "v": "2"},
|
||||
{"n": "好评榜", "v": "3"}]}], "jx": [{"key": "type", "name": "精选",
|
||||
"value": [{"n": "日榜", "v": "1"},
|
||||
{"n": "周榜", "v": "2"},
|
||||
{"n": "月榜", "v": "3"},
|
||||
{"n": "总榜",
|
||||
"v": "4"}]}]}}
|
||||
classes = [{'type_name': "精选", 'type_id': "jx"}]
|
||||
for k in data1['data']:
|
||||
classes.append({'type_name': k['classifyTitle'], 'type_id': k['classifyId']})
|
||||
result['class'] = classes
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
pass
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
path = f'/api/video/queryVideoByClassifyId?pageSize=20&page={pg}&classifyId={tid}&sortType={extend.get("fl", "1")}'
|
||||
if 'click' in tid:
|
||||
path = f'/api/video/queryPersonVideoByType?pageSize=20&page={pg}&userId={tid.replace("click", "")}'
|
||||
if tid == 'jx':
|
||||
path = f'/api/video/getRankVideos?pageSize=20&page={pg}&type={extend.get("type", "1")}'
|
||||
data = self.fetch(f'{self.host}{path}', headers=self.headers()).json()['encData']
|
||||
data1 = self.aes(data)['data']
|
||||
result = {}
|
||||
videos = []
|
||||
for k in data1:
|
||||
img = 'https://dg2ordyr4k5v3.cloudfront.net/' + k.get('coverImg')[0]
|
||||
id = f'{k.get("videoId")}?{k.get("userId")}?{k.get("nickName")}'
|
||||
if 'click' in tid:
|
||||
id = id + 'click'
|
||||
videos.append({"vod_id": id, 'vod_name': k.get('title'), 'vod_pic': self.getProxyUrl() + '&url=' + img,
|
||||
'vod_remarks': self.dtim(k.get('playTime')),'style': {"type": "rect", "ratio": 1.33}})
|
||||
result["list"] = videos
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
vid = ids[0].replace('click', '').split('?')
|
||||
path = f'/api/video/can/watch?videoId={vid[0]}'
|
||||
data = self.fetch(f'{self.host}{path}', headers=self.headers()).json()['encData']
|
||||
data1 = self.aes(data)['playPath']
|
||||
clj = '[a=cr:' + json.dumps({'id': vid[1] + 'click', 'name': vid[2]}) + '/]' + vid[2] + '[/a]'
|
||||
if 'click' in ids[0]:
|
||||
clj = vid[2]
|
||||
vod = {'vod_director': clj, 'vod_play_from': "推特", 'vod_play_url': vid[2] + "$" + data1}
|
||||
result = {"list": [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg='1'):
|
||||
path = f'/api/search/keyWord?pageSize=20&page={pg}&searchWord={quote(key)}&searchType=1'
|
||||
data = self.fetch(f'{self.host}{path}', headers=self.headers()).json()['encData']
|
||||
data1 = self.aes(data)['videoList']
|
||||
result = {}
|
||||
videos = []
|
||||
for k in data1:
|
||||
img = 'https://dg2ordyr4k5v3.cloudfront.net/' + k.get('coverImg')[0]
|
||||
id = f'{k.get("videoId")}?{k.get("userId")}?{k.get("nickName")}'
|
||||
videos.append({"vod_id": id, 'vod_name': k.get('title'), 'vod_pic': self.getProxyUrl() + '&url=' + img,
|
||||
'vod_remarks': self.dtim(k.get('playTime')), 'style': {"type": "rect", "ratio": 1.33}})
|
||||
result["list"] = videos
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
result = {"parse": 0, "url": id, "header": {'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36;SuiRui/twitter/ver=1.3.4'}}
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
return self.imgs(param)
|
||||
|
||||
def imgs(self, param):
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36;SuiRui/twitter/ver=1.3.4'}
|
||||
url = param['url']
|
||||
type = url.split('.')[-1].split('_')[0]
|
||||
data = self.fetch(url,headers=headers).content
|
||||
bdata = self.img(data, 100, '2020-zq3-888')
|
||||
return [200, f'image/{type}', bdata]
|
||||
|
||||
def img(self, data: bytes, length: int, key: str):
|
||||
GIF = b'\x47\x49\x46'
|
||||
JPG = b'\xFF\xD8\xFF'
|
||||
PNG = b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'
|
||||
|
||||
def is_dont_need_decode_for_gif(data):
|
||||
return len(data) > 2 and data[:3] == GIF
|
||||
|
||||
def is_dont_need_decode_for_jpg(data):
|
||||
return len(data) > 7 and data[:3] == JPG
|
||||
|
||||
def is_dont_need_decode_for_png(data):
|
||||
return len(data) > 7 and data[1:8] == PNG[1:8]
|
||||
|
||||
if is_dont_need_decode_for_png(data):
|
||||
return data
|
||||
elif is_dont_need_decode_for_gif(data):
|
||||
return data
|
||||
elif is_dont_need_decode_for_jpg(data):
|
||||
return data
|
||||
else:
|
||||
key_bytes = key.encode('utf-8')
|
||||
result = bytearray(data)
|
||||
for i in range(length):
|
||||
result[i] ^= key_bytes[i % len(key_bytes)]
|
||||
return bytes(result)
|
350
py/py_浴火社.py
Normal file
350
py/py_浴火社.py
Normal file
@ -0,0 +1,350 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from base64 import b64decode, b64encode
|
||||
import requests
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import MD5
|
||||
from Crypto.Util.Padding import unpad
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.did = self.getdid()
|
||||
self.token=self.gettoken()
|
||||
domain=self.domain()
|
||||
self.phost=self.host_late(domain['domain_preview'])
|
||||
self.bhost=domain['domain_original']
|
||||
self.names=domain['name_original']
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host = 'https://lulu-api-92mizw.jcdwn.com'
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/4.11.0',
|
||||
'referer': 'https://app.nova-traffic-1688.com',
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
BASE_CATEGORIES = [
|
||||
{'type_name': '片商', 'type_id': 'makers'},
|
||||
{'type_name': '演员', 'type_id': 'actor'}
|
||||
]
|
||||
|
||||
SORT_OPTIONS = {
|
||||
'key': 'sortby',
|
||||
'name': 'sortby',
|
||||
'value': [
|
||||
{'n': '最新', 'v': 'on_shelf_at'},
|
||||
{'n': '最热', 'v': 'hot'}
|
||||
]
|
||||
}
|
||||
|
||||
tags = self.getdata('/api/v1/video/tag?current=1&pageSize=100&level=1')
|
||||
producers = self.getdata('/api/v1/video/producer?current=1&pageSize=100&status=1')
|
||||
regions = self.getdata('/api/v1/video/region?current=1&pageSize=100')
|
||||
result = {'class': [], 'filters': {}}
|
||||
result['class'].extend(BASE_CATEGORIES)
|
||||
for category in BASE_CATEGORIES:
|
||||
result['filters'][category['type_id']] = [SORT_OPTIONS]
|
||||
if tags.get('data'):
|
||||
main_tag = tags['data'][0]
|
||||
result['class'].append({
|
||||
'type_name': '发现',
|
||||
'type_id': f'{main_tag["id"]}_tag'
|
||||
})
|
||||
tag_values = [
|
||||
{'n': tag['name'], 'v': f"{tag['id']}_tag"}
|
||||
for tag in tags['data'][1:]
|
||||
if tag.get('id')
|
||||
]
|
||||
result['filters'][f'{main_tag["id"]}_tag'] = [
|
||||
{'key': 'tagtype', 'name': 'tagtype', 'value': tag_values},
|
||||
SORT_OPTIONS
|
||||
]
|
||||
|
||||
region_filter = {
|
||||
'key': 'region_ids',
|
||||
'name': 'region_ids',
|
||||
'value': [
|
||||
{'n': region['name'], 'v': region['id']}
|
||||
for region in regions['data'][1:]
|
||||
if region.get('id')
|
||||
]
|
||||
}
|
||||
self.aid=regions['data'][0]['id']
|
||||
result['filters']['actor'].append({
|
||||
'key': 'region_id',
|
||||
'name': 'region_id',
|
||||
'value': region_filter['value'][:2]
|
||||
})
|
||||
complex_sort = {
|
||||
'key': 'sortby',
|
||||
'name': 'sortby',
|
||||
'value': [
|
||||
{'n': '综合', 'v': 'complex'},
|
||||
*SORT_OPTIONS['value']
|
||||
]
|
||||
}
|
||||
producer_filters = [region_filter, complex_sort]
|
||||
for producer in producers['data']:
|
||||
result['class'].append({
|
||||
'type_name': producer['name'],
|
||||
'type_id': f'{producer["id"]}_sx'
|
||||
})
|
||||
result['filters'][f'{producer["id"]}_sx'] = producer_filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data=self.getdata('/api/v1/video?current=1&pageSize=60®ion_ids=&sortby=complex')
|
||||
return {'list':self.getlist(data)}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
if 'act' in tid:
|
||||
data=self.getact(tid, pg, filter, extend)
|
||||
elif 'tag' in tid:
|
||||
data=self.gettag(tid, pg, filter, extend)
|
||||
elif 'sx' in tid:
|
||||
data=self.getsx(tid, pg, filter, extend)
|
||||
elif 'make' in tid:
|
||||
data=self.getmake(tid, pg, filter, extend)
|
||||
result = {}
|
||||
result['list'] = data
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
v=self.getdata(f'/api/v1/video?current=1&pageSize=1&id={ids[0]}&detail=1')
|
||||
v=v['data'][0]
|
||||
vod = {
|
||||
'vod_name': v.get('title'),
|
||||
'type_name': '/'.join(v.get('tag_names',[])),
|
||||
'vod_play_from': '浴火社',
|
||||
'vod_play_url': ''
|
||||
}
|
||||
p=[]
|
||||
for i,j in enumerate(self.bhost):
|
||||
p.append(f'{self.names[i]}${j}{v.get("highres_url") or v.get("preview_url")}@@@{v["id"]}')
|
||||
vod['vod_play_url'] = '#'.join(p)
|
||||
return {'list':[vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
data=self.getdata(f'/api/v1/video?current={pg}&pageSize=30&title={key}')
|
||||
return {'list':self.getlist(data),'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
url=f'{self.getProxyUrl()}&url={self.e64(id)}&type=m3u8'
|
||||
return {'parse': 0, 'url': url, 'header': self.headers}
|
||||
|
||||
def localProxy(self, param):
|
||||
if param.get('type')=='image':
|
||||
data=self.fetch(param.get('url'), headers=self.headers).text
|
||||
content=b64decode(data.encode('utf-8'))
|
||||
return [200, 'image/png', content]
|
||||
if param.get('type')=='m3u8':
|
||||
ids=self.d64(param.get('url')).split('@@@')
|
||||
data=self.fetch(ids[0], headers=self.headers).text
|
||||
lines = data.strip().split('\n')
|
||||
for index, string in enumerate(lines):
|
||||
if 'URI=' in string:
|
||||
replacement = f'URI="{self.getProxyUrl()}&id={ids[1]}&type=mkey"'
|
||||
lines[index]=re.sub(r'URI="[^"]+"', replacement, string)
|
||||
continue
|
||||
if '#EXT' not in string and 'http' not in string:
|
||||
last_slash_index = ids[0].rfind('/')
|
||||
lpath = ids[0][:last_slash_index + 1]
|
||||
lines[index] = f'{lpath}{string}'
|
||||
data = '\n'.join(lines)
|
||||
return [200, 'audio/x-mpegurl', data]
|
||||
if param.get('type')=='mkey':
|
||||
id=param.get('id')
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36',
|
||||
'authdog': self.token
|
||||
}
|
||||
response = self.fetch(f'{self.host}/api/v1/video/key/{id}', headers=headers)
|
||||
type=response.headers.get('Content-Type')
|
||||
return [200, type, response.content]
|
||||
|
||||
def e64(self, text):
|
||||
try:
|
||||
text_bytes = text.encode('utf-8')
|
||||
encoded_bytes = b64encode(text_bytes)
|
||||
return encoded_bytes.decode('utf-8')
|
||||
except Exception as e:
|
||||
print(f"Base64编码错误: {str(e)}")
|
||||
return ""
|
||||
|
||||
def d64(self,encoded_text):
|
||||
try:
|
||||
encoded_bytes = encoded_text.encode('utf-8')
|
||||
decoded_bytes = b64decode(encoded_bytes)
|
||||
return decoded_bytes.decode('utf-8')
|
||||
except Exception as e:
|
||||
print(f"Base64解码错误: {str(e)}")
|
||||
return ""
|
||||
|
||||
def getdid(self):
|
||||
did = self.md5(str(int(time.time() * 1000)))
|
||||
try:
|
||||
if self.getCache('did'):
|
||||
return self.getCache('did')
|
||||
else:
|
||||
self.setCache('did', did)
|
||||
return did
|
||||
except Exception as e:
|
||||
self.setCache('did', did)
|
||||
return did
|
||||
|
||||
def host_late(self, url_list):
|
||||
if isinstance(url_list, str):
|
||||
urls = [u.strip() for u in url_list.split(',')]
|
||||
else:
|
||||
urls = url_list
|
||||
if len(urls) <= 1:
|
||||
return urls[0] if urls else ''
|
||||
results = {}
|
||||
threads = []
|
||||
|
||||
def test_host(url):
|
||||
try:
|
||||
start_time = time.time()
|
||||
response = requests.head(url, timeout=1.0, allow_redirects=False)
|
||||
delay = (time.time() - start_time) * 1000
|
||||
results[url] = delay
|
||||
except Exception as e:
|
||||
results[url] = float('inf')
|
||||
|
||||
for url in urls:
|
||||
t = threading.Thread(target=test_host, args=(url,))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
return min(results.items(), key=lambda x: x[1])[0]
|
||||
|
||||
def domain(self):
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36',
|
||||
}
|
||||
response = self.fetch(f'{self.host}/api/v1/system/domain', headers=headers)
|
||||
return self.aes(response.content)
|
||||
|
||||
def aes(self, word):
|
||||
key = b64decode("amtvaWc5ZnJ2Ym5taml1eQ==")
|
||||
iv = b64decode("AAEFAwQFCQcICQoLDA0ODw==")
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted = unpad(cipher.decrypt(word), AES.block_size)
|
||||
return json.loads(decrypted.decode('utf-8'))
|
||||
|
||||
def md5(self, text):
|
||||
h = MD5.new()
|
||||
h.update(text.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
|
||||
def gettoken(self):
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36',
|
||||
'cookei': self.md5(f'{self.did}+android'),
|
||||
'siteid': '11',
|
||||
'siteauthority': 'lls888.tv'
|
||||
}
|
||||
|
||||
json_data = {
|
||||
'app_id': 'jukjoe.zqgpi.hfzvde.sdot',
|
||||
'phone_device': 'Redmi M2012K10C',
|
||||
'device_id': self.did,
|
||||
'device_type': 'android',
|
||||
'invite_code': 'oi1o',
|
||||
'is_first': 1,
|
||||
'os_version': '11',
|
||||
'version': '8.59',
|
||||
}
|
||||
response = self.post(f'{self.host}/api/v1/member/device', headers=headers, json=json_data)
|
||||
tdata = self.aes(response.content)
|
||||
return f'{tdata["token_type"]} {tdata["access_token"]}'
|
||||
|
||||
def getdata(self, path):
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 11; M2012K10C Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36',
|
||||
'authdog': self.token
|
||||
}
|
||||
response = self.fetch(f'{self.host}{path}', headers=headers)
|
||||
return self.aes(response.content)
|
||||
|
||||
def getimg(self, path):
|
||||
if not path.startswith('/'):
|
||||
path = f'/{path}'
|
||||
return f'{self.getProxyUrl()}&url={self.phost}{path}&type=image'
|
||||
|
||||
def getlist(self,data):
|
||||
videos = []
|
||||
for i in data['data']:
|
||||
videos.append({
|
||||
'vod_id': i['id'],
|
||||
'vod_name': i['title'],
|
||||
'vod_pic': self.getimg(i.get('coverphoto_h' or i.get('coverphoto_v'))),
|
||||
'style': {"type": "rect", "ratio": 1.33}})
|
||||
return videos
|
||||
|
||||
def geticon(self, data, st='',style=None):
|
||||
if style is None:style = {"type": "oval"}
|
||||
videos = []
|
||||
for i in data['data']:
|
||||
videos.append({
|
||||
'vod_id': f'{i["id"]}{st}',
|
||||
'vod_name': i['name'],
|
||||
'vod_pic': self.getimg(i.get('icon_path')),
|
||||
'vod_tag': 'folder',
|
||||
'style': style})
|
||||
return videos
|
||||
|
||||
def getact(self, tid, pg, filter, extend):
|
||||
if tid == 'actor' and pg=='1':
|
||||
data = self.getdata(f'/api/v1/video/actor?current=1&pageSize=999®ion_id={extend.get("region_id",self.aid)}&discover_page={pg}')
|
||||
return self.geticon(data, '_act')
|
||||
elif '_act' in tid:
|
||||
data = self.getdata(f'/api/v1/video?current={pg}&pageSize=50&actor_ids={tid.split("_")[0]}&sortby={extend.get("sortby","on_shelf_at")}')
|
||||
return self.getlist(data)
|
||||
|
||||
def gettag(self, tid, pg, filter, extend):
|
||||
if '_tag' in tid:
|
||||
tid=extend.get('tagtype',tid)
|
||||
data=self.getdata(f'/api/v1/video/tag?current={pg}&pageSize=100&level=2&parent_id={tid.split("_")[0]}')
|
||||
return self.geticon(data, '_stag',{"type": "rect", "ratio": 1.33})
|
||||
elif '_stag' in tid:
|
||||
data = self.getdata(f'/api/v1/video?current={pg}&pageSize=50&tag_ids={tid.split("_")[0]}&sortby={extend.get("sortby","on_shelf_at")}')
|
||||
return self.getlist(data)
|
||||
|
||||
def getsx(self, tid, pg, filter, extend):
|
||||
data=self.getdata(f'/api/v1/video?current={pg}&pageSize=20&producer_ids={tid.split("_")[0]}®ion_ids={extend.get("region_ids","")}&sortby={extend.get("sortby","complex")}')
|
||||
return self.getlist(data)
|
||||
|
||||
def getmake(self, tid, pg, filter, extend):
|
||||
if pg=='1':
|
||||
data=self.getdata('/api/v1/video/producer?current=1&pageSize=100&status=1')
|
||||
return self.geticon(data, '_sx',{"type": "rect", "ratio": 1.33})
|
||||
|
256
py/py_爱.py
Normal file
256
py/py_爱.py
Normal file
@ -0,0 +1,256 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import random
|
||||
import sys
|
||||
from base64 import b64encode, b64decode
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from pprint import pprint
|
||||
from urllib.parse import urlencode
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.did = self.random_str(32)
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
rhost = 'https://www.iqiyi.com'
|
||||
|
||||
hhost='https://mesh.if.iqiyi.com'
|
||||
|
||||
dhost='https://miniapp.iqiyi.com'
|
||||
|
||||
headers = {
|
||||
'Origin': rhost,
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36',
|
||||
'Referer': f'{rhost}/',
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"全部": "1009",
|
||||
"电影": "1",
|
||||
"剧集": "2",
|
||||
"综艺": "6",
|
||||
"动漫": "4",
|
||||
"儿童": "15",
|
||||
"微剧": "35",
|
||||
"纪录片": "3"
|
||||
}
|
||||
classes = []
|
||||
filters = {}
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
with ThreadPoolExecutor(max_workers=len(classes)) as executor:
|
||||
results = executor.map(self.getf, classes)
|
||||
for id, ft in results:
|
||||
if len(ft):filters[id] = ft
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data=self.fetch(f'{self.hhost}/portal/lw/v5/channel/recommend?v=13.014.21150', headers=self.headers).json()
|
||||
vlist = []
|
||||
for i in data['items']:
|
||||
for j in i['video'][0]['data']:
|
||||
id = j.get('firstId')
|
||||
if id:
|
||||
pu=j.get('prevue',{}).get('page_url') or j.get('page_url').split('?')[0]
|
||||
id = f'{id}@{self.e64(pu)}'
|
||||
vlist.append({
|
||||
'vod_id': id,
|
||||
'vod_name': j.get('display_name'),
|
||||
'vod_pic': j.get('prevue',{}).get('image_url'),
|
||||
'vod_year': j.get('sns_score'),
|
||||
'vod_remarks': j.get('dq_updatestatus') or j.get('rank_prefix')
|
||||
})
|
||||
return {'list':vlist}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
if pg == "1":
|
||||
self.sid = ''
|
||||
new_data = {'mode':'24'}
|
||||
for key, value in extend.items():
|
||||
if value:
|
||||
key_value_pairs = self.d64(value).split(',')
|
||||
for pair in key_value_pairs:
|
||||
k, v = pair.split('=')
|
||||
if k in new_data:
|
||||
new_data[k] += "," + v
|
||||
else:
|
||||
new_data[k] = v
|
||||
path=f'/portal/lw/videolib/data?uid=&passport_id=&ret_num=60&version=13.014.21150&device_id={self.did}&channel_id={tid}&page_id={pg}&session={self.sid}&os=&conduit_id=&vip=0&auth&recent_selected_tag=&ad=%5B%7B%22lm%22:%225%22,%22ai%22:%225%22,%22fp%22:%226%22,%22sei%22:%22Sa867aa9d326e2bd8654d8c2a8636055e%22,%22position%22:%22library%22%7D%5D&adExt=%7B%22r%22:%221.2.1-ares6-pure%22%7D&dfp=a12f96215b2f7842a98c082799ca0c3d9236be00946701b106829754d8ece3aaf8&filter={urlencode(new_data)}'
|
||||
data=self.fetch(f'{self.hhost}{path}', headers=self.headers).json()
|
||||
self.sid = data['session']
|
||||
videos = []
|
||||
for i in data['data']:
|
||||
id = i.get('firstId') or i.get('tv_id')
|
||||
if not id:
|
||||
id=i.get('play_url').split(';')[0].split('=')[-1]
|
||||
if id and not i.get('h'):
|
||||
id=f'{id}@{self.e64(i.get("page_url"))}'
|
||||
videos.append({
|
||||
'vod_id': id,
|
||||
'vod_name': i.get('display_name'),
|
||||
'vod_pic': i.get('album_image_url_hover'),
|
||||
'vod_year': i.get('sns_score'),
|
||||
'vod_remarks': i.get('dq_updatestatus') or i.get('pay_mark')
|
||||
})
|
||||
result = {}
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
ids = ids[0].split('@')
|
||||
ids[-1] = self.d64(ids[-1])
|
||||
data = self.fetch(f'{self.dhost}/h5/mina/baidu/play/body/v1/{ids[0]}/', headers=self.headers).json()
|
||||
# t=str(int(time.time()*1000))
|
||||
# e = 'ad_ext={"r":"1.2.1-ares6-pure"}&ad_param=[{"azt":"730","azd":"1000000000942","lm":1,"position":"related"},{"azt":"731","azd":"1000000000943","lm":1,"position":"recommend"},{"azt":"734","azd":"1000000000910","lm":1,"position":"middlecard"},{"azt":"738","azd":"1000000000911","lm":1,"position":"bottomcard"},{"azt":"612","azd":"1000000000695","lm":2,"position":"recommend_full"},{"azt":"","azd":"1000000000912","lm":1,"position":"rcd_image"}]&app_mode=standard&app_version=13.014.21150&auth_cookie=&conduit_id=&device_id='+self.did+'&entity_id='+ids[0]+'&entity_type=1&filter=&ext=&os=&src=pca_tvg×tamp=' + t + '&user_id=0&vip_status=0&vip_type=-1&secret_key=howcuteitis'
|
||||
# sign=self.md5(e).upper()
|
||||
# path=f'/tvg/v2/lw/base_info?entity_id={ids[0]}&device_id={self.did}&auth_cookie&user_id=0&vip_type=-1&vip_status=0&conduit_id&app_version=13.014.21150&ext&app_mode=standard×tamp={t}&src=pca_tvg&os&ad_param=%5B%7B%22azt%22:%22730%22,%22azd%22:%221000000000942%22,%22lm%22:1,%22position%22:%22related%22%7D,%7B%22azt%22:%22731%22,%22azd%22:%221000000000943%22,%22lm%22:1,%22position%22:%22recommend%22%7D,%7B%22azt%22:%22734%22,%22azd%22:%221000000000910%22,%22lm%22:1,%22position%22:%22middlecard%22%7D,%7B%22azt%22:%22738%22,%22azd%22:%221000000000911%22,%22lm%22:1,%22position%22:%22bottomcard%22%7D,%7B%22azt%22:%22612%22,%22azd%22:%221000000000695%22,%22lm%22:2,%22position%22:%22recommend_full%22%7D,%7B%22azt%22:%22%22,%22azd%22:%221000000000912%22,%22lm%22:1,%22position%22:%22rcd_image%22%7D%5D&ad_ext=%7B%22r%22:%221.2.1-ares6-pure%22%7D&sign={sign}'
|
||||
# vdata=self.fetch(f'{self.hhost}{path}', headers=self.headers).json()
|
||||
# print(vdata)
|
||||
v=data['data']['playInfo']
|
||||
vod = {
|
||||
'vod_name': v.get('albumName'),
|
||||
'type_name': v.get('tags'),
|
||||
'vod_year': v.get('albumYear'),
|
||||
'vod_remarks': v.get('updateStrategy'),
|
||||
'vod_actor': v.get('mainActors'),
|
||||
'vod_director': v.get('directors'),
|
||||
'vod_content': v.get('albumDesc'),
|
||||
'vod_play_from': '爱奇艺',
|
||||
'vod_play_url': ''
|
||||
}
|
||||
if data.get('data') and data['data'].get('videoList') and data['data']['videoList'].get('videos'):
|
||||
purl=[f'{i["shortTitle"]}${i["pageUrl"]}' for i in data['data']['videoList']['videos']]
|
||||
pg=data['data']['videoList'].get('totalPages')
|
||||
if pg and pg > 1:
|
||||
id = v['albumId']
|
||||
pages = list(range(2, pg + 1))
|
||||
page_results = {}
|
||||
with ThreadPoolExecutor(max_workers=10) as executor:
|
||||
future_to_page = {
|
||||
executor.submit(self.fetch_page_data, page, id): page
|
||||
for page in pages
|
||||
}
|
||||
for future in as_completed(future_to_page):
|
||||
page = future_to_page[future]
|
||||
try:
|
||||
result = future.result()
|
||||
page_results[page] = result
|
||||
except Exception as e:
|
||||
print(f"Error fetching page {page}: {e}")
|
||||
for page in sorted(page_results.keys()):
|
||||
purl.extend(page_results[page])
|
||||
vod['vod_play_url'] = '#'.join(purl)
|
||||
else:
|
||||
vdata=self.fetch(f'{self.dhost}/h5/mina/baidu/play/head/v1/{ids[0]}/', headers=self.headers).json()
|
||||
v=vdata['data']['playInfo']
|
||||
vod = {
|
||||
'vod_name': v.get('shortTitle'),
|
||||
'type_name': v.get('channelName'),
|
||||
'vod_year': v.get('year'),
|
||||
'vod_remarks': v.get('focus'),
|
||||
'vod_actor': v.get('mainActors'),
|
||||
'vod_director': v.get('directors'),
|
||||
'vod_content': v.get('desc'),
|
||||
'vod_play_from': '爱奇艺',
|
||||
'vod_play_url': f'{v.get("shortTitle")}${ids[-1]}'
|
||||
}
|
||||
return {'list':[vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
data=self.fetch(f'{self.hhost}/portal/lw/search/homePageV3?key={key}¤t_page={pg}&mode=1&source=input&suggest=&version=13.014.21150&pageNum={pg}&pageSize=25&pu=&u={self.did}&scale=150&token=&userVip=0&conduit=&vipType=-1&os=&osShortName=win10&dataType=&appMode=', headers=self.headers).json()
|
||||
videos = []
|
||||
vdata=data['data']['templates']
|
||||
for i in data['data']['templates']:
|
||||
if i.get('intentAlbumInfos'):
|
||||
vdata=[{'albumInfo': c} for c in i['intentAlbumInfos']]+vdata
|
||||
|
||||
for i in vdata:
|
||||
if i.get('albumInfo') and (i['albumInfo'].get('playQipuId','') or i['albumInfo'].get('qipuId')) and i['albumInfo'].get('pageUrl'):
|
||||
b=i['albumInfo']
|
||||
id=f"{(b.get('playQipuId','') or b.get('qipuId'))}@{self.e64(b.get('pageUrl'))}"
|
||||
videos.append({
|
||||
'vod_id': id,
|
||||
'vod_name': b.get('title'),
|
||||
'vod_pic': b.get('img'),
|
||||
'vod_year': (b.get('year',{}) or {}).get('value'),
|
||||
'vod_remarks': b.get('subscriptContent') or b.get('channel') or b.get('vipTips')
|
||||
})
|
||||
return {'list':videos,'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
return {'parse': 1, 'url': id, 'header': ''}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def fetch_page_data(self, page, id):
|
||||
try:
|
||||
url = f'{self.dhost}/h5/mina/avlist/{page}/{id}/'
|
||||
data = self.fetch(url, headers=self.headers).json()
|
||||
return [f'{i["shortTitle"]}${i["pageUrl"]}' for i in data['data']['videoList']['videos']]
|
||||
except:
|
||||
return []
|
||||
|
||||
def getf(self,body):
|
||||
data=self.fetch(f'{self.hhost}/portal/lw/videolib/tag?channel_id={body["type_id"]}&tagAdd=&selected_tag_name=&version=13.014.21150&device={self.did}&uid=', headers=self.headers).json()
|
||||
ft = []
|
||||
# for i in data[:-1]:
|
||||
for i in data:
|
||||
try:
|
||||
value_array = [{"n": value['text'], "v": self.e64(value['tag_param'])} for value in i['tags'] if
|
||||
value.get('tag_param')]
|
||||
ft.append({"key": i['group'], "name": i['group'], "value": value_array})
|
||||
except:
|
||||
print(i)
|
||||
return (body['type_id'], ft)
|
||||
|
||||
def e64(self, text):
|
||||
try:
|
||||
text_bytes = text.encode('utf-8')
|
||||
encoded_bytes = b64encode(text_bytes)
|
||||
return encoded_bytes.decode('utf-8')
|
||||
except Exception as e:
|
||||
print(f"Base64编码错误: {str(e)}")
|
||||
return ""
|
||||
|
||||
def d64(self,encoded_text: str):
|
||||
try:
|
||||
encoded_bytes = encoded_text.encode('utf-8')
|
||||
decoded_bytes = b64decode(encoded_bytes)
|
||||
return decoded_bytes.decode('utf-8')
|
||||
except Exception as e:
|
||||
print(f"Base64解码错误: {str(e)}")
|
||||
return ""
|
||||
|
||||
def random_str(self,length=16):
|
||||
hex_chars = '0123456789abcdef'
|
||||
return ''.join(random.choice(hex_chars) for _ in range(length))
|
216
py/py_胖虎.py
Normal file
216
py/py_胖虎.py
Normal file
@ -0,0 +1,216 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
from Cryptodome.Cipher import AES
|
||||
from Cryptodome.Util.Padding import pad, unpad
|
||||
from base64 import b64encode, b64decode
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "py_胖虎"
|
||||
|
||||
def init(self, extend=""):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def aes(self, operation, text):
|
||||
key = "ihIwTbt2YAe9TGea".encode('utf-8')
|
||||
iv = key
|
||||
|
||||
if operation == 'encrypt':
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
ct_bytes = cipher.encrypt(pad(text.encode('utf-8'), AES.block_size))
|
||||
ct = b64encode(ct_bytes).decode('utf-8')
|
||||
return ct
|
||||
elif operation == 'decrypt':
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
|
||||
return pt.decode('utf-8')
|
||||
|
||||
host = "http://sm.physkan.top:3389"
|
||||
t = str(int(time.time()))
|
||||
|
||||
def homeContent(self, filter):
|
||||
self.header = {
|
||||
'User-Agent': 'okhttp/3.14.9',
|
||||
'app-version-code': '402',
|
||||
'app-ui-mode': 'light',
|
||||
'app-user-device-id': '25f869d32598d3d3089a929453dff0bb7',
|
||||
'app-api-verify-time': self.t,
|
||||
'app-api-verify-sign': self.aes('encrypt', self.t),
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
}
|
||||
data = self.fetch("{0}/api.php/getappapi.index/initV119".format(self.host), headers=self.header).content.decode(
|
||||
'utf-8')
|
||||
data1 = json.loads(data)['data']
|
||||
print(data1)
|
||||
data2 = self.aes('decrypt', data1)
|
||||
dy = {
|
||||
"class": "类型",
|
||||
"area": "地区",
|
||||
"lang": "语言",
|
||||
"year": "年份",
|
||||
"letter": "字母",
|
||||
"by": "排序",
|
||||
"sort": "排序"
|
||||
}
|
||||
|
||||
filter = {}
|
||||
classes = []
|
||||
json_data = json.loads(data2)['type_list']
|
||||
self.homedata = json.loads(data2)['banner_list']
|
||||
|
||||
for item in json_data:
|
||||
if item['type_name'] == '全部':
|
||||
continue
|
||||
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = json.loads(item['type_extend'])
|
||||
jsontype_extend["sort"] = "最新,最热,最赞"
|
||||
|
||||
classes.append({
|
||||
"type_name": item['type_name'],
|
||||
"type_id": item['type_id']
|
||||
})
|
||||
|
||||
for key in dy:
|
||||
if key in jsontype_extend and jsontype_extend[key].strip() != "":
|
||||
has_non_empty_field = True
|
||||
break
|
||||
|
||||
if has_non_empty_field:
|
||||
filter[str(item['type_id'])] = []
|
||||
|
||||
for dkey in jsontype_extend:
|
||||
if dkey in dy and jsontype_extend[dkey].strip() != "":
|
||||
values = jsontype_extend[dkey].split(',')
|
||||
value_array = [
|
||||
{"n": value.strip(), "v": value.strip()}
|
||||
for value in values if value.strip() != ''
|
||||
]
|
||||
|
||||
filter[str(item['type_id'])].append({
|
||||
"key": dkey,
|
||||
"name": dy[dkey],
|
||||
"value": value_array
|
||||
})
|
||||
result = {}
|
||||
result['class'] = classes
|
||||
result['filter'] = filter
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {
|
||||
'list': self.homedata
|
||||
}
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
body = f"area={extend.get('area', '全部')}&year={extend.get('year', '全部')}&type_id={tid}&page={pg}&sort={extend.get('sort', '最新')}&lang={extend.get('lang', '全部')}&class={extend.get('class', '全部')}"
|
||||
result = {}
|
||||
url = '{0}/api.php/getappapi.index/typeFilterVodList'.format(self.host)
|
||||
data = self.post(url, headers=self.header, data=body).content.decode('utf-8')
|
||||
data1 = json.loads(data)['data']
|
||||
data2 = self.aes('decrypt', data1)
|
||||
result['list'] = json.loads(data2)['recommend_list']
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
body = f"vod_id={ids[0]}"
|
||||
print(body)
|
||||
url = '{0}/api.php/getappapi.index/vodDetail'.format(self.host)
|
||||
data = self.post(url, headers=self.header, data=body).content.decode('utf-8')
|
||||
data1 = json.loads(data)['data']
|
||||
data2 = json.loads(self.aes('decrypt', data1))
|
||||
print(data2)
|
||||
vod = data2['vod']
|
||||
print(vod)
|
||||
play = []
|
||||
names = []
|
||||
for itt in data2['vod_play_list']:
|
||||
a = []
|
||||
names.append(itt['player_info']['show'])
|
||||
parse = itt['player_info']['parse']
|
||||
for it in itt['urls']:
|
||||
if re.search(r'mp4|m3u8', it['url']):
|
||||
a.append(f"{it['name']}${it['url']}")
|
||||
elif re.search(r'www.yemu.xyz', it['parse_api_url']):
|
||||
a.append(f"{it['name']}${it['parse_api_url']}")
|
||||
else:
|
||||
a.append(
|
||||
f"{it['name']}${'parse_api=' + parse + '&url=' + self.aes('encrypt', it['url']) + '&token=' + it['token']}")
|
||||
play.append('#'.join(a))
|
||||
vod['vod_play_from'] = '$$$'.join(names)
|
||||
vod['vod_play_url'] = '$$$'.join(play)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg='1'):
|
||||
body = f"keywords={key}&type_id=0&page={pg}"
|
||||
url = '{0}/api.php/getappapi.index/searchList'.format(self.host)
|
||||
data = self.post(url, headers=self.header, data=body).content.decode('utf-8')
|
||||
data1 = json.loads(data)['data']
|
||||
data2 = self.aes('decrypt', data1)
|
||||
result = {
|
||||
'list': json.loads(data2)['search_list']
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
def edu(str):
|
||||
def replacer(match):
|
||||
from urllib.parse import quote_plus
|
||||
return match.group(1) + quote_plus(match.group(2)) + match.group(3)
|
||||
|
||||
return re.sub(r'(url=)(.*?)(&token)', replacer, str)
|
||||
|
||||
url = id
|
||||
parse = 0
|
||||
if 'm3u8' not in url and 'mp4' not in url:
|
||||
try:
|
||||
body = edu(url)
|
||||
print(body)
|
||||
data = self.post('{0}/api.php/getappapi.index/vodParse'.format(self.host), headers=self.header,
|
||||
data=body).content.decode('utf-8')
|
||||
data1 = json.loads(data)['data']
|
||||
data2 = json.loads(self.aes('decrypt', data1))['json']
|
||||
url = json.loads(data2)['url']
|
||||
except:
|
||||
url = id
|
||||
parse = 1
|
||||
if not id.startswith('https://www.yemu.xyz'):
|
||||
url = 'https://www.yemu.xyz/?url={0}'.format(id)
|
||||
result = {}
|
||||
print(url)
|
||||
headers = self.header.copy()
|
||||
del headers['Content-type']
|
||||
result["parse"] = parse
|
||||
result["url"] = url
|
||||
result["header"] = headers
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
366
py/py_腾.py
Normal file
366
py/py_腾.py
Normal file
@ -0,0 +1,366 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import json
|
||||
import sys
|
||||
import uuid
|
||||
import copy
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
from pyquery import PyQuery as pq
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.dbody = {
|
||||
"page_params": {
|
||||
"channel_id": "",
|
||||
"filter_params": "sort=75",
|
||||
"page_type": "channel_operation",
|
||||
"page_id": "channel_list_second_page"
|
||||
}
|
||||
}
|
||||
self.body = self.dbody
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host = 'https://v.qq.com'
|
||||
|
||||
apihost = 'https://pbaccess.video.qq.com'
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5410.0 Safari/537.36',
|
||||
'origin': host,
|
||||
'referer': f'{host}/'
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
cdata = {
|
||||
"电视剧": "100113",
|
||||
"电影": "100173",
|
||||
"综艺": "100109",
|
||||
"纪录片": "100105",
|
||||
"动漫": "100119",
|
||||
"少儿": "100150",
|
||||
"短剧": "110755"
|
||||
}
|
||||
result = {}
|
||||
classes = []
|
||||
filters = {}
|
||||
for k in cdata:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cdata[k]
|
||||
})
|
||||
with ThreadPoolExecutor(max_workers=len(classes)) as executor:
|
||||
futures = [executor.submit(self.get_filter_data, item['type_id']) for item in classes]
|
||||
for future in futures:
|
||||
cid, data = future.result()
|
||||
if not data.get('data', {}).get('module_list_datas'):
|
||||
continue
|
||||
filter_dict = {}
|
||||
try:
|
||||
items = data['data']['module_list_datas'][-1]['module_datas'][-1]['item_data_lists']['item_datas']
|
||||
for item in items:
|
||||
if not item.get('item_params', {}).get('index_item_key'):
|
||||
continue
|
||||
params = item['item_params']
|
||||
filter_key = params['index_item_key']
|
||||
if filter_key not in filter_dict:
|
||||
filter_dict[filter_key] = {
|
||||
'key': filter_key,
|
||||
'name': params['index_name'],
|
||||
'value': []
|
||||
}
|
||||
filter_dict[filter_key]['value'].append({
|
||||
'n': params['option_name'],
|
||||
'v': params['option_value']
|
||||
})
|
||||
except (IndexError, KeyError):
|
||||
continue
|
||||
filters[cid] = list(filter_dict.values())
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
vlist = []
|
||||
data = self.gethtml(self.host)
|
||||
its = data('script')
|
||||
s = None
|
||||
for it in its.items():
|
||||
if 'window.__INITIAL_STATE__' in it.text():
|
||||
s = it.text()
|
||||
break
|
||||
if s:
|
||||
index = s.find('=')
|
||||
if index != -1:
|
||||
sd = json.loads(s[index + 1:])
|
||||
if sd.get('storeModulesData', {}).get('channelsModulesMap', {}).get('choice', {}).get('cardListData'):
|
||||
for its in sd['storeModulesData']['channelsModulesMap']['choice']['cardListData']:
|
||||
if its and its.get('children_list', {}).get('list', {}).get('cards'):
|
||||
for it in its['children_list']['list']['cards']:
|
||||
if it and it.get('params'):
|
||||
p = it['params']
|
||||
tag = json.loads(p.get('uni_imgtag', '{}') or p.get('imgtag', '{}') or '{}')
|
||||
id = it.get('id') or p.get('cid')
|
||||
name = p.get('mz_title') or p.get('title')
|
||||
if name and 'http' not in id:
|
||||
vlist.append({
|
||||
'vod_id': id,
|
||||
'vod_name': name,
|
||||
'vod_pic': p.get('image_url'),
|
||||
'vod_year': tag.get('tag_2', {}).get('text'),
|
||||
'vod_remarks': tag.get('tag_4', {}).get('text')
|
||||
})
|
||||
return {'list': vlist}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
result = {}
|
||||
params = {
|
||||
"sort": extend.get('sort', '75'),
|
||||
"attr": extend.get('attr', '-1'),
|
||||
"itype": extend.get('itype', '-1'),
|
||||
"ipay": extend.get('ipay', '-1'),
|
||||
"iarea": extend.get('iarea', '-1'),
|
||||
"iyear": extend.get('iyear', '-1'),
|
||||
"theater": extend.get('theater', '-1'),
|
||||
"award": extend.get('award', '-1'),
|
||||
"recommend": extend.get('recommend', '-1')
|
||||
}
|
||||
if pg == '1':
|
||||
self.body = self.dbody.copy()
|
||||
self.body['page_params']['channel_id'] = tid
|
||||
self.body['page_params']['filter_params'] = self.josn_to_params(params)
|
||||
data = self.post(
|
||||
f'{self.apihost}/trpc.universal_backend_service.page_server_rpc.PageServer/GetPageData?video_appid=1000005&vplatform=2&vversion_name=8.9.10&new_mark_label_enabled=1',
|
||||
json=self.body, headers=self.headers).json()
|
||||
ndata = data['data']
|
||||
if ndata['has_next_page']:
|
||||
result['pagecount'] = 9999
|
||||
self.body['page_context'] = ndata['next_page_context']
|
||||
else:
|
||||
result['pagecount'] = int(pg)
|
||||
vlist = []
|
||||
for its in ndata['module_list_datas'][-1]['module_datas'][-1]['item_data_lists']['item_datas']:
|
||||
id = its.get('item_params', {}).get('cid')
|
||||
if id:
|
||||
p = its['item_params']
|
||||
tag = json.loads(p.get('uni_imgtag', '{}') or p.get('imgtag', '{}') or '{}')
|
||||
name = p.get('mz_title') or p.get('title')
|
||||
pic = p.get('new_pic_hz') or p.get('new_pic_vt')
|
||||
vlist.append({
|
||||
'vod_id': id,
|
||||
'vod_name': name,
|
||||
'vod_pic': pic,
|
||||
'vod_year': tag.get('tag_2', {}).get('text'),
|
||||
'vod_remarks': tag.get('tag_4', {}).get('text')
|
||||
})
|
||||
result['list'] = vlist
|
||||
result['page'] = pg
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
vbody = {
|
||||
"page_params": {
|
||||
"req_from": "web",
|
||||
"cid": ids[0],
|
||||
"vid": "",
|
||||
"lid": "",
|
||||
"page_type": "detail_operation",
|
||||
"page_id": "detail_page_introduction"
|
||||
},
|
||||
"has_cache": 1
|
||||
}
|
||||
|
||||
body = {
|
||||
"page_params": {
|
||||
"req_from": "web_vsite",
|
||||
"page_id": "vsite_episode_list",
|
||||
"page_type": "detail_operation",
|
||||
"id_type": "1",
|
||||
"page_size": "",
|
||||
"cid": ids[0],
|
||||
"vid": "",
|
||||
"lid": "",
|
||||
"page_num": "",
|
||||
"page_context": "",
|
||||
"detail_page_type": "1"
|
||||
},
|
||||
"has_cache": 1
|
||||
}
|
||||
|
||||
with ThreadPoolExecutor(max_workers=2) as executor:
|
||||
future_detail = executor.submit(self.get_vdata, vbody)
|
||||
future_episodes = executor.submit(self.get_vdata, body)
|
||||
vdata = future_detail.result()
|
||||
data = future_episodes.result()
|
||||
|
||||
pdata = self.process_tabs(data, body, ids)
|
||||
if not pdata:
|
||||
return self.handle_exception(None, "No pdata available")
|
||||
|
||||
try:
|
||||
star_list = vdata['data']['module_list_datas'][0]['module_datas'][0]['item_data_lists']['item_datas'][
|
||||
0].get('sub_items', {}).get('star_list', {}).get('item_datas', [])
|
||||
actors = [star['item_params']['name'] for star in star_list]
|
||||
names = ['腾讯视频', '预告片']
|
||||
plist, ylist = self.process_pdata(pdata, ids)
|
||||
if not plist:
|
||||
del names[0]
|
||||
if not ylist:
|
||||
del names[1]
|
||||
vod = self.build_vod(vdata, actors, plist, ylist, names)
|
||||
return {'list': [vod]}
|
||||
except Exception as e:
|
||||
return self.handle_exception(e, "Error processing detail")
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
body = {"version": "24072901", "clientType": 1, "filterValue": "", "uuid": str(uuid.uuid4()), "retry": 0,
|
||||
"query": key, "pagenum": int(pg) - 1, "pagesize": 30, "queryFrom": 0, "searchDatakey": "",
|
||||
"transInfo": "", "isneedQc": True, "preQid": "", "adClientInfo": "",
|
||||
"extraInfo": {"isNewMarkLabel": "1", "multi_terminal_pc": "1"}}
|
||||
data = self.post(f'{self.apihost}/trpc.videosearch.mobile_search.MultiTerminalSearch/MbSearch?vplatform=2',
|
||||
json=body, headers=self.headers).json()
|
||||
vlist = []
|
||||
for k in data['data']['areaBoxList'][-1]['itemList']:
|
||||
if k.get('doc', {}).get('id'):
|
||||
img_tag = k.get('videoInfo', {}).get('imgTag')
|
||||
if img_tag is not None and isinstance(img_tag, str):
|
||||
try:
|
||||
tag = json.loads(img_tag)
|
||||
except json.JSONDecodeError as e:
|
||||
tag = {}
|
||||
else:
|
||||
tag = {}
|
||||
pic = k.get('videoInfo', {}).get('imgUrl')
|
||||
vlist.append({
|
||||
'vod_id': k['doc']['id'],
|
||||
'vod_name': k['videoInfo']['title'],
|
||||
'vod_pic': pic,
|
||||
'vod_year': tag.get('tag_2', {}).get('text', ''),
|
||||
'vod_remarks': tag.get('tag_4', {}).get('text', '')
|
||||
})
|
||||
return {'list': vlist, 'page': pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
ids = id.split('@')
|
||||
url = f"{self.host}/x/cover/{ids[0]}/{ids[1]}.html"
|
||||
return {'parse': 1, 'url': url, 'header': ''}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def gethtml(self, url):
|
||||
rsp = self.fetch(url, headers=self.headers)
|
||||
rsp = self.cleanText(rsp.text)
|
||||
return pq(rsp)
|
||||
|
||||
def get_filter_data(self, cid):
|
||||
hbody = self.dbody.copy()
|
||||
hbody['page_params']['channel_id'] = cid
|
||||
data = self.post(
|
||||
f'{self.apihost}/trpc.universal_backend_service.page_server_rpc.PageServer/GetPageData?video_appid=1000005&vplatform=2&vversion_name=8.9.10&new_mark_label_enabled=1',
|
||||
json=hbody, headers=self.headers).json()
|
||||
return cid, data
|
||||
|
||||
def get_vdata(self, body):
|
||||
try:
|
||||
vdata = self.post(
|
||||
f'{self.apihost}/trpc.universal_backend_service.page_server_rpc.PageServer/GetPageData?video_appid=3000010&vplatform=2&vversion_name=8.2.96',
|
||||
json=body, headers=self.headers
|
||||
).json()
|
||||
# print(body)
|
||||
return vdata
|
||||
except Exception as e:
|
||||
print(f"Error in get_vdata: {str(e)}")
|
||||
return {'data': {'module_list_datas': []}}
|
||||
|
||||
def process_pdata(self, pdata, ids):
|
||||
plist = []
|
||||
ylist = []
|
||||
for k in pdata:
|
||||
if k.get('item_id'):
|
||||
pid = f"{k['item_params']['union_title']}${ids[0]}@{k['item_id']}"
|
||||
if '预告' in k['item_params']['union_title']:
|
||||
ylist.append(pid)
|
||||
else:
|
||||
plist.append(pid)
|
||||
return plist, ylist
|
||||
|
||||
def build_vod(self, vdata, actors, plist, ylist, names):
|
||||
d = vdata['data']['module_list_datas'][0]['module_datas'][0]['item_data_lists']['item_datas'][0]['item_params']
|
||||
urls = []
|
||||
if plist:
|
||||
urls.append('#'.join(plist))
|
||||
if ylist:
|
||||
urls.append('#'.join(ylist))
|
||||
vod = {
|
||||
'type_name': d.get('sub_genre', ''),
|
||||
'vod_name': d.get('title', ''),
|
||||
'vod_year': d.get('year', ''),
|
||||
'vod_area': d.get('area_name', ''),
|
||||
'vod_remarks': d.get('holly_online_time', '') or d.get('hotval', ''),
|
||||
'vod_actor': ','.join(actors),
|
||||
'vod_content': d.get('cover_description', ''),
|
||||
'vod_play_from': '$$$'.join(names),
|
||||
'vod_play_url': '$$$'.join(urls)
|
||||
}
|
||||
return vod
|
||||
|
||||
def handle_exception(self, e, message):
|
||||
print(f"{message}: {str(e)}")
|
||||
return {'list': [{'vod_play_from': '哎呀翻车啦', 'vod_play_url': '翻车啦#555'}]}
|
||||
|
||||
def process_tabs(self, data, body, ids):
|
||||
try:
|
||||
pdata = data['data']['module_list_datas'][-1]['module_datas'][-1]['item_data_lists']['item_datas']
|
||||
tabs = data['data']['module_list_datas'][-1]['module_datas'][-1]['module_params'].get('tabs')
|
||||
if tabs and len(json.loads(tabs)):
|
||||
tabs = json.loads(tabs)
|
||||
remaining_tabs = tabs[1:]
|
||||
task_queue = []
|
||||
for tab in remaining_tabs:
|
||||
nbody = copy.deepcopy(body)
|
||||
nbody['page_params']['page_context'] = tab['page_context']
|
||||
task_queue.append(nbody)
|
||||
with ThreadPoolExecutor(max_workers=10) as executor:
|
||||
future_map = {executor.submit(self.get_vdata, task): idx for idx, task in enumerate(task_queue)}
|
||||
results = [None] * len(task_queue)
|
||||
for future in as_completed(future_map.keys()):
|
||||
idx = future_map[future]
|
||||
results[idx] = future.result()
|
||||
for result in results:
|
||||
if result:
|
||||
page_data = result['data']['module_list_datas'][-1]['module_datas'][-1]['item_data_lists'][
|
||||
'item_datas']
|
||||
pdata.extend(page_data)
|
||||
return pdata
|
||||
except Exception as e:
|
||||
print(f"Error processing episodes: {str(e)}")
|
||||
return []
|
||||
|
||||
def josn_to_params(self, params, skip_empty=False):
|
||||
query = []
|
||||
for k, v in params.items():
|
||||
if skip_empty and not v:
|
||||
continue
|
||||
query.append(f"{k}={v}")
|
||||
return "&".join(query)
|
||||
|
||||
|
207
py/py_芒.py
Normal file
207
py/py_芒.py
Normal file
@ -0,0 +1,207 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
rhost='https://www.mgtv.com'
|
||||
|
||||
host='https://pianku.api.mgtv.com'
|
||||
|
||||
vhost='https://pcweb.api.mgtv.com'
|
||||
|
||||
mhost='https://dc.bz.mgtv.com'
|
||||
|
||||
shost='https://mobileso.bz.mgtv.com'
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.61 Chrome/126.0.6478.61 Not/A)Brand/8 Safari/537.36',
|
||||
'origin': rhost,
|
||||
'referer': f'{rhost}/'
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电影": "3",
|
||||
"电视剧": "2",
|
||||
"综艺": "1",
|
||||
"动画": "50",
|
||||
"少儿": "10",
|
||||
"纪录片": "51",
|
||||
"教育": "115"
|
||||
}
|
||||
classes = []
|
||||
filters = {}
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
with ThreadPoolExecutor(max_workers=len(classes)) as executor:
|
||||
results = executor.map(self.getf, classes)
|
||||
for id, ft in results:
|
||||
if len(ft):filters[id] = ft
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data=self.fetch(f'{self.mhost}/dynamic/v1/channel/index/0/0/0/1000000/0/0/17/1354?type=17&version=5.0&t={str(int(time.time()*1000))}&_support=10000000', headers=self.headers).json()
|
||||
videoList = []
|
||||
for i in data['data']:
|
||||
if i.get('DSLList') and len(i['DSLList']):
|
||||
for j in i['DSLList']:
|
||||
if j.get('data') and j['data'].get('items') and len(j['data']['items']):
|
||||
for k in j['data']['items']:
|
||||
videoList.append({
|
||||
'vod_id': k["videoId"],
|
||||
'vod_name': k['videoName'],
|
||||
'vod_pic': k['img'],
|
||||
'vod_year': k.get('cornerTitle'),
|
||||
'vod_remarks': k.get('time') or k.get('desc'),
|
||||
})
|
||||
return {'list':videoList}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
body={
|
||||
'allowedRC': '1',
|
||||
'platform': 'pcweb',
|
||||
'channelId': tid,
|
||||
'pn': pg,
|
||||
'pc': '80',
|
||||
'hudong': '1',
|
||||
'_support': '10000000'
|
||||
}
|
||||
body.update(extend)
|
||||
data=self.fetch(f'{self.host}/rider/list/pcweb/v3', params=body, headers=self.headers).json()
|
||||
videoList = []
|
||||
for i in data['data']['hitDocs']:
|
||||
videoList.append({
|
||||
'vod_id': i["playPartId"],
|
||||
'vod_name': i['title'],
|
||||
'vod_pic': i['img'],
|
||||
'vod_year': (i.get('rightCorner',{}) or {}).get('text') or i.get('year'),
|
||||
'vod_remarks': i['updateInfo']
|
||||
})
|
||||
result = {}
|
||||
result['list'] = videoList
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
vbody={'allowedRC': '1', 'vid': ids[0], 'type': 'b', '_support': '10000000'}
|
||||
vdata=self.fetch(f'{self.vhost}/video/info', params=vbody, headers=self.headers).json()
|
||||
d=vdata['data']['info']['detail']
|
||||
vod = {
|
||||
'vod_name': vdata['data']['info']['title'],
|
||||
'type_name': d.get('kind'),
|
||||
'vod_year': d.get('releaseTime'),
|
||||
'vod_area': d.get('area'),
|
||||
'vod_lang': d.get('language'),
|
||||
'vod_remarks': d.get('updateInfo'),
|
||||
'vod_actor': d.get('leader'),
|
||||
'vod_director': d.get('director'),
|
||||
'vod_content': d.get('story'),
|
||||
'vod_play_from': '芒果TV',
|
||||
'vod_play_url': ''
|
||||
}
|
||||
data,pdata=self.fetch_page_data('1', ids[0],True)
|
||||
pagecount=data['data'].get('total_page') or 1
|
||||
if int(pagecount)>1:
|
||||
pages = list(range(2, pagecount+1))
|
||||
page_results = {}
|
||||
with ThreadPoolExecutor(max_workers=10) as executor:
|
||||
future_to_page = {
|
||||
executor.submit(self.fetch_page_data, page, ids[0]): page
|
||||
for page in pages
|
||||
}
|
||||
for future in as_completed(future_to_page):
|
||||
page = future_to_page[future]
|
||||
try:
|
||||
result = future.result()
|
||||
page_results[page] = result
|
||||
except Exception as e:
|
||||
print(f"Error fetching page {page}: {e}")
|
||||
for page in sorted(page_results.keys()):
|
||||
pdata.extend(page_results[page])
|
||||
vod['vod_play_url'] = '#'.join(pdata)
|
||||
return {'list':[vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
data=self.fetch(f'{self.shost}/applet/search/v1?channelCode=mobile-wxap&q={key}&pn={pg}&pc=10&_support=10000000', headers=self.headers).json()
|
||||
videoList = []
|
||||
for i in data['data']['contents']:
|
||||
if i.get('data') and len(i['data']):
|
||||
k = i['data'][0]
|
||||
if k.get('vid') and k.get('img'):
|
||||
try:
|
||||
videoList.append({
|
||||
'vod_id': k['vid'],
|
||||
'vod_name': k['title'],
|
||||
'vod_pic': k['img'],
|
||||
'vod_year': (i.get('rightTopCorner',{}) or {}).get('text') or i.get('year'),
|
||||
'vod_remarks': '/'.join(i.get('desc',[])),
|
||||
})
|
||||
except:
|
||||
print(k)
|
||||
return {'list':videoList,'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
id=f'{self.rhost}{id}'
|
||||
return {'parse': 1, 'url': id, 'header': ''}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def getf(self, body):
|
||||
params = {
|
||||
'allowedRC': '1',
|
||||
'channelId': body['type_id'],
|
||||
'platform': 'pcweb',
|
||||
'_support': '10000000',
|
||||
}
|
||||
data = self.fetch(f'{self.host}/rider/config/channel/v1', params=params, headers=self.headers).json()
|
||||
ft = []
|
||||
for i in data['data']['listItems']:
|
||||
try:
|
||||
value_array = [{"n": value['tagName'], "v": value['tagId']} for value in i['items'] if
|
||||
value.get('tagName')]
|
||||
ft.append({"key": i['eName'], "name": i['typeName'], "value": value_array})
|
||||
except:
|
||||
print(i)
|
||||
return body['type_id'], ft
|
||||
|
||||
def fetch_page_data(self, page, id, b=False):
|
||||
body = {'version': '5.5.35', 'video_id': id, 'page': page, 'size': '30',
|
||||
'platform': '4', 'src': 'mgtv', 'allowedRC': '1', '_support': '10000000'}
|
||||
data = self.fetch(f'{self.vhost}/episode/list', params=body, headers=self.headers).json()
|
||||
ldata = [f'{i["t3"]}${i["url"]}' for i in data['data']['list']]
|
||||
if b:
|
||||
return data, ldata
|
||||
else:
|
||||
return ldata
|
241
py/py_视觉.py
Normal file
241
py/py_视觉.py
Normal file
@ -0,0 +1,241 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜
|
||||
import sys
|
||||
|
||||
sys.path.append("")
|
||||
import re
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
from base64 import b64encode, b64decode
|
||||
import json
|
||||
from base.spider import Spider
|
||||
from urllib.parse import quote
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def getName(self):
|
||||
return "视觉"
|
||||
|
||||
def init(self, extend=""):
|
||||
self.host = self.host()
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def action(self, action):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(
|
||||
f"{self.host}/api/v3/drama/getCategory?orderBy=type_id",
|
||||
headers=self.headers,
|
||||
).json()
|
||||
dy = {
|
||||
"class": "类型",
|
||||
"area": "地区",
|
||||
"lang": "语言",
|
||||
"year": "年份",
|
||||
"letter": "字母",
|
||||
"by": "排序",
|
||||
"sort": "排序",
|
||||
}
|
||||
filters = {}
|
||||
classes = []
|
||||
for item in data["data"]:
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = json.loads(item["converUrl"])
|
||||
classes.append({"type_name": item["name"], "type_id": str(item["id"])})
|
||||
for key in dy:
|
||||
if key in jsontype_extend and jsontype_extend[key].strip() != "":
|
||||
has_non_empty_field = True
|
||||
break
|
||||
if has_non_empty_field:
|
||||
filters[str(item["id"])] = []
|
||||
for dkey in jsontype_extend:
|
||||
if dkey in dy and jsontype_extend[dkey].strip() != "":
|
||||
values = jsontype_extend[dkey].split(",")
|
||||
value_array = [
|
||||
{"n": value.strip(), "v": value.strip()}
|
||||
for value in values
|
||||
if value.strip() != ""
|
||||
]
|
||||
filters[str(item["id"])].append(
|
||||
{"key": dkey, "name": dy[dkey], "value": value_array}
|
||||
)
|
||||
result = {}
|
||||
result["class"] = classes
|
||||
result["filters"] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data = self.fetch(f"{self.host}/api/ex/v3/security/tag/list", headers=self.headers).json()["data"]
|
||||
data1 = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)
|
||||
list = []
|
||||
for item in data1[0]['carousels']:
|
||||
id = item['link'].split("id=")[1]
|
||||
list.append({
|
||||
"vod_id": id,
|
||||
'vod_name': item.get("title"),
|
||||
'vod_pic': item.get("cover"),
|
||||
'vod_remarks': item.get("sort"),
|
||||
})
|
||||
result = {"list": list}
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
params = []
|
||||
if extend.get('area'):
|
||||
params.append(f"vodArea={extend['area']}")
|
||||
if extend.get('classs'):
|
||||
params.append(f"vodClass={extend['class']}")
|
||||
params.append("pagesize=20")
|
||||
params.append(f"typeId1={tid}")
|
||||
params.append(f"page={pg}")
|
||||
if extend.get('year'):
|
||||
params.append(f"vodYear={extend['year']}")
|
||||
body = '&'.join(params)
|
||||
path = self.aes(self.aes(body, self.key[1], 'encrypt'), self.key[0], 'encrypt', True)
|
||||
data = self.fetch(f"{self.host}/api/ex/v3/security/drama/list?query={path}", headers=self.headers).json()[
|
||||
"data"]
|
||||
data = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)['list']
|
||||
list = []
|
||||
for item in data:
|
||||
list.append({
|
||||
'vod_id': item.get("id"),
|
||||
'vod_pic': item["coverImage"].get("path"),
|
||||
'vod_name': item.get("name"),
|
||||
'vod_year': item.get("year"),
|
||||
'vod_remarks': item.get("remark")
|
||||
})
|
||||
result = {}
|
||||
result["list"] = list
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
url = f"{self.host}/api/v3/drama/getDetail?id={ids[0]}"
|
||||
data = self.post(url, headers=self.headers).json()["data"]
|
||||
vod = {
|
||||
'vod_name': data.get("name"),
|
||||
'vod_area': data.get("area"),
|
||||
'type_name': data.get("clazz"),
|
||||
'vod_actor': data.get("actor"),
|
||||
'vod_director': data.get("director"),
|
||||
'vod_content': data.get("brief").strip(),
|
||||
}
|
||||
play = []
|
||||
names = []
|
||||
plays = {}
|
||||
for itt in data["videos"]:
|
||||
if itt["sourceCn"] not in names:
|
||||
plays[itt["source"]] = []
|
||||
names.append(itt["sourceCn"])
|
||||
url = f"vodPlayFrom={itt['source']}&playUrl={itt['path']}"
|
||||
if re.search(r"\.(mp4|m3u8|flv)$", itt["path"]):
|
||||
url = itt["path"]
|
||||
plays[itt["source"]].append(f"{itt['titleOld']}${url}")
|
||||
for it in plays:
|
||||
play.append("#".join(plays[it]))
|
||||
vod["vod_play_from"] = "$$$".join(names)
|
||||
vod["vod_play_url"] = "$$$".join(play)
|
||||
result = {"list": [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg=1):
|
||||
body = f"pagesize=20&page={pg}&searchKeys={key}"
|
||||
path = self.aes(self.aes(body, self.key[1], 'encrypt'), self.key[0], 'encrypt', True)
|
||||
data = self.fetch(f"{self.host}/api/ex/v3/security/drama/list?query={path}", headers=self.headers).json()[
|
||||
"data"]
|
||||
data = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)['list']
|
||||
list = []
|
||||
for item in data:
|
||||
list.append({
|
||||
'vod_id': item.get("id"),
|
||||
'vod_pic': item["coverImage"].get("path"),
|
||||
'vod_name': item.get("name"),
|
||||
'vod_year': item.get("year"),
|
||||
'vod_remarks': item.get("remark")
|
||||
})
|
||||
result = {"list": list, "page": pg}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
url = id
|
||||
if "vodPlayFrom" in url:
|
||||
try:
|
||||
path = self.aes(self.aes(id, self.key[1], 'encrypt'), self.key[0], 'encrypt', True)
|
||||
data = \
|
||||
self.fetch(f"{self.host}/api/ex/v3/security/videoUsableUrl?query={path}", headers=self.headers).json()[
|
||||
"data"]
|
||||
url = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)['playUrl']
|
||||
# try:
|
||||
# url1 = self.fetch(url, headers=self.headers, timeout=5, allow_redirects=False).headers['Location']
|
||||
# if "http" in url1 and url1:
|
||||
# url = url1
|
||||
# except:
|
||||
# pass
|
||||
except Exception as e:
|
||||
pass
|
||||
if '.jpg' in url or '.jpeg' in url or '.png' in url:
|
||||
url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["url"] = url
|
||||
result["header"] = {'User-Agent': 'okhttp/3.12.1'}
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
url = b64decode(param["url"]).decode('utf-8')
|
||||
durl = url[:url.rfind('/')]
|
||||
data = self.fetch(url, headers=self.headers).content.decode("utf-8")
|
||||
lines = data.strip().split('\n')
|
||||
for index, string in enumerate(lines):
|
||||
if '#EXT' not in string and 'http' not in string:
|
||||
lines[index] = durl + ('' if string.startswith('/') else '/') + string
|
||||
data = '\n'.join(lines)
|
||||
return [200, "application/vnd.apple.mpegur", data]
|
||||
|
||||
def host(self):
|
||||
try:
|
||||
url = self.fetch('https://www.shijue.pro/token.txt', headers=self.headers).json()['domain']
|
||||
return url
|
||||
except:
|
||||
return "http://118.25.18.217:6632"
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/3.12.1',
|
||||
'Content-Type': 'application/json;'
|
||||
}
|
||||
key = ['TFLYWVJ5EG5YB1PLZLVVMGVLBGRIDCSW', 'nj6E5K4yYYT5W4ScJ3J3rJ2zrzcJkpTk']
|
||||
|
||||
def aes(self, word, key, mode='decrypt', bool=False):
|
||||
key = key.encode('utf-8')
|
||||
if mode == 'decrypt':
|
||||
word = b64decode(word)
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
decrypted = cipher.decrypt(word)
|
||||
word = unpad(decrypted, AES.block_size).decode('utf-8')
|
||||
if bool:
|
||||
word = json.loads(word)
|
||||
elif mode == 'encrypt':
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
padded = pad(word.encode('utf-8'), AES.block_size)
|
||||
encrypted = cipher.encrypt(padded)
|
||||
word = b64encode(encrypted).decode('utf-8')
|
||||
if bool:
|
||||
word = quote(word)
|
||||
return word
|
||||
|
||||
|
225
py/py_金牌.py
Normal file
225
py/py_金牌.py
Normal file
@ -0,0 +1,225 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import uuid
|
||||
from pprint import pprint
|
||||
import requests
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import time
|
||||
from Crypto.Hash import MD5, SHA1
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
'''
|
||||
{
|
||||
"key": "",
|
||||
"name": "",
|
||||
"type": 3,
|
||||
"api": "",
|
||||
"searchable": 1,
|
||||
"quickSearch": 1,
|
||||
"filterable": 1,
|
||||
"ext": {
|
||||
"site": "https://www.tjrongze.com,https://www.jiabaide.cn,https://cqzuoer.com"
|
||||
}
|
||||
},
|
||||
fm写法
|
||||
'''
|
||||
if extend:
|
||||
hosts=json.loads(extend)['site']
|
||||
# hosts = "https://www.tjrongze.com,https://www.jiabaide.cn,https://cqzuoer.com"
|
||||
self.host = self.host_late(hosts)
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
cdata = self.fetch(f"{self.host}/api/mw-movie/anonymous/get/filer/type", headers=self.getheaders()).json()
|
||||
fdata = self.fetch(f"{self.host}/api/mw-movie/anonymous/v1/get/filer/list", headers=self.getheaders()).json()
|
||||
result = {}
|
||||
classes = []
|
||||
filters={}
|
||||
for k in cdata['data']:
|
||||
classes.append({
|
||||
'type_name': k['typeName'],
|
||||
'type_id': str(k['typeId']),
|
||||
})
|
||||
sort_values = [{"n": "最近更新", "v": "2"},{"n": "人气高低", "v": "3"}, {"n": "评分高低", "v": "4"}]
|
||||
for tid, d in fdata['data'].items():
|
||||
current_sort_values = sort_values.copy()
|
||||
if tid == '1':
|
||||
del current_sort_values[0]
|
||||
filters[tid] = [
|
||||
{"key": "type", "name": "类型",
|
||||
"value": [{"n": i["itemText"], "v": i["itemValue"]} for i in d["typeList"]]},
|
||||
|
||||
*([] if not d["plotList"] else [{"key": "v_class", "name": "剧情",
|
||||
"value": [{"n": i["itemText"], "v": i["itemText"]}
|
||||
for i in d["plotList"]]}]),
|
||||
|
||||
{"key": "area", "name": "地区",
|
||||
"value": [{"n": i["itemText"], "v": i["itemText"]} for i in d["districtList"]]},
|
||||
|
||||
{"key": "year", "name": "年份",
|
||||
"value": [{"n": i["itemText"], "v": i["itemText"]} for i in d["yearList"]]},
|
||||
|
||||
{"key": "lang", "name": "语言",
|
||||
"value": [{"n": i["itemText"], "v": i["itemText"]} for i in d["languageList"]]},
|
||||
|
||||
{"key": "sort", "name": "排序", "value": current_sort_values}
|
||||
]
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data1 = self.fetch(f"{self.host}/api/mw-movie/anonymous/v1/home/all/list", headers=self.getheaders()).json()
|
||||
data2=self.fetch(f"{self.host}/api/mw-movie/anonymous/home/hotSearch",headers=self.getheaders()).json()
|
||||
data=[]
|
||||
for i in data1['data'].values():
|
||||
data.extend(i['list'])
|
||||
data.extend(data2['data'])
|
||||
vods=self.getvod(data)
|
||||
return {'list':vods}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
|
||||
params = {
|
||||
"area": extend.get('area', ''),
|
||||
"filterStatus": "1",
|
||||
"lang": extend.get('lang', ''),
|
||||
"pageNum": pg,
|
||||
"pageSize": "30",
|
||||
"sort": extend.get('sort', '1'),
|
||||
"sortBy": "1",
|
||||
"type": extend.get('type', ''),
|
||||
"type1": tid,
|
||||
"v_class": extend.get('v_class', ''),
|
||||
"year": extend.get('year', '')
|
||||
}
|
||||
data = self.fetch(f"{self.host}/api/mw-movie/anonymous/video/list?{self.js(params)}", headers=self.getheaders(params)).json()
|
||||
result = {}
|
||||
result['list'] = self.getvod(data['data']['list'])
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
data=self.fetch(f"{self.host}/api/mw-movie/anonymous/video/detail?id={ids[0]}",headers=self.getheaders({'id':ids[0]})).json()
|
||||
vod=self.getvod([data['data']])[0]
|
||||
vod['vod_play_from']='嗷呜有金牌'
|
||||
vod['vod_play_url'] = '#'.join(
|
||||
f"{i['name'] if len(vod['episodelist']) > 1 else vod['vod_name']}${ids[0]}@@{i['nid']}" for i in
|
||||
vod['episodelist'])
|
||||
vod.pop('episodelist', None)
|
||||
return {'list':[vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
params = {
|
||||
"keyword": key,
|
||||
"pageNum": pg,
|
||||
"pageSize": "8",
|
||||
"sourceCode": "1"
|
||||
}
|
||||
data=self.fetch(f"{self.host}/api/mw-movie/anonymous/video/searchByWord?{self.js(params)}",headers=self.getheaders(params)).json()
|
||||
vods=self.getvod(data['data']['result']['list'])
|
||||
return {'list':vods,'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
self.header = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.61 Chrome/126.0.6478.61 Not/A)Brand/8 Safari/537.36',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'DNT': '1',
|
||||
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'Origin': self.host,
|
||||
'Referer': f'{self.host}/'
|
||||
}
|
||||
ids=id.split('@@')
|
||||
pdata=self.fetch(f"{self.host}/api/mw-movie/anonymous/v1/video/episode/url?id={ids[0]}&nid={ids[1]}",headers=self.getheaders({'id':ids[0],'nid':ids[1]})).json()
|
||||
return {'parse':0,'url':pdata['data']['playUrl'],'header':self.header}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def host_late(self, url_list):
|
||||
if isinstance(url_list, str):
|
||||
urls = [u.strip() for u in url_list.split(',')]
|
||||
else:
|
||||
urls = url_list
|
||||
if len(urls) <= 1:
|
||||
return urls[0] if urls else ''
|
||||
|
||||
results = {}
|
||||
threads = []
|
||||
|
||||
def test_host(url):
|
||||
try:
|
||||
start_time = time.time()
|
||||
response = requests.head(url, timeout=1.0, allow_redirects=False)
|
||||
delay = (time.time() - start_time) * 1000
|
||||
results[url] = delay
|
||||
except Exception as e:
|
||||
results[url] = float('inf')
|
||||
for url in urls:
|
||||
t = threading.Thread(target=test_host, args=(url,))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
return min(results.items(), key=lambda x: x[1])[0]
|
||||
|
||||
def md5(self, sign_key):
|
||||
md5_hash = MD5.new()
|
||||
md5_hash.update(sign_key.encode('utf-8'))
|
||||
md5_result = md5_hash.hexdigest()
|
||||
return md5_result
|
||||
|
||||
def js(self, param):
|
||||
return '&'.join(f"{k}={v}" for k, v in param.items())
|
||||
|
||||
def getheaders(self, param=None):
|
||||
if param is None:param = {}
|
||||
t=str(int(time.time()*1000))
|
||||
param['key']='cb808529bae6b6be45ecfab29a4889bc'
|
||||
param['t']=t
|
||||
sha1_hash = SHA1.new()
|
||||
sha1_hash.update(self.md5(self.js(param)).encode('utf-8'))
|
||||
sign = sha1_hash.hexdigest()
|
||||
deviceid = str(uuid.uuid4())
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.61 Chrome/126.0.6478.61 Not/A)Brand/8 Safari/537.36',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'sign': sign,
|
||||
't': t,
|
||||
'deviceid':deviceid
|
||||
}
|
||||
return headers
|
||||
|
||||
def convert_field_name(self, field):
|
||||
field = field.lower()
|
||||
if field.startswith('vod') and len(field) > 3:
|
||||
field = field.replace('vod', 'vod_')
|
||||
if field.startswith('type') and len(field) > 4:
|
||||
field = field.replace('type', 'type_')
|
||||
return field
|
||||
|
||||
def getvod(self, array):
|
||||
return [{self.convert_field_name(k): v for k, v in item.items()} for item in array]
|
||||
|
Loading…
Reference in New Issue
Block a user