Add files via upload
This commit is contained in:
parent
a1b09e5c34
commit
36efd48fd0
254
PY/CliCli动漫.py
Normal file
254
PY/CliCli动漫.py
Normal file
@ -0,0 +1,254 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import base64
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from base64 import b64decode, b64encode
|
||||
from Crypto.Cipher import AES, PKCS1_v1_5
|
||||
from Crypto.Hash import MD5
|
||||
from Crypto.PublicKey import RSA
|
||||
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.getdid()
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host='http://60.204.242.79:8091'
|
||||
|
||||
def homeContent(self, filter):
|
||||
res = self.fetch(f'{self.host}/app/channel?top-level=true', headers=self.getheaders()).text
|
||||
data = self.getdata(res)
|
||||
result = {}
|
||||
classes = []
|
||||
filters = {}
|
||||
sortsn = ['最新','最热','高分']
|
||||
for k in data['data']:
|
||||
classes.append({
|
||||
'type_name': k['name'],
|
||||
'type_id': k['id']
|
||||
})
|
||||
filters[k['id']] = []
|
||||
k['sorts']=['addtime','hits','gold']
|
||||
for key,value in k.items():
|
||||
if type(value) == list:
|
||||
filters[k['id']].append({
|
||||
'name': key,
|
||||
'key': key,
|
||||
'value': [{'v': x,'n': x if key !='sorts' else sortsn[i]} for i,x in enumerate(value) if x]
|
||||
})
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
res=self.fetch(f'{self.host}/app/banners/0',headers=self.getheaders()).text
|
||||
data=self.getdata(res)
|
||||
videos=[]
|
||||
for i in data['data']:
|
||||
videos.append({
|
||||
'vod_id': i['vid'],
|
||||
'vod_name': i['vname'],
|
||||
'vod_pic': i['img'],
|
||||
'vod_remarks': i['continu']
|
||||
})
|
||||
return {'list':videos}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
params={'channel':tid,'type':extend.get('types',''),'area':extend.get('areas',''),'year':extend.get('years',''),'sort':extend.get('sorts','addtime'),'limit':'30','page':pg}
|
||||
data=self.fetch(f'{self.host}/app/video/list',params=params,headers=self.getheaders()).text
|
||||
data=self.getdata(data)
|
||||
videos=[]
|
||||
for i in data['data']['items']:
|
||||
videos.append({
|
||||
'vod_id': i.get('id'),
|
||||
'vod_name': i.get('name'),
|
||||
'vod_pic': i.get('pic'),
|
||||
'vod_year': i.get('year'),
|
||||
'vod_remarks': i.get('continu')
|
||||
})
|
||||
result = {}
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
data=self.fetch(f'{self.host}/app/video/detail?id={ids[0]}',headers=self.getheaders()).text
|
||||
data=self.getdata(data)
|
||||
v=data['data']
|
||||
vod = {
|
||||
'type_name': v.get('type'),
|
||||
'vod_year': v.get('year'),
|
||||
'vod_area': v.get('area'),
|
||||
'vod_remarks': v.get('continu'),
|
||||
'vod_actor': v.get('actor'),
|
||||
'vod_director': v.get('director'),
|
||||
'vod_content': v.get('content'),
|
||||
'vod_play_from': '',
|
||||
'vod_play_url': ''
|
||||
}
|
||||
parts,names = [],[]
|
||||
for i in v['parts']:
|
||||
names.append(i['play_zh'])
|
||||
p=[]
|
||||
for j,x in enumerate(i['part']):
|
||||
params={'id':ids[0],'play':i['play'],'part':x}
|
||||
p.append(f'{x}${self.e64(json.dumps(params))}')
|
||||
parts.append('#'.join(p))
|
||||
vod['vod_play_from'] = '$$$'.join(names)
|
||||
vod['vod_play_url'] = '$$$'.join(parts)
|
||||
return {'list':[vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
params={'key':key,'limit':'25','page':pg}
|
||||
data=self.fetch(f'{self.host}/app/video/search',params=params,headers=self.getheaders()).text
|
||||
data=self.getdata(data)
|
||||
videos = []
|
||||
for i in data['data']['items']:
|
||||
videos.append({
|
||||
'vod_id': i.get('id'),
|
||||
'vod_name': i.get('name'),
|
||||
'vod_pic': i.get('pic'),
|
||||
'vod_year': i.get('year'),
|
||||
'vod_remarks': i.get('continu')
|
||||
})
|
||||
return {'list':videos,'page':pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
params= json.loads(self.d64(id))
|
||||
data=self.fetch(f'{self.host}/app/video/play',params=params,headers=self.getheaders()).text
|
||||
data=self.getdata(data)
|
||||
urls=[]
|
||||
for i in data['data']:
|
||||
if i.get('url'):urls.extend([i['resolution'],i['url']])
|
||||
return {'parse': 0, 'url': urls, 'header': {'User-Agent': 'Dart/3.6 (dart:io)'}}
|
||||
|
||||
def liveContent(self, url):
|
||||
pass
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def getheaders(self):
|
||||
t=str(int(time.time() * 1000))
|
||||
stinf=f"3.0.0.2-{t}-Android-1.0.4.5-{self.did}"
|
||||
authentication=self.aes_encrypt(self.e64(stinf))
|
||||
headers = {
|
||||
'User-Agent': 'Dart/3.6 (dart:io)',
|
||||
'x-version': '2020-09-17',
|
||||
'appid': '4150439554430614',
|
||||
'ts': t,
|
||||
'authentication': authentication,
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
}
|
||||
return headers
|
||||
|
||||
def aes_encrypt(self, text):
|
||||
key = b'ziISjqkXPsGUMRNGyWigxDGtJbfTdcGv'
|
||||
iv = b'WonrnVkxeIxDcFbv'
|
||||
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
|
||||
|
||||
def aes_decrypt(self, key,text):
|
||||
iv=key[::-1].encode("utf-8")
|
||||
key=key.encode("utf-8")
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
|
||||
return json.loads(pt.decode("utf-8"))
|
||||
|
||||
def rsa_decrypt(self, encrypted_data):
|
||||
try:
|
||||
private_key_string = '''-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA5xpfniKIMYdjTytUBu5rsLbMtcCRW9B9DB78QEdf4wW5jO8r
|
||||
Mw7j+/mYk3ghi0xrxpjtHm1R2KgNT1b0akJCExTH7gBVcjVywpmXdNXbcuCGfVCK
|
||||
S6vYfMypmj5lNBgalCHe5AVc0ghhP3FG5j8Q5B7q00+tk4nT9nFsTmTeNcAKSH9h
|
||||
aM6a0fbiJ3eXbxEr2o8raAjck10act35t/MIUOkcrQjHx5E9Yvqgs3qbq4yDakaG
|
||||
4qfMAV4DAkkmdZ8N3fdEQ+rFJ67Spd4zzowj81+YO9wMUP2hNgfXmLOGLS5Lyi+x
|
||||
vrwwWZXAIRUkhdQEAYQlhGs8wV9P4bJnTzplewIDAQABAoIBAEnRzNUwZpybiIdT
|
||||
acXFBrUtzvoHhubzE955T04g/mn//CMeiogGq6BjO+9vIhfi01Jequ9bMBeqpoW/
|
||||
WtdOTtjVfH9zr9eJZxzt/skdPrnVKmCBB4vgWoiSv2I7qAwZ3vOOVioz5FBayOWB
|
||||
A4qsfnK/xXa2LtW/4usHk/b+lVRJZhHl3eKio2CnVBrgRb2DTx1GAwpvaRXp0oHm
|
||||
LXDEtngxN4/rh2irPKgaG/lgrCBISKUHtwtgytcpltsHMASMXIKAjZjNgCA98fA3
|
||||
te96U58wGHzQBQ5XtwTf0PiFEfJ7yOhgNRgCtiwsjGOhJFJFiiXYKzTef1GnVxPa
|
||||
wuPc0TECgYEA+KCts3ArkWLqWbi4bVDpekP71geEnQIklSAk3RRZ0eiC1pmmkuTh
|
||||
+q/4jOfoQHGuYCc8GvJqxQ8Y+aspPptbsAeRMSVovjQUvpRMqD0SWT8o3W2xGfqd
|
||||
0W4p14CIF7oXjMqQVeY468AYzxUdNsaulrp9Wnpa5njzE5D5WGDu0IcCgYEA7fSq
|
||||
kvz1oXjlljlskBwJ8gDB8j53PhuqV6Ori71G/qIGpYuOVjHSfPD/04a9T3M9olpk
|
||||
vlLOLn7GS7xa4pjugmp0EDdxBIJJtTHbbi4NL4ZoYg+vHkiemkjGLis4x5qRKjg6
|
||||
jNUEhnpksm68IUMSyO2toasfR0nVUmkb+ylKhG0CgYEAqNDZAJSyUHZcb21YdIlS
|
||||
7rzIe2wBZGZ3FnaL8T0HO9rnM/WCQA1/Tys61doFPfSylQEu85EUZBc7OxM33xW3
|
||||
7M9Gi5s+Ap/0Ue76GeXV1plnEuqPLPeZPwHREU1pmsq1gNhtppW6ooB9l+ZbPr0r
|
||||
AJdB1DRuEj2ftvJiC9tNbHMCgYEAvHaliply6hrYq6x7gX/TmKpk8bnrs3Mx7Qui
|
||||
WKDm09H8Na1cZIQ9U9uEo0H6OizpyeaSF/N5fXXHFEDwMrwxW3V4y0c96fZO7oW4
|
||||
Z4FtzBBGKDSH3BJkG4o7/GEbLWwMQUYbiWNFnETf8DqoIif/fshQVtUzhsDBhe3d
|
||||
zYUckdkCgYAJlTYhJz0qXcO8a5KsQ20/hEGRtOcq+mfPOdGYBOv6LB2ThuDKunbY
|
||||
WsmAvqSo1qoJONnhQVMSpzKWEjCYV6hcifV9aeFofD4kNmG1gWC18QIYfrihLyOU
|
||||
E4GDW7QN8HO2YiQpopGP/muKsIlCmxKP6DasgCCO36xs87Wi8gu1DA==
|
||||
-----END RSA PRIVATE KEY-----'''
|
||||
private_key = RSA.import_key(private_key_string)
|
||||
cipher = PKCS1_v1_5.new(private_key)
|
||||
encrypted_bytes = base64.b64decode(encrypted_data)
|
||||
decrypted_bytes = cipher.decrypt(encrypted_bytes, None)
|
||||
return decrypted_bytes.decode('utf-8')
|
||||
except:
|
||||
return ""
|
||||
|
||||
def getdata(self, data):
|
||||
ds=data.split('.')
|
||||
key=self.rsa_decrypt(ds[0])
|
||||
result=self.aes_decrypt(key,ds[1])
|
||||
return result
|
||||
|
||||
def getdid(self):
|
||||
did=self.getCache('did')
|
||||
if not did:
|
||||
t = str(int(time.time()))
|
||||
did = self.md5(t)
|
||||
self.setCache('did', did)
|
||||
return did
|
||||
|
||||
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()
|
||||
|
249
PY/MiFunP动漫.py
Normal file
249
PY/MiFunP动漫.py
Normal file
@ -0,0 +1,249 @@
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import requests
|
||||
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()
|
||||
self.did=self.getdid()
|
||||
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")}
|
||||
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')
|
||||
else:
|
||||
body = f"parse_api={ids.get('parse') or ids['parse_api_url'].replace(ids['url'], '')}&url={quote(self.aes(ids['url'], True))}&token={ids.get('token')}"
|
||||
b = self.getdata("/api.php/getappapi.index/vodParse", body)['json']
|
||||
url = json.loads(b)['url']
|
||||
if 'error' in url: raise ValueError(f"解析失败: {url}")
|
||||
p = 0
|
||||
except Exception as e:
|
||||
print('错误信息:', e)
|
||||
url, p = ids['url'], 1
|
||||
|
||||
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'
|
||||
}
|
||||
response = self.fetch('https://miget-1313189639.cos.ap-guangzhou.myqcloud.com/mifun.txt',headers=headers).text
|
||||
return self.host_late(response.split('\n'))
|
||||
|
||||
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:
|
||||
url = url.strip()
|
||||
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 getdid(self):
|
||||
did=self.getCache('did')
|
||||
if not did:
|
||||
t = str(int(time.time()))
|
||||
did = self.md5(t)
|
||||
self.setCache('did', did)
|
||||
return did
|
||||
|
||||
def aes(self, text, b=None):
|
||||
key = b"GETMIFUNGEIMIFUN"
|
||||
cipher = AES.new(key, AES.MODE_CBC, key)
|
||||
if b:
|
||||
ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size))
|
||||
ct = b64encode(ct_bytes).decode("utf-8")
|
||||
return ct
|
||||
else:
|
||||
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": "516", "app-ui-mode": "light",
|
||||
"app-api-verify-time": t, "app-user-device-id": self.did,
|
||||
"app-api-verify-sign": self.aes(t, True),
|
||||
"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(vdata)
|
||||
return json.loads(data1)
|
||||
|
||||
def Mproxy(self, url):
|
||||
return f"{self.getProxyUrl()}&url={self.e64(url)}&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()
|
||||
|
263
PY/wawa.py
Normal file
263
PY/wawa.py
Normal file
@ -0,0 +1,263 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
from base64 import b64decode, b64encode
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import SHA256, MD5
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import pkcs1_15
|
||||
from Crypto.Util.Padding import unpad
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.host, self.appKey, self.rsakey = self.userinfo()
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = self.fetch(f"{self.host}/api.php/zjv6.vod/types", headers=self.getheader()).json()
|
||||
dy = {"class": "类型", "area": "地区", "lang": "语言", "year": "年份", "letter": "字母", "by": "排序", }
|
||||
filters = {}
|
||||
classes = []
|
||||
json_data = data['data']['list']
|
||||
for item in json_data:
|
||||
has_non_empty_field = False
|
||||
jsontype_extend = item["type_extend"]
|
||||
jsontype_extend['by'] = '按更新,按播放,按评分,按收藏'
|
||||
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(",")
|
||||
sl = {'按更新': 'time', '按播放': 'hits', '按评分': 'score', '按收藏': 'store_num'}
|
||||
value_array = [
|
||||
{"n": value.strip(), "v": sl[value.strip()] if dkey == "by" else value.strip()}
|
||||
for value in values
|
||||
if value.strip() != ""
|
||||
]
|
||||
filters[str(item["type_id"])].append(
|
||||
{"key": dkey, "name": dy[dkey], "value": value_array}
|
||||
)
|
||||
result = {"class": classes, "filters": filters}
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
data = self.fetch(f"{self.host}/api.php/zjv6.vod/vodPhbAll", headers=self.getheader()).json()
|
||||
return {'list': data['data']['list'][0]['vod_list']}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
params = {
|
||||
"type": tid,
|
||||
"class": extend.get('class', ''),
|
||||
"lang": extend.get('lang', ''),
|
||||
"area": extend.get('area', ''),
|
||||
"year": extend.get('year', ''),
|
||||
"by": extend.get('by', ''),
|
||||
"page": pg,
|
||||
"limit": "12"
|
||||
}
|
||||
data = self.fetch(f"{self.host}/api.php/zjv6.vod", headers=self.getheader(), params=params).json()
|
||||
result = {}
|
||||
result['list'] = 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.php/zjv6.vod/detail?vod_id={ids[0]}&rel_limit=10",
|
||||
headers=self.getheader()).json()
|
||||
vod = data['data']
|
||||
v, np = {'vod_play_from': [], 'vod_play_url': []}, {}
|
||||
for i in vod['vod_play_list']:
|
||||
n = i['player_info']['show']
|
||||
np[n] = []
|
||||
for j in i['urls']:
|
||||
j['parse'] = i['player_info']['parse2']
|
||||
nm = j.pop('name')
|
||||
np[n].append(f"{nm}${self.e64(json.dumps(j))}")
|
||||
for key, value in np.items():
|
||||
v['vod_play_from'].append(key)
|
||||
v['vod_play_url'].append('#'.join(value))
|
||||
v['vod_play_from'] = '$$$'.join(v['vod_play_from'])
|
||||
v['vod_play_url'] = '$$$'.join(v['vod_play_url'])
|
||||
vod.update(v)
|
||||
vod.pop('vod_play_list', None)
|
||||
vod.pop('type', None)
|
||||
return {'list': [vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
data = self.fetch(f"{self.host}/api.php/zjv6.vod?page={pg}&limit=20&wd={key}", headers=self.getheader()).json()
|
||||
return {'list': data['data']['list'], 'page': pg}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
ids = json.loads(self.d64(id))
|
||||
target_url = ids['url']
|
||||
try:
|
||||
parse_str = ids.get('parse', '')
|
||||
if parse_str:
|
||||
parse_urls = parse_str.split(',')
|
||||
result_url = self.try_all_parses(parse_urls, target_url)
|
||||
if result_url:
|
||||
return {
|
||||
'parse': 0,
|
||||
'url': result_url,
|
||||
'header': {'User-Agent': 'dart:io'}
|
||||
}
|
||||
return {
|
||||
'parse': 1,
|
||||
'url': target_url,
|
||||
'header': {'User-Agent': 'dart:io'}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return {
|
||||
'parse': 1,
|
||||
'url': target_url,
|
||||
'header': {'User-Agent': 'dart:io'}
|
||||
}
|
||||
|
||||
def liveContent(self, url):
|
||||
pass
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def userinfo(self):
|
||||
t = str(int(time.time() * 1000))
|
||||
uid = self.generate_uid()
|
||||
sign = self.md5(f"appKey=3bbf7348cf314874883a18d6b6fcf67a&uid={uid}&time={t}")
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36',
|
||||
'Connection': 'Keep-Alive',
|
||||
'appKey': '3bbf7348cf314874883a18d6b6fcf67a',
|
||||
'uid': uid,
|
||||
'time': t,
|
||||
'sign': sign,
|
||||
}
|
||||
|
||||
params = {
|
||||
'access_token': '74d5879931b9774be10dee3d8c51008e',
|
||||
}
|
||||
|
||||
response = self.fetch('https://gitee.com/api/v5/repos/aycapp/openapi/contents/wawaconf.txt', params=params,
|
||||
headers=headers).json()
|
||||
data = json.loads(self.decrypt(response['content']))
|
||||
return data['baseUrl'], data['appKey'], data['appSecret']
|
||||
|
||||
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()
|
||||
|
||||
def generate_uid(self):
|
||||
return uuid.uuid4().hex
|
||||
|
||||
def getheader(self):
|
||||
t = str(int(time.time() * 1000))
|
||||
uid = self.generate_uid()
|
||||
sign = self.sign_message(f"appKey={self.appKey}&time={t}&uid={uid}")
|
||||
headers = {
|
||||
'User-Agent': 'okhttp/4.9.3',
|
||||
'Connection': 'Keep-Alive',
|
||||
'uid': uid,
|
||||
'time': t,
|
||||
'appKey': self.appKey,
|
||||
'sign': sign,
|
||||
}
|
||||
return headers
|
||||
|
||||
def decrypt(self, encrypted_data):
|
||||
key = b64decode('Crm4FXWkk5JItpYirFDpqg==')
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
encrypted = bytes.fromhex(self.d64(encrypted_data))
|
||||
decrypted = cipher.decrypt(encrypted)
|
||||
unpadded = unpad(decrypted, AES.block_size)
|
||||
return unpadded.decode('utf-8')
|
||||
|
||||
def sign_message(self, message):
|
||||
private_key_str = f"-----BEGIN PRIVATE KEY-----\n{self.rsakey}\n-----END PRIVATE KEY-----"
|
||||
private_key = RSA.import_key(private_key_str)
|
||||
message_hash = SHA256.new(message.encode('utf-8'))
|
||||
signature = pkcs1_15.new(private_key).sign(message_hash)
|
||||
signature_b64 = b64encode(signature).decode('utf-8')
|
||||
return signature_b64
|
||||
|
||||
def fetch_url(self, parse_url, target_url):
|
||||
try:
|
||||
response = self.fetch(f"{parse_url.replace('..', '.')}{target_url}",
|
||||
headers={"user-agent": "okhttp/4.1.0/luob.app"}, timeout=5)
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
data = response.json()
|
||||
result_url = data.get('url') or data.get('data', {}).get('url')
|
||||
if result_url:
|
||||
return result_url
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
def try_all_parses(self, parse_urls, target_url):
|
||||
with ThreadPoolExecutor(max_workers=(len(parse_urls))) as executor:
|
||||
future_to_url = {
|
||||
executor.submit(self.fetch_url, parse_url.strip(), target_url): parse_url
|
||||
for parse_url in parse_urls if parse_url.strip()
|
||||
}
|
||||
|
||||
for future in as_completed(future_to_url):
|
||||
try:
|
||||
result = future.result()
|
||||
if result:
|
||||
return result
|
||||
except:
|
||||
continue
|
||||
return None
|
||||
|
128
PY/好帅短剧.py
Normal file
128
PY/好帅短剧.py
Normal file
@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
import json
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
from pyquery import PyQuery as pq
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def action(self, action):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host='https://www.nhsyy.com'
|
||||
|
||||
headers = {
|
||||
'Accept': '*/*',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
'DNT': '1',
|
||||
'Origin': host,
|
||||
'Pragma': 'no-cache',
|
||||
'Referer': f'{host}/',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
||||
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="130", "Google Chrome";v="130"',
|
||||
'sec-ch-ua-mobile': '?1',
|
||||
'sec-ch-ua-platform': '"Android"',
|
||||
}
|
||||
|
||||
def homeContent(self, filter):
|
||||
data = pq(self.fetch(self.host, headers=self.headers).text)
|
||||
result = {}
|
||||
classes = []
|
||||
for i in data('.drop-content-items li').items():
|
||||
j = i('a').attr('href')
|
||||
if j and 'type' in j:
|
||||
id = j.split('/')[-1].split('.')[0]
|
||||
classes.append({
|
||||
'type_name': i('a').text(),
|
||||
'type_id': id
|
||||
})
|
||||
hlist = self.getlist(data('.module-lines-list .module-item'))
|
||||
result['class'] = classes
|
||||
result['list'] = hlist
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
pass
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
data = self.fetch(f'{self.host}/vodshwo/{tid}--------{pg}---.html', headers=self.headers).text
|
||||
vlist = self.getlist(pq(data)('.module-list .module-item'))
|
||||
return {"list": vlist, "page": pg, "pagecount": 9999, "limit": 90, "total": 999999}
|
||||
|
||||
def detailContent(self, ids):
|
||||
data = pq(self.fetch(f"{self.host}{ids[0]}", headers=self.headers).text)
|
||||
udata = data('.scroll-box-y .scroll-content a')
|
||||
vdata = data('.video-info-main .video-info-item')
|
||||
vod = {
|
||||
'vod_year': vdata.eq(2)('div').text(),
|
||||
'vod_remarks': vdata.eq(3)('div').text(),
|
||||
'vod_actor': vdata.eq(1)('a').text(),
|
||||
'vod_director': vdata.eq(0)('a').text(),
|
||||
'typt_name': data('.video-info-aux a').eq(0).attr('title'),
|
||||
'vod_content': vdata.eq(4)('p').eq(-1).text(),
|
||||
'vod_play_from': '嗷呜爱看短剧',
|
||||
'vod_play_url': '#'.join([f"{i.text()}${i.attr('href')}" for i in udata.items()]),
|
||||
}
|
||||
result = {"list": [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
dlist = self.fetch(f'{self.host}/vodsearch/{key}----------{pg}---.html', headers=self.headers).text
|
||||
ldata = pq(dlist)('.module-list .module-search-item')
|
||||
vlist = []
|
||||
for i in ldata.items():
|
||||
img = i('.module-item-pic')
|
||||
vlist.append({
|
||||
'vod_id': i('.video-serial').attr('href'),
|
||||
'vod_name': img('img').attr('alt'),
|
||||
'vod_pic': img('img').attr('data-src'),
|
||||
'vod_year': i('.tag-link a').eq(0).text(),
|
||||
'vod_remarks': i('.video-serial').text()
|
||||
})
|
||||
result = {"list": vlist, "page": pg}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
data=self.fetch(f"{self.host}{id}", headers=self.headers).text
|
||||
jstr = pq(data)('.player-wrapper script').eq(0).text()
|
||||
try:
|
||||
jdata = json.loads(jstr.split('=', 1)[-1])
|
||||
url = jdata.get('url') or jdata.get('next_url')
|
||||
p=0
|
||||
except:
|
||||
url,p = f"{self.host}{id}",1
|
||||
return {'parse': p, 'url': url, 'header': self.headers}
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def getlist(self, data):
|
||||
vlist = []
|
||||
for i in data.items():
|
||||
img = i('.module-item-pic')
|
||||
vlist.append({
|
||||
'vod_id': img('a').attr('href'),
|
||||
'vod_name': img('img').attr('alt'),
|
||||
'vod_pic': img('img').attr('data-src'),
|
||||
'vod_remarks': i('.module-item-text').text()
|
||||
})
|
||||
return vlist
|
166
PY/爱瓜(代理).py
Normal file
166
PY/爱瓜(代理).py
Normal file
@ -0,0 +1,166 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @嗷呜
|
||||
# 温馨提示:搜索只能搜拼音联想
|
||||
# 播放需要挂代理
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
from Crypto.Hash import MD5
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.uid = self.getuid()
|
||||
self.token, self.code = self.getuserinfo()
|
||||
pass
|
||||
|
||||
def getName(self):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
host = 'https://tvapi211.magicetech.com'
|
||||
|
||||
headers = {'User-Agent': 'okhttp/3.11.0'}
|
||||
|
||||
def homeContent(self, filter):
|
||||
body = {'token': self.token, 'authcode': self.code}
|
||||
data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/filter-header', json=self.getbody(body),
|
||||
headers=self.headers).json()
|
||||
result = {}
|
||||
classes = []
|
||||
filters = {}
|
||||
for k in data['data']:
|
||||
classes.append({
|
||||
'type_name': k['channel_name'],
|
||||
'type_id': str(k['channel_id']),
|
||||
})
|
||||
filters[str(k['channel_id'])] = []
|
||||
for i in k['search_box']:
|
||||
if len(i['list']):
|
||||
filters[str(k['channel_id'])].append({
|
||||
'key': i['field'],
|
||||
'name': i['label'],
|
||||
'value': [{'n': j['display'], 'v': str(j['value'])} for j in i['list'] if j['value']]
|
||||
})
|
||||
result['class'] = classes
|
||||
result['filters'] = filters
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
body = {'token': self.token, 'authcode': self.code}
|
||||
data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/index-tv', json=self.getbody(body),
|
||||
headers=self.headers).json()
|
||||
return {'list': self.getlist(data['data'][0]['banner'])}
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
body = {'token': self.token, 'authcode': self.code, 'channel_id': tid, 'area': extend.get('area', '0'),
|
||||
'year': extend.get('year', '0'), 'sort': extend.get('sort', '0'), 'tag': extend.get('tag', 'hot'),
|
||||
'status': extend.get('status', '0'), 'page_num': pg, 'page_size': '24'}
|
||||
data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/filter-video', json=self.getbody(body),
|
||||
headers=self.headers).json()
|
||||
result = {}
|
||||
result['list'] = self.getlist(data['data']['list'])
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, ids):
|
||||
ids = ids[0].split('@')
|
||||
body = {'token': self.token, 'authcode': self.code, 'channel_id': ids[0], 'video_id': ids[1]}
|
||||
data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/video/detail', json=self.getbody(body),
|
||||
headers=self.headers).json()
|
||||
vdata = {}
|
||||
for k in data['data']['chapters']:
|
||||
i = k['sourcelist']
|
||||
for j in i:
|
||||
if j['source_name'] not in vdata: vdata[j['source_name']] = []
|
||||
vdata[j['source_name']].append(f"{k['title']}${j['source_url']}")
|
||||
plist, names = [], []
|
||||
for key, value in vdata.items():
|
||||
names.append(key)
|
||||
plist.append('#'.join(value))
|
||||
vod = {
|
||||
'vod_play_from': '$$$'.join(names),
|
||||
'vod_play_url': '$$$'.join(plist),
|
||||
}
|
||||
return {'list': [vod]}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
body = {'token': self.token, 'authcode': self.code, 'keyword': key, 'page_num': pg}
|
||||
data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/search/letter-result', json=self.getbody(body),
|
||||
headers=self.headers).json()
|
||||
return {'list': self.getlist(data['data']['list'])}
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
# https://rysp.tv
|
||||
# https://aigua.tv
|
||||
result = {
|
||||
"parse": 0,
|
||||
"url": id,
|
||||
"header": {
|
||||
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)",
|
||||
"Origin": "https://aigua.tv",
|
||||
"Referer": "https://aigua.tv/"
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
pass
|
||||
|
||||
def getuserinfo(self):
|
||||
data = self.post(f'{self.host}/hr_1_1_0/apptvapi/web/index.php/user/auth-login', json=self.getbody(),
|
||||
headers=self.headers).json()
|
||||
v = data['data']
|
||||
return v['user_token'], v['authcode']
|
||||
|
||||
def getuid(self):
|
||||
uid = self.getCache('uid')
|
||||
if not uid:
|
||||
uid = str(uuid.uuid4())
|
||||
self.setCache('uid', uid)
|
||||
return uid
|
||||
|
||||
def getbody(self, json_data=None):
|
||||
if json_data is None: json_data = {}
|
||||
params = {"product": "4", "ver": "1.1.0", "debug": "1", "appId": "1", "osType": "3", "marketChannel": "tv",
|
||||
"sysVer": "11", "time": str(int(time.time())), "packageName": "com.gzsptv.gztvvideo",
|
||||
"udid": self.uid, }
|
||||
json_data.update(params)
|
||||
sorted_json = dict(sorted(json_data.items(), key=lambda item: item[0]))
|
||||
text = '&'.join(f"{k}={v}" for k, v in sorted_json.items() if v != '')
|
||||
md5_hash = self.md5(f"jI7POOBbmiUZ0lmi{text}D9ShYdN51ksWptpkTu11yenAJu7Zu3cR").upper()
|
||||
json_data.update({'sign': md5_hash})
|
||||
return json_data
|
||||
|
||||
def md5(self, text):
|
||||
h = MD5.new()
|
||||
h.update(text.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
|
||||
def getlist(self, data):
|
||||
videos = []
|
||||
for i in data:
|
||||
if type(i.get('video')) == dict: i = i['video']
|
||||
videos.append({
|
||||
'vod_id': f"{i.get('channel_id')}@{i.get('video_id')}",
|
||||
'vod_name': i.get('video_name'),
|
||||
'vod_pic': i.get('cover'),
|
||||
'vod_year': i.get('score'),
|
||||
'vod_remarks': i.get('flag'),
|
||||
})
|
||||
return videos
|
||||
|
Loading…
x
Reference in New Issue
Block a user