mirror of
https://github.com/ZTHA000/tvbox.git
synced 2025-10-25 19:22:17 +00:00
Add files via upload
This commit is contained in:
97
th/py/APPV2.py
Normal file
97
th/py/APPV2.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
'''
|
||||
example:
|
||||
{
|
||||
"key": "py_appV2",
|
||||
"name": "xxx",
|
||||
"type": 3,
|
||||
"searchable": 1,
|
||||
"quickSearch": 1,
|
||||
"filterable": 1,
|
||||
"api": "./py/APPV2.py",
|
||||
"ext": "http://cmsyt.lyyytv.cn"
|
||||
}
|
||||
|
||||
'''
|
||||
self.host=extend
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/4.12.0',
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(f"{self.host}//api.php/app/nav?token=",headers=self.headers).json()
|
||||
keys = ["class", "area", "lang", "year", "letter", "by", "sort"]
|
||||
filters = {}
|
||||
classes = []
|
||||
for item in data['list']:
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = item["type_extend"]
|
||||
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
|
||||
for key in keys:
|
||||
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 keys 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": dkey, "value": value_array})
|
||||
result = {}
|
||||
result["class"] = classes
|
||||
result["filters"] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data=self.fetch(f"{self.host}/api.php/app/index_video?token=",headers=self.headers).json()
|
||||
videos=[]
|
||||
for item in data['list']:videos.extend(item['vlist'])
|
||||
return {'list':videos}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
params = {'tid':tid,'class':extend.get('class',''),'area':extend.get('area',''),'lang':extend.get('lang',''),'year':extend.get('year',''),'limit':'18','pg':pg}
|
||||
data=self.fetch(f"{self.host}/api.php/app/video",params=params,headers=self.headers).json()
|
||||
return data
|
||||
|
||||
def detailContent(self, ids):
|
||||
data=self.fetch(f"{self.host}/api.php/app/video_detail?id={ids[0]}",headers=self.headers).json()
|
||||
return {'list':[data['data']]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
data=self.fetch(f"{self.host}/api.php/app/search?text={key}&pg={pg}",headers=self.headers).json()
|
||||
videos=data['list']
|
||||
for item in data['list']:
|
||||
item.pop('type', None)
|
||||
return {'list':videos,'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
return {'jx':1,'playUrl':'','parse': 1, 'url': id, 'header': self.headers}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
|
||||
222
th/py/光速影视.py
Normal file
222
th/py/光速影视.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import re
|
||||
import sys
|
||||
from Crypto.Hash import MD5
|
||||
sys.path.append('..')
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
from urllib.parse import quote, urlparse
|
||||
from base64 import b64encode, b64decode
|
||||
import json
|
||||
import time
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.host = self.gethost()
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
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"][8:]
|
||||
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[1:]
|
||||
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"])
|
||||
for it in itt['urls']:
|
||||
it['user_agent']=itt["player_info"].get("user_agent")
|
||||
it["parse"]=itt["player_info"].get("parse")
|
||||
a.append(f"{it['name']}${self.e64(json.dumps(it))}")
|
||||
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
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
ids = json.loads(self.d64(id))
|
||||
h={"User-Agent": (ids['user_agent'] or "okhttp/3.14.9")}
|
||||
url = ids['url']
|
||||
p=1
|
||||
try:
|
||||
if re.search(r'\?url=', ids['parse_api_url']):
|
||||
data=self.fetch(ids['parse_api_url'], headers=h, timeout=10).json()
|
||||
url=data.get('url') or data['data'].get('url')
|
||||
elif not re.search(r'\.m3u8|\.mp4', ids.get('url')):
|
||||
body = f"parse_api={ids.get('parse') or ids['parse_api_url'].replace(ids['url'], '')}&url={quote(self.aes('encrypt', ids['url']))}&token={ids.get('token')}"
|
||||
b = self.getdata("/api.php/getappapi.index/vodParse", body)['json']
|
||||
url = json.loads(b)['url']
|
||||
p=0
|
||||
except Exception as e:
|
||||
print('错误信息:',e)
|
||||
pass
|
||||
if re.search(r'\.jpg|\.png|\.jpeg', url):
|
||||
url = self.Mproxy(url)
|
||||
result = {}
|
||||
result["parse"] = p
|
||||
result["url"] = url
|
||||
result["header"] = h
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
return self.Mlocal(param)
|
||||
|
||||
def gethost(self):
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/3.14.9'
|
||||
}
|
||||
host = self.fetch('https://jingyu-1312635929.cos.ap-nanjing.myqcloud.com/1.json',
|
||||
headers=headers).text.strip()
|
||||
return host
|
||||
|
||||
phend = {
|
||||
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)',
|
||||
'allowCrossProtocolRedirects': 'true'
|
||||
}
|
||||
|
||||
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()))
|
||||
header = {"Referer":self.host,
|
||||
"User-Agent": "okhttp/3.14.9", "app-version-code": "300", "app-ui-mode": "light",
|
||||
"app-api-verify-time": t, "app-user-device-id": self.md5(t),
|
||||
"app-api-verify-sign": self.aes("encrypt", t),
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
|
||||
return header
|
||||
|
||||
def getdata(self, path, data=None):
|
||||
vdata = self.post(f"{self.host}{path}", headers=self.header(), data=data, timeout=10).json()['data']
|
||||
data1 = self.aes("decrypt", vdata)
|
||||
return json.loads(data1)
|
||||
|
||||
def Mproxy(self, url):
|
||||
return self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
|
||||
|
||||
def Mlocal(self, param,header=None):
|
||||
url = self.d64(param["url"])
|
||||
ydata = self.fetch(url, headers=header, allow_redirects=False)
|
||||
data = ydata.content.decode('utf-8')
|
||||
if ydata.headers.get('Location'):
|
||||
url = ydata.headers['Location']
|
||||
data = self.fetch(url, headers=header).content.decode('utf-8')
|
||||
parsed_url = urlparse(url)
|
||||
durl = parsed_url.scheme + "://" + parsed_url.netloc
|
||||
lines = data.strip().split('\n')
|
||||
for index, string in enumerate(lines):
|
||||
if '#EXT' not in string and 'http' not in string:
|
||||
last_slash_index = string.rfind('/')
|
||||
lpath = string[:last_slash_index + 1]
|
||||
lines[index] = durl + ('' if lpath.startswith('/') else '/') + lpath
|
||||
data = '\n'.join(lines)
|
||||
return [200, "application/vnd.apple.mpegur", data]
|
||||
|
||||
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 md5(self, text):
|
||||
h = MD5.new()
|
||||
h.update(text.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
146
th/py/嗨皮影视.py
Normal file
146
th/py/嗨皮影视.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
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
|
||||
225
th/py/文才影视.py
Normal file
225
th/py/文才影视.py
Normal file
@@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import uuid
|
||||
import requests
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import time
|
||||
from Crypto.Hash import MD5, SHA1
|
||||
|
||||
class Spider(Spider):
|
||||
'''
|
||||
配置示例:
|
||||
{
|
||||
"key": "xxxx",
|
||||
"name": "xxxx",
|
||||
"type": 3,
|
||||
"api": ".所在路径/金牌.py",
|
||||
"searchable": 1,
|
||||
"quickSearch": 1,
|
||||
"filterable": 1,
|
||||
"changeable": 1,
|
||||
"ext": {
|
||||
"site": "https://www.jiabaide.cn,域名2,域名3"
|
||||
}
|
||||
},
|
||||
'''
|
||||
def init(self, extend=""):
|
||||
if extend:
|
||||
hosts=json.loads(extend)['site']
|
||||
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/v2/video/episode/url?clientType=1&id={ids[0]}&nid={ids[1]}",headers=self.getheaders({'clientType':'1','id': ids[0], 'nid': ids[1]})).json()
|
||||
vlist=[]
|
||||
for i in pdata['data']['list']:vlist.extend([i['resolutionName'],i['url']])
|
||||
return {'parse':0,'url':vlist,'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]
|
||||
|
||||
314
th/py/爱看短剧.py
Normal file
314
th/py/爱看短剧.py
Normal file
@@ -0,0 +1,314 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
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.ut = False
|
||||
# self.did, self.ntid =self.getdid()
|
||||
self.did, self.ntid = 'e59eb2465f61b9ca','65a0de19b3a2ec93fa479ad6'
|
||||
self.token, self.uid = 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 getdid(self):
|
||||
did = self.random_str(16)
|
||||
ntid = self.random_str(24)
|
||||
return did, ntid
|
||||
# try:
|
||||
# if self.getCache('did'):
|
||||
# return self.getCache('did'), self.getCache('ntid')
|
||||
# else:
|
||||
# self.setCache('did', did)
|
||||
# self.setCache('ntid', ntid)
|
||||
# return did, ntid
|
||||
# except Exception as e:
|
||||
# self.setCache('did', did)
|
||||
# self.setCache('ntid', ntid)
|
||||
# return did, ntid
|
||||
|
||||
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.ut=True
|
||||
return data['data']['token'], data['data']['userId']
|
||||
|
||||
def getdata(self,path,params=None):
|
||||
t = int(time.time()*1000)
|
||||
n=self.md5(f'{self.uuid()}{t}')
|
||||
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(int(t/1000)),
|
||||
's': s,
|
||||
}
|
||||
if self.ut:
|
||||
headers['ta-token'] = self.token
|
||||
headers['userId'] = self.uid
|
||||
if params:
|
||||
params={'ct':ct}
|
||||
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):
|
||||
try:
|
||||
at = int(time.time() * 1000)
|
||||
t=str(int(at/ 1000))
|
||||
n = self.md5(f'{self.uuid()}{at}')
|
||||
headers = {
|
||||
'Host': '192.151.245.34:8089',
|
||||
'User-Agent': 'okhttp-okgo/jeasonlzy',
|
||||
'Connection': 'Keep-Alive',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.8',
|
||||
'tenantId': self.ntid,
|
||||
'userId': self.uid,
|
||||
'ta-token': self.token,
|
||||
'n': n,
|
||||
't': t,
|
||||
's': self.md5(f'{t}{n}8j@78m.367HGDF')
|
||||
}
|
||||
params = {
|
||||
'tenantId': self.ntid,
|
||||
}
|
||||
response = self.fetch(f'{self.host}/supports/configs', params=params, headers=headers).text
|
||||
data=self.aes(response[1:-1],False)
|
||||
config = {
|
||||
'image_cdn': '',
|
||||
'image_cdn_path': '',
|
||||
'cdn-domain': ''
|
||||
}
|
||||
for item in data.get('data', []):
|
||||
name = item.get('name')
|
||||
records = item.get('records', [])
|
||||
|
||||
if name in config and records:
|
||||
value = records[0].get('value', '')
|
||||
if name == 'cdn-domain':
|
||||
value = value.split('#')[0]
|
||||
config[name] = value
|
||||
|
||||
return config['image_cdn'], config['image_cdn_path'], config['cdn-domain']
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in getpic: {e}")
|
||||
return 'https://dbtp.tgydy.com', '.log', 'https://dplay.nbzsmc.com'
|
||||
|
||||
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': 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 = base64.urlsafe_b64decode("iM41VipvCFtToAFFRExEXw==")
|
||||
iv = base64.urlsafe_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)]
|
||||
|
||||
279
th/py/猎手影视.py
Normal file
279
th/py/猎手影视.py
Normal file
@@ -0,0 +1,279 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
# by嗷呜(finally)
|
||||
import sys
|
||||
import os
|
||||
sys.path.append("..")
|
||||
import re
|
||||
import hashlib
|
||||
import hmac
|
||||
import random
|
||||
import string
|
||||
from Crypto.Util.Padding import unpad
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Cipher import PKCS1_v1_5, AES
|
||||
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.device = self.device_id()
|
||||
self.host = self.gethost()
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def action(self, action):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
t = str(int(time.time()))
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
filters = {}
|
||||
classes = []
|
||||
bba = self.url()
|
||||
data = self.fetch(f"{self.host}/api/v1/app/config?pack={bba[0]}&signature={bba[1]}", headers=self.header()).text
|
||||
data1 = self.aes(data)
|
||||
dy = {"class":"类型","area":"地区","lang":"语言","year":"年份","letter":"字母","by":"排序","sort":"排序"}
|
||||
data1['data']['movie_screen']['sort'].pop(0)
|
||||
for item in data1['data']['movie_screen']['sort']:
|
||||
item['n'] = item.pop('name')
|
||||
item['v'] = item.pop('value')
|
||||
for item in data1['data']['movie_screen']['filter']:
|
||||
has_non_empty_field = False
|
||||
classes.append({"type_name": item["name"], "type_id": str(item["id"])})
|
||||
for key in dy:
|
||||
if key in item and item[key]:
|
||||
has_non_empty_field = True
|
||||
break
|
||||
if has_non_empty_field:
|
||||
filters[str(item["id"])] = []
|
||||
filters[str(item["id"])].append(
|
||||
{"key": 'sort', "name": '排序', "value": data1['data']['movie_screen']['sort']})
|
||||
for dkey in item:
|
||||
if dkey in dy and item[dkey]:
|
||||
item[dkey].pop(0)
|
||||
value_array = [
|
||||
{"n": value.strip(), "v": value.strip()}
|
||||
for value in item[dkey]
|
||||
if value.strip() != ""
|
||||
]
|
||||
filters[str(item["id"])].append(
|
||||
{"key": dkey, "name": dy[dkey], "value": value_array}
|
||||
)
|
||||
result["class"] = classes
|
||||
result["filters"] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
bba = self.url()
|
||||
url = f'{self.host}/api/v1/movie/index_recommend?pack={bba[0]}&signature={bba[1]}'
|
||||
data = self.fetch(url, headers=self.header()).json()
|
||||
videos = []
|
||||
for item in data['data']:
|
||||
if len(item['list']) > 0:
|
||||
for it in item['list']:
|
||||
try:
|
||||
videos.append(self.voides(it))
|
||||
except Exception as e:
|
||||
continue
|
||||
result = {"list": videos}
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
body = {"type_id": tid, "sort": extend.get("sort", "by_default"), "class": extend.get("class", "类型"),
|
||||
"area": extend.get("area", "地区"), "year": extend.get("year", "年份"), "page": str(pg),
|
||||
"pageSize": "21"}
|
||||
result = {}
|
||||
list = []
|
||||
bba = self.url(body)
|
||||
url = f"{self.host}/api/v1/movie/screen/list?pack={bba[0]}&signature={bba[1]}"
|
||||
data = self.fetch(url, headers=self.header()).json()['data']['list']
|
||||
for item in data:
|
||||
list.append(self.voides(item))
|
||||
result["list"] = list
|
||||
result["page"] = pg
|
||||
result["pagecount"] = 9999
|
||||
result["limit"] = 90
|
||||
result["total"] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
body = {"id": ids[0]}
|
||||
bba = self.url(body)
|
||||
url = f'{self.host}/api/v1/movie/detail?pack={bba[0]}&signature={bba[1]}'
|
||||
data = self.fetch(url, headers=self.header()).json()['data']
|
||||
video = {'vod_name': data.get('name'),'type_name': data.get('type_name'),'vod_year': data.get('year'),'vod_area': data.get('area'),'vod_remarks': data.get('dynami'),'vod_content': data.get('content')}
|
||||
play = []
|
||||
names = []
|
||||
tasks = []
|
||||
for itt in data["play_from"]:
|
||||
name = itt["name"]
|
||||
a = []
|
||||
if len(itt["list"]) > 0:
|
||||
names.append(name)
|
||||
play.append(self.playeach(itt['list']))
|
||||
else:
|
||||
tasks.append({"movie_id": ids[0], "from_code": itt["code"]})
|
||||
names.append(name)
|
||||
if tasks:
|
||||
with ThreadPoolExecutor(max_workers=len(tasks)) as executor:
|
||||
results = executor.map(self.playlist, tasks)
|
||||
for result in results:
|
||||
if result:
|
||||
play.append(result)
|
||||
else:
|
||||
play.append("")
|
||||
video["vod_play_from"] = "$$$".join(names)
|
||||
video["vod_play_url"] = "$$$".join(play)
|
||||
result = {"list": [video]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg=1):
|
||||
body = {"keyword": key, "sort": "", "type_id": "0", "page": str(pg), "pageSize": "10",
|
||||
"res_type": "by_movie_name"}
|
||||
bba = self.url(body)
|
||||
url = f"{self.host}/api/v1/movie/search?pack={bba[0]}&signature={bba[1]}"
|
||||
data = self.fetch(url, headers=self.header()).json()['data'].get('list')
|
||||
videos = []
|
||||
for it in data:
|
||||
try:
|
||||
videos.append(self.voides(it))
|
||||
except Exception as e:
|
||||
continue
|
||||
result = {"list": videos, "page": pg}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
url = id
|
||||
if "m3u8" not in url and "mp4" not in url:
|
||||
try:
|
||||
add = id.split('|||')
|
||||
data = {"from_code": add[0], "play_url": add[1], "episode_id": add[2], "type": "play"}
|
||||
bba = self.url(data)
|
||||
data2 = self.fetch(f"{self.host}/api/v1/movie_addr/parse_url?pack={bba[0]}&signature={bba[1]}",
|
||||
headers=self.header()).json()['data']
|
||||
url = data2.get('play_url') or data2.get('download_url')
|
||||
try:
|
||||
url1 = self.fetch(url, headers=self.header(), allow_redirects=False).headers['Location']
|
||||
if url1 and "http" in 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/4.9.2'}
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
url = b64decode(param["url"]).decode('utf-8')
|
||||
durl = url[:url.rfind('/')]
|
||||
data = self.fetch(url, headers=self.header()).content.decode("utf-8")
|
||||
lines = data.strip().split('\n')
|
||||
for index, string in enumerate(lines):
|
||||
# if 'URI="' in string and 'http' not in string:
|
||||
# lines[index] = index
|
||||
# 暂时预留,貌似用不到
|
||||
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 device_id(self):
|
||||
characters = string.ascii_lowercase + string.digits
|
||||
random_string = ''.join(random.choices(characters, k=32))
|
||||
return random_string
|
||||
|
||||
def gethost(self):
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/4.9.2',
|
||||
'Connection': 'Keep-Alive',
|
||||
}
|
||||
response = self.fetch('https://app-site.ecoliving168.com/domain_v5.json', headers=headers).json()
|
||||
url = response['api_service'].replace('/api/', '')
|
||||
return url
|
||||
|
||||
def header(self):
|
||||
headers = {
|
||||
'User-Agent': 'Android',
|
||||
'Accept': 'application/prs.55App.v2+json',
|
||||
'timestamp': self.t,
|
||||
'x-client-setting': '{"pure-mode":1}',
|
||||
'x-client-uuid': '{"device_id":' + self.device + '}, "type":1,"brand":"Redmi", "model":"M2012K10C", "system_version":30, "sdk_version":"3.1.0.7"}',
|
||||
'x-client-version': '3096 '
|
||||
}
|
||||
return headers
|
||||
|
||||
def url(self, id=None):
|
||||
if not id:
|
||||
id = {}
|
||||
id["timestamp"] = self.t
|
||||
public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02F/kPg5A2NX4qZ5JSns+bjhVMCC6JbTiTKpbgNgiXU+Kkorg6Dj76gS68gB8llhbUKCXjIdygnHPrxVHWfzmzisq9P9awmXBkCk74Skglx2LKHa/mNz9ivg6YzQ5pQFUEWS0DfomGBXVtqvBlOXMCRxp69oWaMsnfjnBV+0J7vHbXzUIkqBLdXSNfM9Ag5qdRDrJC3CqB65EJ3ARWVzZTTcXSdMW9i3qzEZPawPNPe5yPYbMZIoXLcrqvEZnRK1oak67/ihf7iwPJqdc+68ZYEmmdqwunOvRdjq89fQMVelmqcRD9RYe08v+xDxG9Co9z7hcXGTsUquMxkh29uNawIDAQAB'
|
||||
encrypted_text = json.dumps(id)
|
||||
public_key = RSA.import_key(b64decode(public_key))
|
||||
cipher = PKCS1_v1_5.new(public_key)
|
||||
encrypted_message = cipher.encrypt(encrypted_text.encode('utf-8'))
|
||||
encrypted_message_base64 = b64encode(encrypted_message).decode('utf-8')
|
||||
result = encrypted_message_base64.replace('+', '-').replace('/', '_').replace('=', '')
|
||||
key = '635a580fcb5dc6e60caa39c31a7bde48'
|
||||
sign = hmac.new(key.encode(), result.encode(), hashlib.md5).hexdigest()
|
||||
return result, sign
|
||||
|
||||
def playlist(self, body):
|
||||
try:
|
||||
bba = self.url(body)
|
||||
url = f'{self.host}/api/v1/movie_addr/list?pack={bba[0]}&signature={bba[1]}'
|
||||
data = self.fetch(url, headers=self.header()).json()['data']
|
||||
return self.playeach(data)
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def playeach(self,data):
|
||||
play_urls = []
|
||||
for it in data:
|
||||
if re.search(r"mp4|m3u8", it["play_url"]):
|
||||
play_urls.append(f"{it['episode_name']}${it['play_url']}")
|
||||
else:
|
||||
play_urls.append(
|
||||
f"{it['episode_name']}${it['from_code']}|||{it['play_url']}|||{it['episode_id']}"
|
||||
)
|
||||
return '#'.join(play_urls)
|
||||
|
||||
def voides(self, item):
|
||||
if item['name'] or item['title']:
|
||||
voide = {
|
||||
"vod_id": item.get('id') or item.get('click'),
|
||||
'vod_name': item.get('name') or item.get('title'),
|
||||
'vod_pic': item.get('cover') or item.get('image'),
|
||||
'vod_year': item.get('year') or item.get('label'),
|
||||
'vod_remarks': item.get('dynamic') or item.get('sub_title')
|
||||
}
|
||||
return voide
|
||||
|
||||
def aes(self, text):
|
||||
text = text.replace('-', '+').replace('_', '/') + '=='
|
||||
key = b"e6d5de5fcc51f53d"
|
||||
iv = b"2f13eef7dfc6c613"
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size).decode("utf-8")
|
||||
return json.loads(pt)
|
||||
93
th/py/美帕影视.py
Normal file
93
th/py/美帕影视.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
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
|
||||
225
th/py/金牌影视.py
Normal file
225
th/py/金牌影视.py
Normal file
@@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import uuid
|
||||
import requests
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import time
|
||||
from Crypto.Hash import MD5, SHA1
|
||||
|
||||
class Spider(Spider):
|
||||
'''
|
||||
配置示例:
|
||||
{
|
||||
"key": "xxxx",
|
||||
"name": "xxxx",
|
||||
"type": 3,
|
||||
"api": ".所在路径/金牌.py",
|
||||
"searchable": 1,
|
||||
"quickSearch": 1,
|
||||
"filterable": 1,
|
||||
"changeable": 1,
|
||||
"ext": {
|
||||
"site": "https://www.jiabaide.cn,域名2,域名3"
|
||||
}
|
||||
},
|
||||
'''
|
||||
def init(self, extend=""):
|
||||
if extend:
|
||||
hosts=json.loads(extend)['site']
|
||||
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/v2/video/episode/url?clientType=1&id={ids[0]}&nid={ids[1]}",headers=self.getheaders({'clientType':'1','id': ids[0], 'nid': ids[1]})).json()
|
||||
vlist=[]
|
||||
for i in pdata['data']['list']:vlist.extend([i['resolutionName'],i['url']])
|
||||
return {'parse':0,'url':vlist,'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]
|
||||
|
||||
Reference in New Issue
Block a user