Sync all projects
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
{"spider":"","sites":[
|
||||
{"key":"py_douban","name":"🫧豆瓣|评分","type":3,"api":"./py/py_douban.py","searchable":0,"changeable":0},
|
||||
{"key":"py_cctv","name":"🫧央视|频道","type":3,"style":{"type":"rect","ratio":1.485},"api":"./py/py_cctv.py","searchable":1,"changeable":1},
|
||||
{"key":"py_1905","name":"🫧1905|直连","type":3,"api":"./py/m1905.py","searchable":1,"changeable":1},
|
||||
{"key":"py_live","name":"🫧视频|直播","type":3,"api":"./py/py_live.py","searchable":1,"changeable":0,"ext":{"url":"./py/json/live.json"}},
|
||||
{"key":"py_Alist","name":"🫧Alist|网盘","type":3,"api":"./py/py_alist.py","playerType":1,"searchable":1,"changeable":1,"ext":"./py/json/alist.json"},
|
||||
{"key":"py_czspp","name":"🫧厂长|直连","type":3,"api":"./py/py_czspp.py","searchable":1,"changeable":1},
|
||||
{"key":"py_cyys","name":"🫧创艺|直连","type":3,"api":"./py/py_cyys.py","searchable":1,"changeable":1},
|
||||
{"key":"py_xigua.py","name":"🫧西瓜|直连","type":3,"api":"./py/py_xigua.py","searchable":1,"changeable":1},
|
||||
{"key":"py_douyu","name":"🫧斗鱼|直播","type":3,"api":"./py/py_douyu.py","searchable":1,"changeable":1},
|
||||
{"key":"py_huya","name":"🫧虎牙|直播","type":3,"api":"./py/py_huya.py","searchable":1,"changeable":1},
|
||||
{"key":"py_bilimd","name":"🫧B站|番剧","type":3,"style":{"type":"rect","ratio":1.485},"api":"./py/py_bilibilimd.py","searchable":1,"changeable":1,"ext":{"cookie":"buvid3=8B57D3BA-607A-1E85-018A-E8C430023CED42659infoc; b_lsid=BEB8EE7F_18742FF8C2E; bsource=search_baidu; _uuid=DE810E367-B52C-AF6E-A612-EDF4C31567F358591infoc; b_nut=100; buvid_fp=711a632b5c876fa8bbcf668c1efba551; SESSDATA=7624af93%2C1696008331%2C862c8%2A42; bili_jct=141a474ef3ce8cf2fedf384e68f6625d; DedeUserID=3493271303096985; DedeUserID__ckMd5=212a836c164605b7; sid=5h4ruv6o; buvid4=978E9208-13DA-F87A-3DC0-0B8EDF46E80434329-123040301-dWliG5BMrUb70r3g583u7w%3D%3D"}},
|
||||
{"key":"py_bilibili","name":"🫧B站|视频","type":3,"api":"./py/py_bilibilivd.py","searchable":1,"changeable":1,"ext":{"json":"./py/json/bili.json"}},
|
||||
{"key":"py_freezb","name":"🫧体育|直播","type":3,"api":"./py/py_sport.py","searchable":0,"changeable":0},
|
||||
{"key":"py_firstaid","name":"🫧急救|教学","type":3,"api":"./py/py_firstaid.py","searchable":0,"changeable":0},
|
||||
|
||||
],"rules":[{"name":"一起看","hosts":["yqk88"],"regex":["18.4","15.1666"]},{"name":"小小","hosts":["aws.ulivetv.net"],"regex":["#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:8,[\\s\\S]*?#EXT-X-DISCONTINUITY"]},{"name":"索尼","hosts":["suonizy"],"regex":["15.1666","15.2666"]},{"name":"暴風","hosts":["bfzy"],"regex":["#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:3,[\\s\\S]*?#EXT-X-DISCONTINUITY"]},{"name":"星星","hosts":["aws.ulivetv.net"],"regex":["#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:8,[\\s\\S]*?#EXT-X-DISCONTINUITY"]},{"name":"量子","hosts":["vip.lz","hd.lz","v.cdnlz"],"regex":["18.5333"]},{"name":"非凡","hosts":["vip.ffzy","hd.ffzy"],"regex":["25.0666","25.08"]},{"name":"火山嗅探","hosts":["huoshan.com"],"regex":["item_id="]},{"name":"抖音嗅探","hosts":["douyin.com"],"regex":["is_play_url="]},{"name":"農民嗅探","hosts":["toutiaovod.com"],"regex":["video/tos/cn"]},{"name":"快看广告","hosts":["kuaikan"],"regex":["20.123","20.167"]}],"ads":["mozai.4gtv.tv"]}
|
||||
@@ -0,0 +1,210 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import re
|
||||
import math
|
||||
import json
|
||||
import time
|
||||
import hashlib
|
||||
import uuid
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "哔哩哔哩"
|
||||
def init(self,extend=""):
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电影": "n_1/o3p",
|
||||
"微电影": "n_1_c_922/o3p",
|
||||
"系列电影": "n_2/o3p",
|
||||
"记录片": "c_927/o3p",
|
||||
"晚会": "n_1_c_586/o3p",
|
||||
"独家": "n_1_c_178/o3p",
|
||||
"综艺": "n_1_c_1024/o3p",
|
||||
"体育": "n_1_c_1053/o3p"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name':k,
|
||||
'type_id':cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
url = 'https://www.1905.com/vod/cctv6/lst/'
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43',
|
||||
'Referer': 'https://www.1905.com/vod/list/n_1/o3p1.html',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
|
||||
}
|
||||
rsp = self.fetch(url, headers=headers)
|
||||
html = self.html(rsp.text)
|
||||
aList = html.xpath("//div[@class='grid-2x']/a")
|
||||
videos = []
|
||||
for a in aList:
|
||||
aid = a.xpath("./@href")[0] #https://www.1905.com/vod/play/85646.shtml
|
||||
if '//vip.1905.com' in str(aid):
|
||||
continue #跳过VIP视频
|
||||
aid = self.regStr(reg=r'play/(.*?).sh', src=aid) # 85646
|
||||
img = a.xpath('./img/@src')[0]
|
||||
title = a.xpath('./img/@alt')[0]
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": ''
|
||||
})
|
||||
result['list'] = videos
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
url = 'https://www.1905.com/vod/list/{}{}.html'.format(tid, pg)
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43',
|
||||
'Referer': 'https://www.1905.com/vod/list/n_1/o3p1.html',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
|
||||
}
|
||||
rsp = self.fetch(url, headers=headers)
|
||||
html = self.html(rsp.text)
|
||||
aList = html.xpath("//section[contains(@class,'search-list')]/div/a" if tid != u'n_2/o3p' else "//div[@class='mod']/div[1]/a")
|
||||
videos = []
|
||||
limit = len(aList)
|
||||
for a in aList:
|
||||
aid = a.xpath("./@href")[0] # https://www.1905.com/vod/play/85646.shtml
|
||||
aid = self.regStr(reg=r'play/(.*?).sh', src=aid) # 85646
|
||||
img = a.xpath('./img/@src')[0]
|
||||
title = a.xpath('./@title')[0]
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": ''
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 100
|
||||
result['limit'] = limit
|
||||
result['total'] = 100 * limit
|
||||
return result
|
||||
def detailContent(self,array):
|
||||
aid = array[0]
|
||||
url = "https://www.1905.com/api/content/?callback=&m=Vod&a=getVodSidebar&id={0}&fomat=json".format(aid)
|
||||
rsp = self.fetch(url)
|
||||
root = json.loads(rsp.text)
|
||||
title = root['title']
|
||||
pic = root['thumb']
|
||||
remark = root['commendreason']
|
||||
content = root['description']
|
||||
actor = root['starring']
|
||||
direct = root['direct']
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": "",
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": remark,
|
||||
"vod_actor": actor,
|
||||
"vod_director":direct,
|
||||
"vod_content": content
|
||||
}
|
||||
vodItems = []
|
||||
vodItems.append(title + "$" + aid)
|
||||
#处理多集的电影
|
||||
series = root['info']['series_data']
|
||||
for ser in series:
|
||||
vodItems.append(ser['title'] + "$" + ser['contentid'])
|
||||
playList = []
|
||||
joinStr = '#'.join(vodItems)
|
||||
playList.append(joinStr)
|
||||
vod['vod_play_from'] = '默认最高画质'
|
||||
vod['vod_play_url'] = '$$$'.join(playList)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def searchContent(self,key,quick):
|
||||
result = {}
|
||||
url = 'https://www.1905.com/search/index-p-type-all-q-{}.html'.format(key)
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43',
|
||||
'Referer': 'https://www.1905.com/vod/list/n_1/o3p1.html',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
|
||||
}
|
||||
rsp = self.fetch(url, headers=headers)
|
||||
html = self.html(rsp.text)
|
||||
aList = html.xpath("//div[contains(@class,'movie_box')]/div/div")
|
||||
videos = []
|
||||
for a in aList:
|
||||
aid = a.xpath("./div/ul/li[contains(@class,'paly-tab-icon')]/a/@href")[0] #https://www.1905.com/vod/play/85646.shtml
|
||||
if len(aid) == 0:
|
||||
continue
|
||||
aid = self.regStr(reg=r'play/(.*?).sh', src=aid) # 85646
|
||||
img = a.xpath('./div/div/a/img/@src')[0]
|
||||
title = a.xpath('./div/a/img/@alt')[0]
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": ''
|
||||
})
|
||||
result['list'] = videos
|
||||
return result
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
nonce = int(round(time.time() * 1000))
|
||||
expiretime = nonce + 600
|
||||
uid = str(uuid.uuid4())
|
||||
playerid = uid.replace("-", "")[5:20]
|
||||
signature = 'cid={0}&expiretime={1}&nonce={2}&page=https%3A%2F%2Fwww.1905.com%2Fvod%2Fplay%2F{3}.shtml&playerid={4}&type=hls&uuid={5}.dde3d61a0411511d'.format(id,expiretime,nonce,id,playerid,uid)
|
||||
signature = hashlib.sha1(signature.encode()).hexdigest()
|
||||
url = 'https://profile.m1905.com/mvod/getVideoinfo.php?nonce={0}&expiretime={1}&cid={2}&uuid={3}&playerid={4}&page=https%3A%2F%2Fwww.1905.com%2Fvod%2Fplay%2F{5}.shtml&type=hls&signature={6}&callback='.format(nonce,expiretime,id,uid,playerid,id,signature)
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43',
|
||||
'Referer': 'https://www.1905.com/vod/list/n_1/o3p1.html',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
|
||||
}
|
||||
rsp = self.fetch(url,headers=headers)
|
||||
jo = json.loads(rsp.text.replace("(", "").replace(")", ""))
|
||||
data = jo['data']['sign']
|
||||
sign = ''
|
||||
qualityStr = ''
|
||||
if 'uhd' in data.keys():
|
||||
sign = data['uhd']['sign']
|
||||
qualityStr = 'uhd'
|
||||
elif 'hd' in data.keys():
|
||||
sign = data['hd']['sign']
|
||||
qualityStr = 'hd'
|
||||
elif 'sd' in data.keys():
|
||||
sign = data['sd']['sign']
|
||||
qualityStr = 'sd'
|
||||
host = jo['data']['quality'][qualityStr]['host']
|
||||
path = jo['data']['path'][qualityStr]['path']
|
||||
playUrl = host + sign + path
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = playUrl
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,288 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
from os.path import splitext
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
alisttoken = ''
|
||||
def getName(self):
|
||||
return "Alist"
|
||||
|
||||
def init(self, extend):
|
||||
try:
|
||||
self.ext = extend
|
||||
except:
|
||||
self.ext = ''
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
if self.ext.startswith('http'):
|
||||
url = self.ext
|
||||
drivers = self.fetch(url, headers=self.header, timeout=5).json()['drives']
|
||||
else:
|
||||
drivers = json.loads(self.ext)['drives']
|
||||
classes = []
|
||||
for driver in drivers:
|
||||
if 'hidden' in driver and driver['hidden']:
|
||||
continue
|
||||
tid = driver['server']
|
||||
if 'login' in driver:
|
||||
tid = tid + '&&&login' + json.dumps(driver['login'], ensure_ascii=False)
|
||||
if 'params' in driver:
|
||||
tid = tid + '&&¶ms' + json.dumps(driver['params'], ensure_ascii=False)
|
||||
classes.append({
|
||||
'type_name': driver['name'],
|
||||
'type_id': tid
|
||||
})
|
||||
result['class'] = classes
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def categoryContent(self, cid, page, filter, ext):
|
||||
result = {}
|
||||
login = {}
|
||||
params = []
|
||||
password = ''
|
||||
if '&&&' in cid:
|
||||
cidList = cid.split('&&&')
|
||||
url = cidList[0]
|
||||
for cL in cidList:
|
||||
if cL.startswith('login'):
|
||||
login = json.loads(cL.replace('login', ''))
|
||||
elif cL.startswith('params'):
|
||||
params = json.loads(cL.replace('params', ''))
|
||||
else:
|
||||
url = cid
|
||||
if url.count('/') == 2:
|
||||
url = url + '/'
|
||||
header = self.header.copy()
|
||||
baseUrl = self.getCache('baseUrl')
|
||||
if not baseUrl:
|
||||
baseUrl = self.regStr(reg="(http.*://.*?/)", src=url)
|
||||
header['Referer'] = baseUrl
|
||||
token = self.getCache('token')
|
||||
if token:
|
||||
token = token['token']
|
||||
else:
|
||||
data = self.postJson(baseUrl + 'api/auth/login', json=login, headers=header).json()
|
||||
if data['code'] == 200:
|
||||
token = data['data']['token']
|
||||
self.setCache('token', {'token': token, 'expiresAt': int(time.time()) + 86400})
|
||||
header['Authorization'] = token
|
||||
path = '/' + url.replace(baseUrl, "")
|
||||
for param in params:
|
||||
if param['path'].startswith(path) and 'pass' in param:
|
||||
password = param['pass']
|
||||
break
|
||||
param = {
|
||||
"path": path,
|
||||
'password': password
|
||||
}
|
||||
data = self.postJson(baseUrl + 'api/fs/list', json=param, headers=header).json()
|
||||
vodList = data['data']['content']
|
||||
videos = []
|
||||
subtList = []
|
||||
playList = []
|
||||
for vod in vodList:
|
||||
if len(vod['thumb']) == 0:
|
||||
img = "https://api-lmteam.koyeb.app/files/alist.png"
|
||||
elif vod['thumb'].startswith('http'):
|
||||
img = vod['thumb']
|
||||
else:
|
||||
img = baseUrl.strip('/') + vod['thumb']
|
||||
if path != '/':
|
||||
aid = path.strip('/') + '/'
|
||||
else:
|
||||
aid = path.strip('/')
|
||||
if vod['type'] == 1:
|
||||
tag = "folder"
|
||||
remark = "文件夹"
|
||||
cid = baseUrl + aid + vod['name']
|
||||
else:
|
||||
if splitext(vod['name'])[1] in ['.mp4', '.mpg', '.mkv', '.ts', '.TS', '.avi', '.flv', '.rmvb', '.mp3', '.flac', '.wav', '.wma', '.dff']:
|
||||
size = self.getSize(vod['size'])
|
||||
tag = "file"
|
||||
remark = size
|
||||
cid = baseUrl + aid + vod['name']
|
||||
playList.append(vod['name'])
|
||||
elif splitext(vod['name'])[1] in ['.ass', '.ssa', '.srt']:
|
||||
cid = baseUrl + aid + vod['name']
|
||||
subtList.append(vod['name'])
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
if login != {}:
|
||||
cid = cid + '&&&login' + json.dumps(login, ensure_ascii=False)
|
||||
elif params != []:
|
||||
cid = cid + '&&¶ms' + json.dumps(params, ensure_ascii=False)
|
||||
videos.append({
|
||||
"vod_id": cid,
|
||||
"vod_name": vod['name'],
|
||||
"vod_pic": img,
|
||||
"vod_tag": tag,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
if playList != []:
|
||||
cid = baseUrl + aid
|
||||
for pL in playList:
|
||||
cid = cid + '!!!' + pL
|
||||
if login != {}:
|
||||
cid = cid + '&&&login' + json.dumps(login, ensure_ascii=False)
|
||||
elif params != []:
|
||||
cid = cid + '&&¶ms' + json.dumps(params, ensure_ascii=False)
|
||||
videos.insert(0, {
|
||||
"vod_id": cid,
|
||||
"vod_name": '播放列表',
|
||||
"vod_pic": "https://avatars.githubusercontent.com/u/97389433?s=200&v=4",
|
||||
"vod_tag": 'file',
|
||||
"vod_remarks": path
|
||||
})
|
||||
if subtList != []:
|
||||
self.setCache(f"subtList_{cid[:cid.rfind('/')]}", {'subtList': subtList, 'expiresAt': int(time.time()) + 86400})
|
||||
result['list'] = videos
|
||||
result['page'] = 1
|
||||
result['pagecount'] = 1
|
||||
result['limit'] = len(videos)
|
||||
result['total'] = len(videos)
|
||||
return result
|
||||
|
||||
def detailContent(self, did):
|
||||
did = did[0]
|
||||
if '&&&' in did:
|
||||
pos = did.index('&&&')
|
||||
url = did[:pos]
|
||||
append = did[pos:]
|
||||
else:
|
||||
url = did
|
||||
append = ''
|
||||
name = url[url.strip('/').rfind('/') + 1:].strip('/')
|
||||
if '!!!' in url:
|
||||
urls = url.split('!!!')
|
||||
fileList = urls[1:]
|
||||
url = urls[0]
|
||||
playUrl = ''
|
||||
for file in fileList:
|
||||
playUrl += file + '$' + url + file + append + '#'
|
||||
else:
|
||||
playUrl = name + '$' + did
|
||||
name = did[did.rfind('/') + 1:]
|
||||
if '&&&' in name:
|
||||
name = name.split('&&&')[0]
|
||||
vod = {
|
||||
"vod_id": did,
|
||||
"vod_name": name,
|
||||
"vod_play_from": "Alist网盘",
|
||||
"vod_play_url": playUrl.strip('#')
|
||||
}
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
return self.searchContentPage(key, quick, '1')
|
||||
|
||||
def searchContentPage(self, key, quick, page):
|
||||
result = {'list': []}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, pid, vipFlags):
|
||||
result = {}
|
||||
purl = self.getDownloadUrl(pid)
|
||||
if '&&&' in pid:
|
||||
append = pid[pid.index('&&&'):]
|
||||
else:
|
||||
append = ''
|
||||
url = pid[:pid.rfind('/')]
|
||||
data = self.getCache(f'subtList_{url}')
|
||||
subs = []
|
||||
if data:
|
||||
subList = data['subtList']
|
||||
for sub in subList:
|
||||
subformat = os.path.splitext(sub)[1]
|
||||
if subformat == '.srt':
|
||||
sformat = 'application/x-subrip'
|
||||
elif subformat == '.ass':
|
||||
sformat = 'application/x-subtitle-ass'
|
||||
elif subformat == '.ssa':
|
||||
sformat = 'text/x-ssa'
|
||||
else:
|
||||
sformat = 'text/plain'
|
||||
surl = url + '/' + sub
|
||||
subs.append(f'http://127.0.0.1:UndCover/proxy?do=py&type=sub&url={surl}&sformat={sformat}')
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = purl
|
||||
result["header"] = ''
|
||||
result["subs"] = subs
|
||||
return result
|
||||
|
||||
def getSize(self, size):
|
||||
if size > 1024 * 1024 * 1024 * 1024.0:
|
||||
fs = "TB"
|
||||
sz = round(size / (1024 * 1024 * 1024 * 1024.0), 2)
|
||||
elif size > 1024 * 1024 * 1024.0:
|
||||
fs = "GB"
|
||||
sz = round(size / (1024 * 1024 * 1024.0), 2)
|
||||
elif size > 1024 * 1024.0:
|
||||
fs = "MB"
|
||||
sz = round(size / (1024 * 1024.0), 2)
|
||||
elif size > 1024.0:
|
||||
fs = "KB"
|
||||
sz = round(size / (1024.0), 2)
|
||||
else:
|
||||
fs = "KB"
|
||||
sz = round(size / (1024.0), 2)
|
||||
return str(sz) + fs
|
||||
|
||||
def localProxy(self, params):
|
||||
url = self.getDownloadUrl(params['url'])
|
||||
baseUrl = self.getCache('baseUrl')
|
||||
if not baseUrl:
|
||||
baseUrl = self.regStr(reg="(http.*://.*?/)", src=params['url'])
|
||||
header = self.header.copy()
|
||||
header['Referer'] = baseUrl
|
||||
content = self.fetch(url, headers=header).content.decode()
|
||||
contentTyep = params['sformat']
|
||||
action = {'url': '', 'header': header, 'param': '', 'type': 'string'}
|
||||
return [200, contentTyep, action, content]
|
||||
|
||||
def getDownloadUrl(self, url):
|
||||
params = []
|
||||
password = ''
|
||||
if '&&&' in url:
|
||||
urlList = url.split('&&&')
|
||||
url = urlList[0]
|
||||
for uL in urlList:
|
||||
if uL.startswith('login'):
|
||||
login = json.loads(uL.replace('login', ''))
|
||||
elif uL.startswith('params'):
|
||||
params = json.loads(uL.replace('params', ''))
|
||||
if url.count('/') == 2:
|
||||
url = url + '/'
|
||||
header = self.header.copy()
|
||||
baseUrl = self.getCache('baseUrl')
|
||||
if not baseUrl:
|
||||
baseUrl = self.regStr(reg="(http.*://.*?/)", src=url)
|
||||
header['Referer'] = baseUrl
|
||||
token = self.getCache('token')
|
||||
if token:
|
||||
token = token['token']
|
||||
else:
|
||||
data = self.postJson(baseUrl + 'api/auth/
|
||||
@@ -0,0 +1,2975 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import sys, os, json
|
||||
from base.spider import Spider
|
||||
from requests import session, utils, get as requests_get
|
||||
from requests.adapters import HTTPAdapter, Retry
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
import threading
|
||||
import hashlib
|
||||
import time
|
||||
import random
|
||||
import base64
|
||||
from functools import reduce
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
sys.path.append('..')
|
||||
dirname, filename = os.path.split(os.path.abspath(__file__))
|
||||
sys.path.append(dirname)
|
||||
|
||||
class Spider(Spider):
|
||||
#默认设置
|
||||
defaultConfig = {
|
||||
'currentVersion': "20231213_1",
|
||||
#【建议通过扫码确认】设置Cookie,在双引号内填写
|
||||
'raw_cookie_line': "",
|
||||
#如果主cookie没有vip,可以设置第二cookie,仅用于播放会员番剧,所有的操作、记录还是在主cookie,不会同步到第二cookie
|
||||
'raw_cookie_vip': "",
|
||||
#主页默认显示3图
|
||||
'maxHomeVideoContent': '3',
|
||||
#收藏标签默认显示追番1,追剧2,默认收藏夹0
|
||||
'favMode': '0',
|
||||
#部分视频列表分页,限制每次加载数量
|
||||
'page_size': 12,
|
||||
#上传播放进度间隔时间,单位秒,b站默认间隔15,0则不上传播放历史
|
||||
'heartbeatInterval': '15',
|
||||
#视频默认画质ID
|
||||
'vodDefaultQn': '80',
|
||||
#视频默认解码ID
|
||||
'vodDefaultCodec': '7',
|
||||
#音频默认码率ID
|
||||
'vodDefaultAudio': '30280',
|
||||
#获取视频热门评论
|
||||
'show_vod_hot_reply': True,
|
||||
#从正片中拆分出番剧的预告
|
||||
'hide_bangumi_preview': True,
|
||||
#登陆会员账号后,影视播放页不显示会员专享的标签,更简洁
|
||||
'hide_bangumi_vip_badge': True,
|
||||
#番剧(热门)列表使用横图
|
||||
'bangumi_horizontal_cover': True,
|
||||
#非会员播放会员专享视频时,添加一个页面可以使用解析源,解析源自行解决
|
||||
'bangumi_vip_parse': True,
|
||||
#付费视频添加一个页面可以使用解析,解析源自行解决
|
||||
'bangumi_pay_parse': True,
|
||||
#是否显示直播标签筛选中分区的细化标签, 0为不显示,1为显示
|
||||
'showLiveFilterTag': '0',
|
||||
#主页标签排序, 未登录或cookie失效时自动隐藏动态、收藏、关注、历史
|
||||
'cateManual': [
|
||||
"推荐",
|
||||
"影视",
|
||||
"直播",
|
||||
"动态",
|
||||
"频道",
|
||||
"收藏",
|
||||
"关注",
|
||||
"历史",
|
||||
"搜索",
|
||||
],
|
||||
#自定义推荐标签的筛选
|
||||
'tuijianLis': [
|
||||
"热门",
|
||||
"排行榜",
|
||||
"每周必看",
|
||||
"入站必刷",
|
||||
"番剧时间表",
|
||||
"国创时间表"
|
||||
],
|
||||
'rankingLis': [
|
||||
"动画",
|
||||
"音乐",
|
||||
"舞蹈",
|
||||
"游戏",
|
||||
"鬼畜",
|
||||
"知识",
|
||||
"科技",
|
||||
"运动",
|
||||
"生活",
|
||||
"美食",
|
||||
"动物",
|
||||
"汽车",
|
||||
"时尚",
|
||||
"娱乐",
|
||||
"影视",
|
||||
"原创",
|
||||
"新人",
|
||||
],
|
||||
}
|
||||
|
||||
#在动态标签的筛选中固定显示他,n为用户名或任意都可以,v必须为准确的UID
|
||||
focus_on_up_list = [
|
||||
#{"n":"徐云流浪中国", "v":"697166795"},
|
||||
]
|
||||
|
||||
#在搜索标签的筛选中固定显示搜索词
|
||||
focus_on_search_key = []
|
||||
|
||||
def getName(self):
|
||||
return "哔哩哔哩"
|
||||
|
||||
def load_config(self):
|
||||
try:
|
||||
with open(f"{self.configdir}/config.json",encoding="utf-8") as f:
|
||||
self.userConfig = json.load(f)
|
||||
old_config = {
|
||||
'master': 'cookie_dic',
|
||||
'vip': 'cookie_vip_dic',
|
||||
'fake': 'cookie_fake_dic',
|
||||
}
|
||||
for _type, old in old_config.items():
|
||||
old = self.userConfig.get(old)
|
||||
if old:
|
||||
if not self.userConfig.get('users'):
|
||||
self.userConfig['users'] = {}
|
||||
self.userConfig['users'][_type] = {'cookies_dic': old}
|
||||
users = self.userConfig.get('users', {})
|
||||
if users.get('master') and users['master'].get('cookies_dic'):
|
||||
self.session_master.cookies = utils.cookiejar_from_dict(users['master']['cookies_dic'])
|
||||
self.userid = users['master']['userid']
|
||||
if users.get('fake') and users['fake'].get('cookies_dic'):
|
||||
self.session_fake.cookies = utils.cookiejar_from_dict(users['fake']['cookies_dic'])
|
||||
except:
|
||||
self.userConfig = {}
|
||||
self.userConfig = {**self.defaultConfig, **self.userConfig}
|
||||
|
||||
dump_config_lock = threading.Lock()
|
||||
|
||||
def dump_config(self):
|
||||
needSaveConfig = ['users', 'channel_list', 'cateLive', 'cateManualLive', 'cateManualLiveExtra']
|
||||
userConfig_new = {}
|
||||
for key, value in self.userConfig.items():
|
||||
dafalutValue = self.defaultConfig.get(key)
|
||||
if dafalutValue != None and value != dafalutValue or key in needSaveConfig:
|
||||
userConfig_new[key] = value
|
||||
self.dump_config_lock.acquire()
|
||||
with open(f"{self.configdir}/config.json", 'w', encoding="utf-8") as f:
|
||||
data = json.dumps(userConfig_new, indent=1, ensure_ascii=False)
|
||||
f.write(data)
|
||||
self.dump_config_lock.release()
|
||||
|
||||
pool = ThreadPoolExecutor(max_workers=8)
|
||||
task_pool = []
|
||||
# 主页
|
||||
def homeContent(self, filter):
|
||||
self.pool.submit(self.add_live_filter)
|
||||
self.pool.submit(self.add_channel_filter)
|
||||
self.pool.submit(self.add_search_key)
|
||||
self.pool.submit(self.add_focus_on_up_filter)
|
||||
self.pool.submit(self.get_tuijian_filter)
|
||||
self.pool.submit(self.add_fav_filter)
|
||||
#self.pool.submit(self.homeVideoContent)
|
||||
needLogin = ['频道', '动态', '收藏', '关注', '历史']
|
||||
cateManual = self.userConfig['cateManual']
|
||||
if not self.userid and not 'UP' in cateManual or not '动态' in cateManual and not 'UP' in cateManual:
|
||||
cateManual += ['UP']
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
if k in needLogin and not self.userid:
|
||||
continue
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': k
|
||||
})
|
||||
self.add_focus_on_up_filter_event.wait()
|
||||
if 'UP' in cateManual:
|
||||
self.config["filter"].update({'UP': self.config["filter"].pop('动态')})
|
||||
result = {'class': classes}
|
||||
self.add_live_filter_event.wait()
|
||||
self.add_channel_filter_event.wait()
|
||||
self.add_fav_filter_event.wait()
|
||||
self.add_search_key_event.wait()
|
||||
if filter:
|
||||
result['filters'] = self.config['filter']
|
||||
self.pool.submit(self.dump_config)
|
||||
return result
|
||||
|
||||
# 用户cookies
|
||||
userid = csrf = ''
|
||||
session_master = session()
|
||||
session_vip = session()
|
||||
session_fake = session()
|
||||
con = threading.Condition()
|
||||
getCookie_event = threading.Event()
|
||||
retries = Retry(total=5,
|
||||
#status_forcelist=[ 500, 502, 503, 504 ],
|
||||
backoff_factor=0.1)
|
||||
adapter = HTTPAdapter(max_retries=retries)
|
||||
session_master.mount('https://', adapter)
|
||||
session_vip.mount('https://', adapter)
|
||||
session_fake.mount('https://', adapter)
|
||||
|
||||
def getCookie_dosth(self, co):
|
||||
c = co.strip().split('=', 1)
|
||||
if not '%' in c[1]:
|
||||
c[1] = quote(c[1])
|
||||
return c
|
||||
|
||||
def getCookie(self, _type='master'):
|
||||
raw_cookie = 'raw_cookie_line'
|
||||
if _type == 'vip':
|
||||
raw_cookie = 'raw_cookie_vip'
|
||||
raw_cookie = self.userConfig.get(raw_cookie)
|
||||
users = self.userConfig.get('users', {})
|
||||
user = users.get(_type, {})
|
||||
if not raw_cookie and not user:
|
||||
if _type == 'master':
|
||||
self.getCookie_event.set()
|
||||
with self.con:
|
||||
self.con.notifyAll()
|
||||
return
|
||||
cookies_dic = user.get('cookies_dic', {})
|
||||
if raw_cookie:
|
||||
cookies_dic = dict(map(self.getCookie_dosth, raw_cookie.split(';')))
|
||||
cookies = utils.cookiejar_from_dict(cookies_dic)
|
||||
url = 'https://api.bilibili.com/x/web-interface/nav'
|
||||
content = self.fetch(url, headers=self.header, cookies=cookies)
|
||||
res = json.loads(content.text)
|
||||
user['isLogin'] = 0
|
||||
if res["code"] == 0:
|
||||
user['isLogin'] = 1
|
||||
user['userid'] = res["data"]['mid']
|
||||
user['face'] = res['data']['face']
|
||||
user['uname'] = res['data']['uname']
|
||||
user['cookies_dic'] = cookies_dic
|
||||
user['isVIP'] = int(res['data']['vipStatus'])
|
||||
if _type == 'master':
|
||||
self.session_master.cookies = cookies
|
||||
self.userid = user['userid']
|
||||
self.csrf = cookies_dic['bili_jct']
|
||||
if user['isVIP']:
|
||||
self.session_vip.cookies = cookies
|
||||
else:
|
||||
self.userid = ''
|
||||
users[_type] = user
|
||||
with self.con:
|
||||
if len(user) > 1:
|
||||
self.userConfig.update({'users': users})
|
||||
if _type == 'master':
|
||||
self.getCookie_event.set()
|
||||
|
||||
getFakeCookie_event = threading.Event()
|
||||
|
||||
def getFakeCookie(self, fromSearch=None):
|
||||
if self.session_fake.cookies:
|
||||
self.getFakeCookie_event.set()
|
||||
header = {}
|
||||
header['User-Agent'] = self.header['User-Agent']
|
||||
rsp = self.fetch('https://space.bilibili.com/2/video', headers=header)
|
||||
self.session_fake.cookies = rsp.cookies
|
||||
self.getFakeCookie_event.set()
|
||||
with self.con:
|
||||
users = self.userConfig.get('users', {})
|
||||
users['fake'] = {'cookies_dic': dict(rsp.cookies)}
|
||||
self.userConfig.update({'users': users})
|
||||
if not fromSearch:
|
||||
self.getCookie_event.wait()
|
||||
if not self.session_master.cookies:
|
||||
self.session_master.cookies = rsp.cookies
|
||||
|
||||
def get_fav_list_dict(self, fav):
|
||||
fav_dict = {
|
||||
'n': fav['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""",'"').strip(),
|
||||
'v': fav['id']}
|
||||
return fav_dict
|
||||
|
||||
add_fav_filter_event = threading.Event()
|
||||
|
||||
def add_fav_filter(self):
|
||||
users = self.userConfig.get('users', {})
|
||||
if users.get('master') and users['master'].get('userid'):
|
||||
userid = self.userConfig['users']['master']['userid']
|
||||
else:
|
||||
self.getCookie_event.wait()
|
||||
userid = self.userid
|
||||
fav_list = []
|
||||
if userid:
|
||||
url = 'https://api.bilibili.com/x/v3/fav/folder/created/list-all?up_mid=%s&jsonp=jsonp' % str(userid)
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0 and jo.get('data'):
|
||||
fav = jo['data'].get('list')
|
||||
fav_list = list(map(self.get_fav_list_dict, fav))
|
||||
fav_top = [{"n": "追番", "v": "1"},{"n": "追剧", "v": "2"}]
|
||||
fav_config = self.config["filter"].get('收藏')
|
||||
if fav_config:
|
||||
fav_config.insert(0, {
|
||||
"key": "mlid",
|
||||
"name": "分区",
|
||||
"value": fav_top + fav_list,
|
||||
})
|
||||
self.add_fav_filter_event.set()
|
||||
self.userConfig["fav_list"] = fav_list
|
||||
|
||||
def get_channel_list_dict(self, channel):
|
||||
channel_dict = {
|
||||
'n': channel['name'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""",'"').strip(),
|
||||
'v': channel['id']}
|
||||
return channel_dict
|
||||
|
||||
def get_channel_list(self):
|
||||
url = 'https://api.bilibili.com/x/web-interface/web/channel/category/channel/list?id=100&offset=0&page_size=15'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
channel_list = []
|
||||
if jo['code'] == 0:
|
||||
channel = jo['data'].get('channels')
|
||||
self.userConfig['channel_list'] = list(map(self.get_channel_list_dict, channel))
|
||||
return self.userConfig['channel_list']
|
||||
|
||||
add_channel_filter_event = threading.Event()
|
||||
|
||||
def add_channel_filter(self):
|
||||
channel_list = self.userConfig.get('channel_list', '')
|
||||
channel_list_task = self.pool.submit(self.get_channel_list)
|
||||
if not channel_list:
|
||||
channel_list = channel_list_task.result()
|
||||
channel_config = self.config["filter"].get('频道', [])
|
||||
if channel_config:
|
||||
channel_config.insert(0, {
|
||||
"key": "cid",
|
||||
"name": "分区",
|
||||
"value": channel_list,
|
||||
})
|
||||
self.config["filter"]['频道'] = channel_config
|
||||
self.add_channel_filter_event.set()
|
||||
|
||||
add_focus_on_up_filter_event = threading.Event()
|
||||
|
||||
def add_focus_on_up_filter(self):
|
||||
first_list = [{"n": "上个视频的UP主", "v": "上个视频的UP主"}]
|
||||
up_list = self.focus_on_up_list
|
||||
if not self.session_master.cookies:
|
||||
self.getCookie_event.wait()
|
||||
focus_on_up_list_mid = list(map(lambda x: x['v'], up_list))
|
||||
if self.session_master.cookies:
|
||||
url = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=video&page=1'
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0 and jo.get('data'):
|
||||
up = jo['data'].get('items', [])
|
||||
for u in map(lambda x: {'n': x['modules']["module_author"]['name'], 'v': str(x['modules']["module_author"]['mid'])}, up):
|
||||
if not u in up_list and not u['v'] in focus_on_up_list_mid:
|
||||
up_list.append(u)
|
||||
last_list = [{"n": "登录与设置", "v": "登录"}]
|
||||
if not self.isFongmi:
|
||||
up_list = first_list + up_list
|
||||
up_list += last_list
|
||||
dynamic_config = self.config["filter"].get('动态', [])
|
||||
if dynamic_config:
|
||||
dynamic_config.insert(0, {
|
||||
"key": "mid",
|
||||
"name": "UP主",
|
||||
"value": up_list,
|
||||
})
|
||||
self.config["filter"]['动态'] = dynamic_config
|
||||
self.add_focus_on_up_filter_event.set()
|
||||
|
||||
def get_live_parent_area_list(self, parent_area):
|
||||
name = parent_area['name']
|
||||
id = str(parent_area['id'])
|
||||
area = parent_area['list']
|
||||
area_dict = list(map(lambda area: {'n': area['name'], 'v': str(area['parent_id']) + '_' + str(area['id'])}, area))
|
||||
live_area = {'key': 'tid', 'name': name, 'value': area_dict}
|
||||
cateLive_name = {'id': id + '_0', 'value': live_area}
|
||||
return (name, cateLive_name)
|
||||
|
||||
def get_live_list(self):
|
||||
url = 'https://api.live.bilibili.com/xlive/web-interface/v1/index/getWebAreaList?source_id=2'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
cateLive = {}
|
||||
if jo['code'] == 0:
|
||||
parent = jo['data']['data']
|
||||
self.userConfig['cateLive'] = dict(self.pool.map(self.get_live_parent_area_list, parent))
|
||||
return self.userConfig['cateLive']
|
||||
|
||||
def set_default_cateManualLive(self):
|
||||
cateManualLive = [{'n': '推荐', 'v': '推荐'},]
|
||||
for name in self.userConfig['cateLive']:
|
||||
area_dict = {'n': name, 'v': self.userConfig['cateLive'][name]['id']}
|
||||
cateManualLive.append(area_dict)
|
||||
self.defaultConfig['cateManualLive'] = cateManualLive
|
||||
return cateManualLive
|
||||
|
||||
add_live_filter_event = threading.Event()
|
||||
|
||||
def add_live_filter(self):
|
||||
cateLive = self.userConfig.get('cateLive', {})
|
||||
cateLive_task = self.pool.submit(self.get_live_list)
|
||||
if not cateLive:
|
||||
cateLive = cateLive_task.result()
|
||||
default_cateManualLive_task = self.pool.submit(self.set_default_cateManualLive)
|
||||
self.config["filter"]['直播'] = []
|
||||
#分区栏
|
||||
cateManualLive = self.userConfig.get('cateManualLive', [])
|
||||
if not cateManualLive:
|
||||
cateManualLive = default_cateManualLive_task.result()
|
||||
if cateManualLive:
|
||||
live_area = {'key': 'tid', 'name': '分区', 'value': cateManualLive}
|
||||
self.config["filter"]['直播'].append(live_area)
|
||||
#显示分区细分
|
||||
if int(self.userConfig['showLiveFilterTag']):
|
||||
for name in cateLive.values():
|
||||
if len(name['value']['value']) == 1:
|
||||
continue
|
||||
self.config["filter"]['直播'].append(name['value'])
|
||||
self.add_live_filter_event.set()
|
||||
|
||||
add_search_key_event = threading.Event()
|
||||
|
||||
def add_search_key(self):
|
||||
focus_on_search_key = self.focus_on_search_key
|
||||
url = 'https://api.bilibili.com/x/web-interface/search/square?limit=10&platform=web'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
cateLive = {}
|
||||
if jo['code'] == 0:
|
||||
trending = jo['data']['trending'].get('list', [])
|
||||
focus_on_search_key += list(map(lambda x:x['keyword'], trending))
|
||||
keyword = {"key": "keyword", "name": "搜索词","value": []}
|
||||
keyword["value"] = list(map(lambda i: {'n': i, 'v': i}, focus_on_search_key))
|
||||
self.config["filter"]['搜索'].insert(0, keyword)
|
||||
self.add_search_key_event.set()
|
||||
|
||||
def get_tuijian_filter(self):
|
||||
tuijian_filter = {"番剧时间表": "10001", "国创时间表": "10004", "排行榜": "0", "动画": "1", "音乐": "3", "舞蹈": "129", "游戏": "4", "鬼畜": "119", "知识": "36", "科技": "188", "运动": "234", "生活": "160", "美食": "211", "动物": "217", "汽车": "223", "时尚": "155", "娱乐": "5", "影视": "181", "原创": "origin", "新人": "rookie"}
|
||||
_dic = [{'n': 'tuijianLis', 'v': '分区'}, {'n': 'rankingLis', 'v': '排行榜'}]
|
||||
filter_lis = []
|
||||
for d in _dic:
|
||||
_filter = {"key": "tid" ,'name': d['v'],"value": []}
|
||||
t_lis = self.userConfig.get(d['n'], [])
|
||||
for t in t_lis:
|
||||
tf = tuijian_filter.get(t)
|
||||
if not tf:
|
||||
tf = t
|
||||
tf_dict = {'n': t, 'v': tf}
|
||||
_filter["value"].append(tf_dict)
|
||||
filter_lis.append(_filter)
|
||||
self.config["filter"]['推荐'] = filter_lis
|
||||
|
||||
isFongmi = False
|
||||
|
||||
def __init__(self):
|
||||
self.configdir = dirname
|
||||
if dirname.startswith('/data/'):
|
||||
self.isFongmi = True
|
||||
configdir = os.path.abspath(os.path.join(dirname, ".."))
|
||||
configdir = os.path.abspath(os.path.join(configdir, ".."))
|
||||
self.configdir = f"{configdir}/files"
|
||||
self.load_config()
|
||||
self.pool.submit(self.getCookie)
|
||||
self.pool.submit(self.getFakeCookie)
|
||||
self.pool.submit(self.getCookie, 'vip')
|
||||
wts = round(time.time())
|
||||
self.pool.submit(self.get_wbiKey, wts)
|
||||
|
||||
def init(self, extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
# 降低内存占用
|
||||
def format_img(self, img):
|
||||
img += "@672w_378h_1c.webp"
|
||||
if not img.startswith('http'):
|
||||
img = 'https:' + img
|
||||
return img
|
||||
|
||||
def pagination(self, array, pg):
|
||||
max_number = self.userConfig['page_size'] * int(pg)
|
||||
min_number = max_number - self.userConfig['page_size']
|
||||
return array[min_number:max_number]
|
||||
|
||||
# 将超过10000的数字换成成以万和亿为单位
|
||||
def zh(self, num):
|
||||
if int(num) >= 100000000:
|
||||
p = round(float(num) / float(100000000), 1)
|
||||
p = str(p) + '亿'
|
||||
else:
|
||||
if int(num) >= 10000:
|
||||
p = round(float(num) / float(10000), 1)
|
||||
p = str(p) + '万'
|
||||
else:
|
||||
p = str(num)
|
||||
return p
|
||||
|
||||
# 将秒数转化为 时分秒的格式
|
||||
def second_to_time(self, a):
|
||||
a = int(a)
|
||||
if a < 3600:
|
||||
result = time.strftime("%M:%S", time.gmtime(a))
|
||||
else:
|
||||
result = time.strftime("%H:%M:%S", time.gmtime(a))
|
||||
if str(result).startswith('0'):
|
||||
result = str(result).replace('0', '', 1)
|
||||
return result
|
||||
|
||||
# 字符串时分秒以及分秒形式转换成秒
|
||||
def str2sec(self, x):
|
||||
x = str(x)
|
||||
try:
|
||||
h, m, s = x.strip().split(':') # .split()函数将其通过':'分隔开,.strip()函数用来除去空格
|
||||
return int(h) * 3600 + int(m) * 60 + int(s) # int()函数转换成整数运算
|
||||
except:
|
||||
m, s = x.strip().split(':') # .split()函数将其通过':'分隔开,.strip()函数用来除去空格
|
||||
return int(m) * 60 + int(s) # int()函数转换成整数运算
|
||||
|
||||
# 按时间过滤
|
||||
def filter_duration(self, vodlist, key):
|
||||
if key == '0':
|
||||
return vodlist
|
||||
else:
|
||||
vod_list_new = [i for i in vodlist if
|
||||
self.time_diff1[key][0] <= self.str2sec(str(i["vod_remarks"])) < self.time_diff1[key][1]]
|
||||
return vod_list_new
|
||||
|
||||
# 提取番剧id
|
||||
def find_bangumi_id(self, url):
|
||||
aid = str(url).strip().split(r"/")[-1]
|
||||
if not aid:
|
||||
aid = str(url).strip().split(r"/")[-2]
|
||||
aid = aid.split(r"?")[0]
|
||||
return aid
|
||||
|
||||
# 登录二维码
|
||||
def get_Login_qrcode(self, pg):
|
||||
result = {}
|
||||
if int(pg) != 1:
|
||||
return result
|
||||
video = [{
|
||||
"vod_id": 'setting_tab&filter',
|
||||
"vod_name": '标签与筛选',
|
||||
"vod_pic": 'https://www.bilibili.com/favicon.ico'
|
||||
},{
|
||||
"vod_id": 'setting_liveExtra',
|
||||
"vod_name": '查看直播细化标签',
|
||||
"vod_pic": 'https://www.bilibili.com/favicon.ico'
|
||||
}]
|
||||
url = 'https://passport.bilibili.com/x/passport-login/web/qrcode/generate'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
id = jo['data']['qrcode_key']
|
||||
url = jo['data']['url']
|
||||
account = {'master': '主账号', 'vip': '副账号'}
|
||||
isLogin = {0: '未登录', 1: '已登录'}
|
||||
isVIP = {0: '', 1: '👑'}
|
||||
users = self.userConfig.get('users', {})
|
||||
for _type, typeName in account.items():
|
||||
user = users.get(_type)
|
||||
if user:
|
||||
video.append({
|
||||
"vod_id": 'setting_login_' + id,
|
||||
"vod_name": user['uname'],
|
||||
"vod_pic": self.format_img(user['face']),
|
||||
"vod_remarks": isVIP[user['isVIP']] + typeName + ' ' + isLogin[user['isLogin']]
|
||||
})
|
||||
#pic_url = {'qrcode': url}
|
||||
pic_url = {'qrcode': 'https://passport.bilibili.com/h5-app/passport/login/scan?qrcode_key=' + id + '&navhide=1'}
|
||||
#if not dirname.startswith('/data/'):
|
||||
# pic_url['qr_chs'] = '208x117'
|
||||
pic_url['qr_chs'] = '208x117'
|
||||
video.append({
|
||||
"vod_id": 'setting_login_' + id,
|
||||
#"vod_name": '扫码后点击',
|
||||
'vod_pic': 'http://jm92swf.s1002.xrea.com/?' + urlencode(pic_url),
|
||||
})
|
||||
result['list'] = video
|
||||
result['page'] = 1
|
||||
result['pagecount'] = 1
|
||||
result['limit'] = 1
|
||||
result['total'] = 1
|
||||
return result
|
||||
|
||||
time_diff1 = {'1': [0, 300],
|
||||
'2': [300, 900], '3': [900, 1800], '4': [1800, 3600],
|
||||
'5': [3600, 99999999999999999999999999999999]
|
||||
}
|
||||
time_diff = '0'
|
||||
|
||||
dynamic_offset = ''
|
||||
|
||||
def get_dynamic(self, pg, mid, order):
|
||||
if mid == '0':
|
||||
result = {}
|
||||
if int(pg) == 1:
|
||||
self.dynamic_offset = ''
|
||||
url = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=video&offset=%s&page=%s' % (self.dynamic_offset, pg)
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
self.dynamic_offset = jo['data'].get('offset')
|
||||
videos = []
|
||||
vodList = jo['data']['items']
|
||||
for vod in vodList:
|
||||
if not vod['visible']:
|
||||
continue
|
||||
up = vod['modules']["module_author"]['name']
|
||||
ivod = vod['modules']['module_dynamic']['major']['archive']
|
||||
aid = str(ivod['aid']).strip()
|
||||
title = ivod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = ivod['cover'].strip()
|
||||
# remark = str(ivod['duration_text']).strip()
|
||||
remark = str(self.second_to_time(self.str2sec(ivod['duration_text']))).strip() + ' 🆙' + str(
|
||||
up).strip() # 显示分钟数+up主名字
|
||||
videos.append({
|
||||
"vod_id": 'av' + aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
else:
|
||||
return self.get_up_videos(mid=mid, pg=pg, order=order)
|
||||
|
||||
def get_found_vod(self, vod):
|
||||
aid = vod.get('aid', '')
|
||||
if not aid:
|
||||
aid = vod.get('id', '')
|
||||
goto = vod.get('goto', '')
|
||||
if not goto or goto and goto == 'av':
|
||||
aid = 'av' + str(aid).strip()
|
||||
elif goto == 'ad':
|
||||
return []
|
||||
title = vod['title'].strip()
|
||||
img = vod['pic'].strip()
|
||||
is_followed = vod.get('is_followed')
|
||||
if goto == 'live':
|
||||
room_info = vod['room_info']
|
||||
remark = ''
|
||||
live_status = room_info.get('live_status', '')
|
||||
if live_status:
|
||||
remark = '直播中 '
|
||||
else:
|
||||
return []
|
||||
remark += '👁' + room_info['watched_show']['text_small'] + ' 🆙' + vod['owner']['name'].strip()
|
||||
else:
|
||||
rcmd_reason = vod.get('rcmd_reason', '')
|
||||
if rcmd_reason and type(rcmd_reason) == dict and rcmd_reason.get('content'):
|
||||
reason= ' 🔥' + rcmd_reason['content'].strip()
|
||||
if '人气飙升' in reason:
|
||||
reason= ' 🔥人气飙升'
|
||||
elif is_followed:
|
||||
reason = ' 已关注'
|
||||
else:
|
||||
#reason = " 💬" + self.zh(vod['stat']['danmaku'])
|
||||
reason = ' 🆙' + vod['owner']['name'].strip()
|
||||
remark = str(self.second_to_time(vod['duration'])).strip() + " ▶" + self.zh(vod['stat']['view']) + reason
|
||||
video = [{
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
}]
|
||||
for v in self.pool.map(self.get_found_vod, vod.get('others', [])):
|
||||
video.extend(v)
|
||||
return video
|
||||
|
||||
_popSeriesInit = 0
|
||||
|
||||
def get_found(self, tid, rid, pg):
|
||||
result = {}
|
||||
if tid == '推荐':
|
||||
query = self.encrypt_wbi(fresh_type=4, feed_version='V3', brush=1, fresh_idx=pg, fresh_idx_1h=pg, ps=self.userConfig['page_size'])
|
||||
url = f'https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd?{query}'
|
||||
else:
|
||||
url = 'https://api.bilibili.com/x/web-interface/ranking/v2?rid={0}&type={1}'.format(rid, tid)
|
||||
if tid == '热门':
|
||||
url = 'https://api.bilibili.com/x/web-interface/popular?pn={0}&ps={1}'.format(pg, self.userConfig['page_size'])
|
||||
elif tid == "入站必刷":
|
||||
url = 'https://api.bilibili.com/x/web-interface/popular/precious'
|
||||
elif tid == "每周必看":
|
||||
if not self._popSeriesInit or int(pg) == 1:
|
||||
url = 'https://api.bilibili.com/x/web-interface/popular/series/list'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
number = self._popSeriesInit = jo['data']['list'][0]['number']
|
||||
self._popSeriesNum = [int(number), 1]
|
||||
else:
|
||||
number = self._popSeriesNum[0]
|
||||
url = 'https://api.bilibili.com/x/web-interface/popular/series/one?number=' + str(number)
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data'].get('item')
|
||||
if not vodList:
|
||||
vodList = jo['data']['list']
|
||||
if len(vodList) > self.userConfig['page_size']:
|
||||
if tid == "每周必看":
|
||||
_tmp_pg = int(self._popSeriesNum[1])
|
||||
value = len(vodList) / self.userConfig['page_size'] - _tmp_pg
|
||||
if value > 0:
|
||||
value += 1
|
||||
if not int(value):
|
||||
self._popSeriesNum = [int(number) - 1, 1]
|
||||
else:
|
||||
self._popSeriesNum[1] = _tmp_pg + 1
|
||||
else:
|
||||
_tmp_pg = pg
|
||||
vodList = self.pagination(vodList, _tmp_pg)
|
||||
for v in self.pool.map(self.get_found_vod, vodList):
|
||||
videos.extend(v)
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_bangumi(self, tid, pg, order, season_status):
|
||||
result = {}
|
||||
if order == '追番剧':
|
||||
url = 'https://api.bilibili.com/x/space/bangumi/follow/list?type={0}&vmid={1}&pn={2}&ps={3}'.format(tid, self.userid, pg, self.userConfig['page_size'])
|
||||
rsp = self._get_sth(url)
|
||||
else:
|
||||
url = 'https://api.bilibili.com/pgc/season/index/result?type=1&season_type={0}&page={1}&order={2}&season_status={3}&pagesize={4}'.format(tid, pg, order, season_status, self.userConfig['page_size'])
|
||||
if order == '热门':
|
||||
if tid == '1':
|
||||
url = 'https://api.bilibili.com/pgc/web/rank/list?season_type={0}&day=3'.format(tid)
|
||||
else:
|
||||
url = 'https://api.bilibili.com/pgc/season/rank/web/list?season_type={0}&day=3'.format(tid)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
if 'data' in jo:
|
||||
vodList = jo['data']['list']
|
||||
else:
|
||||
vodList = jo['result']['list']
|
||||
if len(vodList) > self.userConfig['page_size']:
|
||||
vodList = self.pagination(vodList, pg)
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
aid = str(vod['season_id']).strip()
|
||||
title = vod['title']
|
||||
img = vod.get('ss_horizontal_cover')
|
||||
if not img or tid == '1' and not self.userConfig['bangumi_horizontal_cover']:
|
||||
if vod.get('first_ep_info') and 'cover' in vod['first_ep_info']:
|
||||
img = vod['first_ep_info']['cover']
|
||||
elif vod.get('first_ep') and 'cover' in vod['first_ep']:
|
||||
img = vod['first_ep']['cover']
|
||||
else:
|
||||
img = vod['cover'].strip()
|
||||
remark = vod.get('index_show', '')
|
||||
if not remark and vod.get('new_ep') and vod['new_ep'].get('index_show'):
|
||||
remark = vod['new_ep']['index_show']
|
||||
remark = remark.replace('更新至', '🆕')
|
||||
stat = vod.get('stat')
|
||||
if stat:
|
||||
remark = '▶' + self.zh(stat.get('view')) + ' ' + remark
|
||||
videos.append({
|
||||
"vod_id": 'ss' + aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_timeline(self, tid, pg):
|
||||
result = {}
|
||||
url = 'https://api.bilibili.com/pgc/web/timeline/v2?season_type={0}&day_before=2&day_after=4'.format(tid)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
videos1 = []
|
||||
vodList = jo['result']['latest']
|
||||
for vod in vodList:
|
||||
aid = str(vod['season_id']).strip()
|
||||
title = vod['title'].strip()
|
||||
img = vod['ep_cover'].strip()
|
||||
remark = '🆕' + vod['pub_index'] + ' ❤ ' + vod['follows'].replace('系列', '').replace('追番', '')
|
||||
videos1.append({
|
||||
"vod_id": 'ss' + aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
videos2 = []
|
||||
vodList2 = jo['result']['timeline']
|
||||
for i in range(len(vodList2)):
|
||||
vodList = vodList2[i]['episodes']
|
||||
for vod in vodList:
|
||||
if str(vod['published']) == "0":
|
||||
aid = str(vod['season_id']).strip()
|
||||
title = str(vod['title']).strip()
|
||||
img = str(vod['ep_cover']).strip()
|
||||
date = str(time.strftime("%m-%d %H:%M", time.localtime(vod['pub_ts'])))
|
||||
remark = date + " " + vod['pub_index']
|
||||
videos2.append({
|
||||
"vod_id": 'ss' + aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos2 + videos1
|
||||
result['page'] = 1
|
||||
result['pagecount'] = 1
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_live(self, pg, parent_area_id, area_id):
|
||||
result = {}
|
||||
if parent_area_id == '推荐':
|
||||
url = 'https://api.live.bilibili.com/xlive/web-interface/v1/webMain/getList?platform=web&page=%s' % pg
|
||||
rsp = self._get_sth(url)
|
||||
else:
|
||||
url = 'https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=%s&area_id=%s&sort_type=online&page=%s' % (parent_area_id, area_id, pg)
|
||||
if parent_area_id == '热门':
|
||||
url = 'https://api.live.bilibili.com/room/v1/room/get_user_recommend?page=%s&page_size=%s' % (pg, self.userConfig['page_size'])
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data']
|
||||
if 'recommend_room_list' in vodList:
|
||||
vodList = vodList['recommend_room_list']
|
||||
elif 'list' in vodList:
|
||||
vodList = vodList['list']
|
||||
for vod in vodList:
|
||||
aid = str(vod['roomid']).strip()
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = vod.get('user_cover')
|
||||
if not img:
|
||||
img = vod.get('cover')
|
||||
remark = '👁' + vod['watched_show']['text_small'].strip() + " 🆙" + vod['uname'].strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_up_series(self, mid, pg):
|
||||
result = {}
|
||||
url = 'https://api.bilibili.com/x/polymer/web-space/seasons_series_list?mid=%s&page_num=%s&page_size=%s' % (mid, pg, self.userConfig['page_size'])
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
jo = jo['data']['items_lists']
|
||||
vodList = jo['seasons_list'] + jo['series_list']
|
||||
for vod in vodList:
|
||||
vod = vod.get('meta')
|
||||
aid = str(vod.get('season_id', '')).strip()
|
||||
if aid:
|
||||
aid = 'list_' + str(mid) + '_season_' + aid
|
||||
else:
|
||||
aid = 'list_' + str(mid) + '_series_' + str(vod.get('series_id', '')).strip()
|
||||
title = vod['name'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = vod.get('cover')
|
||||
remark = vod.get('description', '').strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
get_up_videos_result = {}
|
||||
|
||||
def get_up_videos(self, mid, pg, order):
|
||||
result = {}
|
||||
if not mid.isdigit():
|
||||
if int(pg) == 1:
|
||||
self.get_up_videos_mid = mid = self.detailContent_args.get('mid', '')
|
||||
if not mid in self.get_up_videos_result:
|
||||
self.get_up_videos_result.clear()
|
||||
self.get_up_videos_result[mid] = []
|
||||
else:
|
||||
mid = self.get_up_videos_mid
|
||||
if int(pg) == 1:
|
||||
self.get_up_videoNum_event.clear()
|
||||
self.get_up_info_event.clear()
|
||||
self.pool.submit(self.get_up_info, mid)
|
||||
Space = order2 = ''
|
||||
if order == 'oldest':
|
||||
order2 = order
|
||||
order = 'pubdate'
|
||||
elif order == 'quicksearch':
|
||||
Space = '投稿: '
|
||||
videos = self.get_up_videos_result.get(mid, [])
|
||||
if videos:
|
||||
result['list'] = videos
|
||||
return result
|
||||
elif order == 'series':
|
||||
return self.get_up_series(mid=mid, pg=pg)
|
||||
tmp_pg = pg
|
||||
if order2:
|
||||
self.get_up_videoNum_event.wait()
|
||||
tmp_pg = self.up_info[mid]['vod_pc'] - int(pg) + 1
|
||||
query = self.encrypt_wbi(mid=mid, pn=tmp_pg, ps=self.userConfig['page_size'], order=order)
|
||||
url = f'https://api.bilibili.com/x/space/wbi/arc/search?{query}'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
if jo['code'] == 0:
|
||||
vodList = jo['data']['list']['vlist']
|
||||
for vod in vodList:
|
||||
aid = str(vod['aid']).strip()
|
||||
title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = vod['pic'].strip()
|
||||
remark = self.second_to_time(self.str2sec(str(vod['length']).strip())) + " ▶" + self.zh(vod['play'])
|
||||
if not Space:
|
||||
remark += " 💬" + self.zh(vod['video_review'])
|
||||
videos.append({
|
||||
"vod_id": 'av' + aid,
|
||||
"vod_name": Space + title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
if order2:
|
||||
videos.reverse()
|
||||
if int(pg) == 1:
|
||||
self.get_up_info_event.wait()
|
||||
vodname = self.up_info[mid]['name'] + " 个人主页"
|
||||
if Space:
|
||||
vodname = 'UP: ' + self.up_info[mid]['name']
|
||||
gotoUPHome={
|
||||
"vod_id": 'up' + str(mid),
|
||||
"vod_name": vodname,
|
||||
"vod_pic": self.format_img(self.up_info[mid]['face']),
|
||||
"vod_remarks": self.up_info[mid]['following'] + ' 👥' + self.up_info[mid]['fans'] + ' 🎬' + str(self.up_info[mid]['vod_count'])
|
||||
}
|
||||
videos.insert(0, gotoUPHome)
|
||||
if Space:
|
||||
self.get_up_videos_result[mid] = videos
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 99
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
history_view_at = 0
|
||||
|
||||
def get_history(self, type, pg):
|
||||
result = {}
|
||||
if int(pg) == 1:
|
||||
self.history_view_at = 0
|
||||
url = 'https://api.bilibili.com/x/web-interface/history/cursor?ps={0}&view_at={1}&type={2}'.format(self.userConfig['page_size'], self.history_view_at, type)
|
||||
if type == '稍后再看':
|
||||
url = 'https://api.bilibili.com/x/v2/history/toview'
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data'].get('list', [])
|
||||
if type == '稍后再看':
|
||||
vodList = self.pagination(vodList, pg)
|
||||
else:
|
||||
self.history_view_at = jo['data']['cursor']['view_at']
|
||||
for vod in vodList:
|
||||
history = vod.get('history', '')
|
||||
if history:
|
||||
business = history['business']
|
||||
aid = str(history['oid']).strip()
|
||||
img = vod['cover'].strip()
|
||||
part = str(history['part']).strip()
|
||||
else:
|
||||
business = 'archive'
|
||||
aid = str(vod["aid"]).strip()
|
||||
img = vod['pic'].strip()
|
||||
part = str(vod['page']['part']).strip()
|
||||
if business == 'article':
|
||||
continue
|
||||
elif business == 'pgc':
|
||||
aid = 'ep' + str(history['epid'])
|
||||
_total = vod['total']
|
||||
part = vod.get('show_title')
|
||||
elif business == 'archive':
|
||||
aid = 'av' + aid
|
||||
_total = vod['videos']
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
if business == 'live':
|
||||
live_status = vod.get('badge', '')
|
||||
remark = live_status + ' 🆙' + vod['author_name'].strip()
|
||||
else:
|
||||
if str(vod['progress']) == '-1':
|
||||
remark = '已看完'
|
||||
elif str(vod['progress']) == '0':
|
||||
remark = '刚开始看'
|
||||
else:
|
||||
process = str(self.second_to_time(vod['progress'])).strip()
|
||||
remark = '看到 ' + process
|
||||
if not _total in [0, 1] and part:
|
||||
remark += ' (' + str(part) + ')'
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_fav_detail(self, pg, mlid, order):
|
||||
result = {}
|
||||
url = 'https://api.bilibili.com/x/v3/fav/resource/list?media_id=%s&order=%s&pn=%s&ps=10&platform=web&type=0' % (mlid, order, pg)
|
||||
rsp = self._get_sth(url)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data'].get('medias', [])
|
||||
for vod in vodList:
|
||||
# 只展示类型为 视频的条目
|
||||
# 过滤去掉收藏中的 已失效视频;如果不喜欢可以去掉这个 if条件
|
||||
if vod.get('type') in [2] and vod.get('title') != '已失效视频':
|
||||
aid = str(vod['id']).strip()
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""",
|
||||
'"')
|
||||
img = vod['cover'].strip()
|
||||
remark = str(self.second_to_time(vod['duration'])).strip() + " ▶" + self.zh(vod['cnt_info']['play']) + " 💬" + self.zh(vod['cnt_info']['danmaku'])
|
||||
videos.append({
|
||||
"vod_id": 'av' + aid + '_mlid' + str(mlid),
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
# videos=self.filter_duration(videos, duration_diff)
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
get_up_videoNum_event = threading.Event()
|
||||
|
||||
def get_up_videoNum(self, mid):
|
||||
url = "https://api.bilibili.com/x/space/navnum?mid={0}".format(mid)
|
||||
rsp = self._get_sth(url)
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] == 0:
|
||||
return jRoot['data']['video']
|
||||
else:
|
||||
return 0
|
||||
|
||||
get_up_info_event = threading.Event()
|
||||
up_info = {}
|
||||
|
||||
def get_up_info(self, mid, **kwargs):
|
||||
if mid in self.up_info:
|
||||
self.get_up_info_event.set()
|
||||
get_up_videoNum = self.pool.submit(self.get_up_videoNum, mid)
|
||||
data = kwargs.get('data')
|
||||
if not data:
|
||||
url = "https://api.bilibili.com/x/web-interface/card?mid={0}".format(mid)
|
||||
rsp = self._get_sth(url)
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] == 0:
|
||||
data = jRoot['data']
|
||||
else:
|
||||
self.get_up_info_event.set()
|
||||
return
|
||||
jo = data['card']
|
||||
info = {}
|
||||
info['following'] = '未关注'
|
||||
if data['following']:
|
||||
info['following'] = '已关注'
|
||||
info['name'] = info['crname'] = jo['name'].replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
if self.isFongmi:
|
||||
info['crname'] = '[a=cr:{"id": "' + mid + '_pubdate_getupvideos","name": "' + info['name'].replace('"', '\\"') + '"}/]' + info['name'] + '[/a]'
|
||||
info['face'] = jo['face']
|
||||
info['fans'] = self.zh(jo['fans'])
|
||||
info['like_num'] = self.zh(data['like_num'])
|
||||
info['desc'] = jo['Official']['desc'] + " " + jo['Official']['title']
|
||||
info['vod_count'] = str(data['archive_count']).strip()
|
||||
self.up_info[mid] = info
|
||||
self.get_up_info_event.set()
|
||||
self.up_info[mid]['vod_count'] = str(get_up_videoNum.result()).strip()
|
||||
pc = divmod(int(info['vod_count']), self.userConfig['page_size'])
|
||||
vod_pc = pc[0]
|
||||
if pc[1] != 0:
|
||||
vod_pc += 1
|
||||
self.up_info[mid]['vod_pc'] = vod_pc
|
||||
self.get_up_videoNum_event.set()
|
||||
|
||||
def get_vod_relation(self, id):
|
||||
if id.isdigit():
|
||||
urlarg = 'aid=' + str(id)
|
||||
elif '=' in id:
|
||||
urlarg = id
|
||||
else:
|
||||
urlarg = 'bvid=' + id
|
||||
url = 'https://api.bilibili.com/x/web-interface/archive/relation?' + urlarg
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
relation = []
|
||||
if jo['code'] == 0:
|
||||
jo = jo['data']
|
||||
if jo['attention']:
|
||||
relation.append('已关注')
|
||||
else:
|
||||
relation.append('未关注')
|
||||
triple = []
|
||||
if jo['favorite']:
|
||||
triple.append('⭐')
|
||||
if jo['like']:
|
||||
triple.append('👍')
|
||||
coin = jo.get('coin')
|
||||
if coin:
|
||||
triple.append('💰'*coin)
|
||||
if len(triple) == 3:
|
||||
relation.append('👍💰⭐')
|
||||
else:
|
||||
relation.extend(triple)
|
||||
if jo['dislike']:
|
||||
relation.append('👎')
|
||||
if jo['season_fav']:
|
||||
relation.append('已订阅合集')
|
||||
return relation
|
||||
|
||||
def get_channel(self, pg, cid, order):
|
||||
result = {}
|
||||
if str(pg) == '1':
|
||||
self.channel_offset = ''
|
||||
if order == "featured":
|
||||
url = 'https://api.bilibili.com/x/web-interface/web/channel/featured/list?channel_id={0}&filter_type=0&offset={1}&page_size={2}'.format(cid, self.channel_offset, self.userConfig['page_size'])
|
||||
else:
|
||||
url = 'https://api.bilibili.com/x/web-interface/web/channel/multiple/list?channel_id={0}&sort_type={1}&offset={2}&page_size={3}'.format(cid, order, self.channel_offset, self.userConfig['page_size'])
|
||||
rsp = self._get_sth(url, 'master')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo.get('code') == 0:
|
||||
self.channel_offset = jo['data'].get('offset')
|
||||
videos = []
|
||||
vodList = jo['data']['list']
|
||||
if pg == '1' and 'items' in vodList[0]:
|
||||
vodList_rank = vodList[0]['items']
|
||||
del (vodList[0])
|
||||
vodList = vodList_rank + vodList
|
||||
for vod in vodList:
|
||||
if 'uri' in vod and 'bangumi' in vod['uri']:
|
||||
aid = self.find_bangumi_id(vod['uri'])
|
||||
else:
|
||||
aid = 'av' + str(vod['id']).strip()
|
||||
title = vod['name'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = vod['cover'].strip()
|
||||
remark = "▶" + str(vod['view_count'])
|
||||
duration = vod.get('duration', '')
|
||||
if duration:
|
||||
remark = str(self.second_to_time(self.str2sec(duration))).strip() + ' ' + remark
|
||||
danmaku = vod.get('danmaku', '')
|
||||
like_count = vod.get('like_count', '')
|
||||
follow_count = vod.get('follow_count', '')
|
||||
if danmaku:
|
||||
remark += " 💬" + self.zh(danmaku)
|
||||
elif like_count:
|
||||
remark += " 👍" + str(like_count)
|
||||
elif follow_count:
|
||||
remark += " ❤" + str(follow_count)
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_follow(self, pg, sort):
|
||||
result = {}
|
||||
if sort == "最常访问":
|
||||
url = 'https://api.bilibili.com/x/relation/followings?vmid={0}&pn={1}&ps=10&order=desc&order_type=attention' .format(self.userid, pg)
|
||||
elif sort == "最近关注":
|
||||
url = 'https://api.bilibili.com/x/relation/followings?vmid={0}&pn={1}&ps=10&order=desc&order_type='.format(self.userid, pg)
|
||||
elif sort == "正在直播":
|
||||
url = 'https://api.live.bilibili.com/xlive/web-ucenter/v1/xfetter/GetWebList?page={0}&page_size=10'.format(pg)
|
||||
elif sort == "最近访问":
|
||||
url = 'https://api.bilibili.com/x/v2/history?pn={0}&ps=15'.format(pg)
|
||||
elif sort == "特别关注":
|
||||
url = 'https://api.bilibili.com/x/relation/tag?mid={0}&tagid=-10&pn={1}&ps=10'.format(self.userid, pg)
|
||||
elif sort == "悄悄关注":
|
||||
url = 'https://api.bilibili.com/x/relation/whispers?pn={0}&ps=10'.format(pg)
|
||||
else:
|
||||
url = 'https://api.bilibili.com/x/relation/followers?vmid={0}&pn={1}&ps=10&order=desc&order_type=attention'.format(self.userid, pg)
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] != 0:
|
||||
return result
|
||||
if sort == "特别关注" or sort == "最近访问":
|
||||
vodList = jo['data']
|
||||
elif sort == "正在直播":
|
||||
vodList = jo['data']['rooms']
|
||||
else:
|
||||
vodList = jo['data']['list']
|
||||
if int(pg) == 1:
|
||||
self.recently_up_list = []
|
||||
follow = []
|
||||
for f in vodList:
|
||||
remark = ''
|
||||
if sort == "最近访问":
|
||||
mid = 'up' + str(f['owner']['mid'])
|
||||
if mid in self.recently_up_list:
|
||||
continue
|
||||
self.recently_up_list.append(mid)
|
||||
title = str(f['owner']['name']).strip()
|
||||
img = str(f['owner']['face']).strip()
|
||||
elif sort == "正在直播":
|
||||
mid = str(f['room_id'])
|
||||
title = f['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = f['cover_from_user'].strip()
|
||||
remark = f['uname'].strip()
|
||||
else:
|
||||
mid = 'up' + str(f['mid'])
|
||||
title = str(f['uname']).strip()
|
||||
img = str(f['face']).strip()
|
||||
if 'special' in f and f['special'] == 1:
|
||||
remark = '特别关注'
|
||||
follow.append({
|
||||
"vod_id": mid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = follow
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
homeVideoContent_result = {}
|
||||
def homeVideoContent(self):
|
||||
if not self.homeVideoContent_result:
|
||||
videos = self.get_found(rid='0', tid='all', pg=1)['list'][0:int(self.userConfig['maxHomeVideoContent'])]
|
||||
self.homeVideoContent_result['list'] = videos
|
||||
return self.homeVideoContent_result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
self.stop_heartbeat_event.set()
|
||||
if tid == "推荐":
|
||||
if 'tid' in extend:
|
||||
tid = extend['tid']
|
||||
if tid.isdigit():
|
||||
tid = int(tid)
|
||||
if tid > 10000:
|
||||
tid -= 10000
|
||||
return self.get_timeline(tid=tid, pg=pg)
|
||||
rid = tid
|
||||
tid = 'all'
|
||||
return self.get_found(tid=tid, rid=rid, pg=pg)
|
||||
rid = '0'
|
||||
return self.get_found(tid=tid, rid=rid, pg=pg)
|
||||
elif tid == "影视":
|
||||
tid = '1'
|
||||
order = '热门'
|
||||
season_status = '-1'
|
||||
if 'tid' in extend:
|
||||
tid = extend['tid']
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
if 'season_status' in extend:
|
||||
if order == '热门':
|
||||
order = '2'
|
||||
season_status = extend['season_status']
|
||||
return self.get_bangumi(tid, pg, order, season_status)
|
||||
elif tid == "动态":
|
||||
mid = '0'
|
||||
order = 'pubdate'
|
||||
if 'mid' in extend:
|
||||
mid = extend['mid']
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
if mid == '0' and not self.userid or mid == '登录':
|
||||
return self.get_Login_qrcode(pg)
|
||||
return self.get_dynamic(pg=pg, mid=mid, order=order)
|
||||
elif tid == '频道':
|
||||
order = 'hot'
|
||||
cid = random.choice(self.userConfig['channel_list'])
|
||||
cid = cid['v']
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
if 'cid' in extend:
|
||||
cid = extend['cid']
|
||||
return self.get_channel(pg=pg, cid=cid, order=order)
|
||||
elif tid == '直播':
|
||||
tid = "热门"
|
||||
area_id = '0'
|
||||
if 'tid' in extend:
|
||||
tid = extend['tid']
|
||||
if '_' in tid:
|
||||
tids = tid.split('_')
|
||||
tid = tids[0]
|
||||
area_id = tids[1]
|
||||
return self.get_live(pg=pg, parent_area_id=tid, area_id=area_id)
|
||||
elif tid == "UP":
|
||||
mid = self.detailContent_args.get('mid', '')
|
||||
if 'mid' in extend:
|
||||
mid = extend['mid']
|
||||
if not mid or mid == '登录':
|
||||
return self.get_Login_qrcode(pg)
|
||||
up_config = self.config["filter"].get('UP')
|
||||
if not mid and up_config:
|
||||
for i in up_config:
|
||||
if i['key'] == 'mid':
|
||||
if len(i['value']) > 1:
|
||||
mid = i['value'][1]['v']
|
||||
break
|
||||
order = 'pubdate'
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
return self.get_up_videos(mid=mid, pg=pg, order=order)
|
||||
elif tid == "关注":
|
||||
sort = "最常访问"
|
||||
if 'sort' in extend:
|
||||
sort = extend['sort']
|
||||
return self.get_follow(pg, sort)
|
||||
elif tid == "收藏":
|
||||
mlid = str(self.userConfig['favMode'])
|
||||
if 'mlid' in extend:
|
||||
mlid = extend['mlid']
|
||||
fav_config = self.config["filter"].get('收藏')
|
||||
if mlid in ['1', '2']:
|
||||
return self.get_bangumi(tid=mlid, pg=pg, order='追番剧', season_status='')
|
||||
elif mlid == '0' and fav_config:
|
||||
for i in fav_config:
|
||||
if i['key'] == 'mlid':
|
||||
if len(i['value']) > 1:
|
||||
mlid = i['value'][2]['v']
|
||||
break
|
||||
order = 'mtime'
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
return self.get_fav_detail(pg=pg, mlid=mlid, order=order)
|
||||
elif tid == '历史':
|
||||
type = 'all'
|
||||
if 'type' in extend:
|
||||
type = extend['type']
|
||||
if type == 'UP主':
|
||||
return self.get_follow(pg=pg, sort='最近访问')
|
||||
return self.get_history(type=type, pg=pg)
|
||||
elif tid.endswith('_getbangumiseasons'):
|
||||
if int(pg) == 1:
|
||||
return {'list': self.detailContent_args.get('seasons', [])}
|
||||
elif tid.endswith('_getupvideos'):
|
||||
mid, order, clicklink = tid.split('_')
|
||||
return self.get_up_videos(pg=pg, mid=mid, order=order)
|
||||
elif tid.endswith('_clicklink'):
|
||||
keyword = tid.replace('_clicklink', '')
|
||||
duration_diff = '0'
|
||||
if 'duration' in extend:
|
||||
duration_diff = extend['duration']
|
||||
return self.get_search_content(key=keyword, pg=pg, duration_diff=duration_diff, order='', type='video', ps=self.userConfig['page_size'])
|
||||
else:
|
||||
duration_diff = '0'
|
||||
if 'duration' in extend:
|
||||
duration_diff = extend['duration']
|
||||
type = 'video'
|
||||
if 'type' in extend:
|
||||
type = extend['type']
|
||||
order = 'totalrank'
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
keyword = str(self.search_key)
|
||||
search_config = self.config["filter"].get('搜索')
|
||||
if not keyword and search_config:
|
||||
for i in search_config:
|
||||
if i['key'] == 'keyword':
|
||||
if len(i['value']) > 0:
|
||||
keyword = i['value'][0]['v']
|
||||
break
|
||||
if 'keyword' in extend:
|
||||
keyword = extend['keyword']
|
||||
return self.get_search_content(key=keyword, pg=pg, duration_diff=duration_diff, order=order, type=type, ps=self.userConfig['page_size'])
|
||||
|
||||
def get_search_content(self, key, pg, duration_diff, order, type, ps):
|
||||
value = None
|
||||
if not pg.isdigit():
|
||||
value = pg
|
||||
pg = 1
|
||||
query = self.encrypt_wbi(keyword=key, page=pg, duration=duration_diff, order=order, search_type=type, page_size=ps)
|
||||
url = f'https://api.bilibili.com/x/web-interface/wbi/search/type?{query}'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
result = {}
|
||||
if jo.get('code') == 0 and 'result' in jo['data']:
|
||||
videos = []
|
||||
vodList = jo['data'].get('result')
|
||||
if vodList and type == 'live':
|
||||
vodList = vodList.get('live_room')
|
||||
if not vodList:
|
||||
return result
|
||||
for vod in vodList:
|
||||
if type != vod['type']:
|
||||
continue
|
||||
title = ''
|
||||
if type == 'bili_user':
|
||||
aid = 'up' + str(vod['mid']).strip()
|
||||
img = vod['upic'].strip()
|
||||
remark = '👥' + self.zh(vod['fans']) + " 🎬" + self.zh(vod['videos'])
|
||||
title = vod['uname']
|
||||
elif type == 'live':
|
||||
aid = str(vod['roomid']).strip()
|
||||
img = vod['cover'].strip()
|
||||
remark = '👁' + self.zh(vod['online']) + ' 🆙' + vod['uname']
|
||||
elif 'media' in type:
|
||||
aid = str(vod['season_id']).strip()
|
||||
if self.detailContent_args:
|
||||
seasons = self.detailContent_args.get('seasons')
|
||||
if seasons:
|
||||
bangumi_seasons_id = []
|
||||
for ss in self.detailContent_args['seasons']:
|
||||
bangumi_seasons_id.append(ss['vod_id'])
|
||||
if aid + 'ss' in bangumi_seasons_id:
|
||||
continue
|
||||
aid = 'ss' + aid
|
||||
img = vod['cover'].strip()
|
||||
remark = str(vod['index_show']).strip().replace('更新至', '🆕')
|
||||
else:
|
||||
aid = 'av' + str(vod['aid']).strip()
|
||||
img = vod['pic'].strip()
|
||||
remark = str(self.second_to_time(self.str2sec(vod['duration']))).strip() + " ▶" + self.zh(vod['play'])
|
||||
if value == None:
|
||||
remark += " 💬" + self.zh(vod['danmaku'])
|
||||
if not title:
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""",'"').replace('&', '&')
|
||||
if value:
|
||||
title = value + title
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": self.format_img(img),
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 99
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def cleanSpace(self, str):
|
||||
return str.replace('\n', '').replace('\t', '').replace('\r', '').replace(' ', '')
|
||||
|
||||
def get_normal_episodes(self, episode):
|
||||
ssid = epid = ''
|
||||
aid = episode.get('aid', '')
|
||||
if not aid:
|
||||
aid = self.detailContent_args['aid']
|
||||
cid = episode.get('cid', '')
|
||||
ep_title = episode.get('title', '')
|
||||
if not ep_title:
|
||||
ep_title = episode.get('part', '')
|
||||
duration = episode.get('duration', '')
|
||||
if not duration:
|
||||
page = episode.get('page', '')
|
||||
if page:
|
||||
duration = page['duration']
|
||||
badge = long_title = preview = parse = ''
|
||||
ssid = self.detailContent_args.get('ssid', '')
|
||||
if ssid:
|
||||
ssid = '_ss' + ssid
|
||||
epid = episode.get('id', '')
|
||||
if epid:
|
||||
epid = '_ep' + str(epid)
|
||||
if duration and str(duration).endswith('000'):
|
||||
duration = int(duration / 1000)
|
||||
if ep_title.isdigit():
|
||||
ep_title = '第' + ep_title + self.detailContent_args['title_type']
|
||||
badge = episode.get('badge', '')
|
||||
if not self.session_vip.cookies and badge == '会员' and self.userConfig['bangumi_vip_parse'] or badge == '付费' and self.userConfig['bangumi_pay_parse']:
|
||||
parse = '_parse'
|
||||
if self.session_vip.cookies and self.userConfig['hide_bangumi_vip_badge']:
|
||||
badge = badge.replace('会员', '')
|
||||
if self.userConfig['hide_bangumi_preview'] and badge == '预告':
|
||||
badge = badge.replace('预告', '')
|
||||
preview = 1
|
||||
if badge:
|
||||
badge = '【' + badge + '】'
|
||||
long_title = episode.get('long_title', '')
|
||||
if not badge and long_title:
|
||||
long_title = ' ' + long_title
|
||||
title = ep_title + badge + long_title
|
||||
title = title.replace("#", "﹟").replace("$", "﹩")
|
||||
if duration:
|
||||
duration = '_dur' + str(duration)
|
||||
url = '{0}${1}_{2}{3}{4}{5}'.format(title, aid, cid, ssid, epid, duration)
|
||||
fromep = self.detailContent_args.get('fromep', '')
|
||||
if '_' + str(fromep) == epid:
|
||||
self.detailContent_args['fromep'] = url
|
||||
replyList = self.detailContent_args.get('Reply')
|
||||
if '_' + str(fromep) == epid or not fromep and replyList == None:
|
||||
self.detailContent_args['Reply'] = ''
|
||||
if self.userConfig['show_vod_hot_reply']:
|
||||
self.get_vod_hot_reply_event.clear()
|
||||
self.pool.submit(self.get_vod_hot_reply, aid)
|
||||
if ssid:
|
||||
if preview:
|
||||
return url, ''
|
||||
if parse:
|
||||
self.detailContent_args['parse'] = 1
|
||||
if long_title:
|
||||
long_title = '【解析】' + long_title
|
||||
ep_title += long_title
|
||||
parseurl = '{0}${1}_{2}{3}{4}{5}{6}'.format(ep_title, aid, cid, ssid, epid, duration, parse)
|
||||
if '_' + str(fromep) == epid:
|
||||
self.detailContent_args['fromep'] += '#' + parseurl
|
||||
else:
|
||||
parseurl = url
|
||||
return url, parseurl
|
||||
else:
|
||||
return url
|
||||
|
||||
def get_ugc_season(self, section, sections_len):
|
||||
if sections_len > 1:
|
||||
sec_title = self.detailContent_args['season_title'] + ' ' + section['title']
|
||||
else:
|
||||
sec_title = self.detailContent_args['season_title']
|
||||
sec_title = sec_title.replace("#", "﹟").replace("$", "﹩")
|
||||
episodes = section.get('episodes')
|
||||
playUrl = '#'.join(map(self.get_normal_episodes, episodes))
|
||||
result = (sec_title, playUrl)
|
||||
return result
|
||||
|
||||
get_vod_hot_reply_event = threading.Event()
|
||||
|
||||
def get_vod_hot_reply(self, oid):
|
||||
query = self.encrypt_wbi(type=1, ps=30, oid=str(oid))
|
||||
url = f'http://api.bilibili.com/x/v2/reply/main?{query}'
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] == 0:
|
||||
replies = jRoot['data'].get('replies')
|
||||
top_replies = jRoot['data'].get('top_replies')
|
||||
if replies and top_replies:
|
||||
replies = top_replies + replies
|
||||
if replies:
|
||||
up_mid = jRoot['data']['upper']['mid']
|
||||
ReplyList = []
|
||||
Reply_jump = []
|
||||
for r in replies:
|
||||
rpid = r['rpid']
|
||||
sex = r['member']['sex']
|
||||
if sex and sex == '女':
|
||||
sex = '👧'
|
||||
else:
|
||||
sex = '👦'
|
||||
name = sex + r['member']['uname'] + ':'
|
||||
mid = r['mid']
|
||||
if mid == up_mid:
|
||||
name = '🆙' + name
|
||||
like = '👍' + self.zh(r['like'])
|
||||
message = r['content']['message']
|
||||
if '/note-app/' in message:
|
||||
continue
|
||||
content = like + ' ' + name + message
|
||||
content = content.replace("#", "﹟").replace("$", "﹩")
|
||||
content += '$' + str(oid) + '_' + str(rpid) + '_notplay_reply'
|
||||
ReplyList.append(content)
|
||||
jump_url = r['content'].get('jump_url',{})
|
||||
for key, value in jump_url.items():
|
||||
if not value.get('app_url_schema') and not value.get('pc_url'):
|
||||
if key.startswith('https://www.bilibili.com/'):
|
||||
key = str(key).split('?')[0].split('/')
|
||||
while key[-1] == '':
|
||||
key.pop(-1)
|
||||
key = key[-1]
|
||||
if key.startswith('https://b23.tv/') or key.startswith('BV') or key.startswith('ep') or key.startswith('ss'):
|
||||
title = str(value['title']).replace("#", "﹟").replace("$", "﹩")
|
||||
vod = {'vod_id': str(key), 'vod_name': '评论:' + title}
|
||||
if not vod in Reply_jump:
|
||||
Reply_jump.append(vod)
|
||||
title = '快搜:' + str(key) +' ' + title
|
||||
content = title + '$ '
|
||||
ReplyList.append(content)
|
||||
self.detailContent_args['Reply'] = '#'.join(ReplyList)
|
||||
self.detailContent_args['Reply_jump'] = Reply_jump
|
||||
self.get_vod_hot_reply_event.set()
|
||||
|
||||
detailContent_args = {}
|
||||
|
||||
def detailContent(self, array):
|
||||
self.stop_heartbeat_event.set()
|
||||
aid = array[0]
|
||||
if aid.startswith('edgeid'):
|
||||
return self.interaction_detailContent(aid)
|
||||
elif aid.startswith('list'):
|
||||
return self.series_detailContent(aid)
|
||||
self.detailContent_args = {}
|
||||
if aid.startswith('https://b23.tv/'):
|
||||
try:
|
||||
r = requests_get(url=aid, headers=self.header, allow_redirects=False)
|
||||
url = r.headers['Location'].split('?')[0].split('/')
|
||||
while url[-1] == '':
|
||||
url.pop(-1)
|
||||
aid = url[-1]
|
||||
if not aid.startswith('BV', 0, 2):
|
||||
return {}
|
||||
except:
|
||||
return {}
|
||||
id = mlid = urlargs = ''
|
||||
self.get_vod_hot_reply_event.set()
|
||||
if aid.startswith('setting'):
|
||||
aid = aid.split('_')
|
||||
if aid[1] == 'tab&filter':
|
||||
return self.setting_tab_filter_detailContent()
|
||||
elif aid[1] == 'liveExtra':
|
||||
return self.setting_liveExtra_detailContent()
|
||||
elif aid[1] == 'login':
|
||||
key = aid[2]
|
||||
return self.setting_login_detailContent(key)
|
||||
elif aid.startswith('av') or aid.startswith('BV'):
|
||||
for i in aid.split('_'):
|
||||
if i.startswith('av'):
|
||||
id = i.replace('av', '', 1)
|
||||
urlargs = 'aid=' + str(id)
|
||||
elif i.startswith('BV'):
|
||||
id = i
|
||||
urlargs = 'bvid=' + id
|
||||
elif i.startswith('mlid'):
|
||||
mlid = i.replace('mlid', '', 1)
|
||||
#获取热门评论
|
||||
if self.userConfig['show_vod_hot_reply']:
|
||||
self.detailContent_args['Reply'] = ''
|
||||
self.get_vod_hot_reply_event.clear()
|
||||
self.pool.submit(self.get_vod_hot_reply, id)
|
||||
elif 'up' in aid:
|
||||
return self.up_detailContent(array)
|
||||
elif 'ss' in aid or 'ep' in aid:
|
||||
return self.ysContent(array)
|
||||
elif aid.isdigit():
|
||||
return self.live_detailContent(array)
|
||||
relation = self.pool.submit(self.get_vod_relation, urlargs)
|
||||
url = 'https://api.bilibili.com/x/web-interface/view/detail?' + urlargs
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] != 0:
|
||||
return {}
|
||||
jo = jRoot['data']['View']
|
||||
redirect_url = jo.get('redirect_url', '')
|
||||
if 'bangumi' in redirect_url:
|
||||
ep_id = self.find_bangumi_id(redirect_url)
|
||||
new_array = []
|
||||
for i in array:
|
||||
new_array.append(i)
|
||||
new_array[0] = ep_id
|
||||
return self.ysContent(new_array)
|
||||
self.detailContent_args['mid'] = up_mid = str(jo['owner']['mid'])
|
||||
self.detailContent_args['aid'] = aid = jo.get('aid')
|
||||
self.pool.submit(self.get_up_info, mid=up_mid, data=jRoot['data'].get('Card'))
|
||||
#相关合集
|
||||
ugc_season = jo.get('ugc_season')
|
||||
if ugc_season:
|
||||
self.detailContent_args['season_title'] = ugc_season['title']
|
||||
sections = ugc_season['sections']
|
||||
sections_len = len(sections)
|
||||
ugc_season_task = []
|
||||
for section in sections:
|
||||
t = self.pool.submit(self.get_ugc_season, section, sections_len)
|
||||
ugc_season_task.append(t)
|
||||
#相关推荐
|
||||
jo_Related = jRoot['data'].get('Related')
|
||||
#正片
|
||||
pages = jo['pages']
|
||||
title = jo['title'].replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
pic = jo['pic']
|
||||
desc = jo['desc'].strip()
|
||||
typeName = jo['tname']
|
||||
date = time.strftime("%Y%m%d", time.localtime(jo['pubdate'])) # 投稿时间本地年月日表示
|
||||
stat = jo['stat']
|
||||
# 演员项展示视频状态,包括以下内容:
|
||||
remark = []
|
||||
remark.append('▶' + self.zh(stat['view']))
|
||||
remark.append('💬' + self.zh(stat['danmaku']))
|
||||
remark.append('👍' + self.zh(stat['like']))
|
||||
remark.append('💰' + self.zh(stat['coin']))
|
||||
remark.append('⭐' + self.zh(stat['favorite']))
|
||||
_is_stein_gate = jo['rights'].get('is_stein_gate', 0)
|
||||
vod = {
|
||||
"vod_id": 'av' + str(aid),
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": typeName,
|
||||
"vod_year": date,
|
||||
"vod_content": desc
|
||||
}
|
||||
if self.isFongmi:
|
||||
vod['vod_remarks'] = " ".join(remark)
|
||||
vod_tags = ', '.join(sorted(map(lambda x: '[a=cr:{"id": "' + x['tag_name'].replace('"', '\\"') + '_clicklink","name":"' + x['tag_name'].replace('"', '\\"') + '"}/]' + x['tag_name'] + '[/a]', jRoot['data'].get('Tags', [])), key=len))
|
||||
vod['vod_content'] = vod_tags + ' \n' + desc
|
||||
self.userConfig['show_vod_hot_reply'] = False
|
||||
else:
|
||||
vod['vod_actor'] = " ".join(remark)
|
||||
vod['vod_area'] = "bilidanmu"
|
||||
secondP = []
|
||||
if self.userid:
|
||||
#做点什么
|
||||
follow = '➕关注$1_notplay_follow'
|
||||
unfollow = '➖取关$2_notplay_follow'
|
||||
like = '👍点赞$1_notplay_like'
|
||||
unlike = '👍🏻取消点赞$2_notplay_like'
|
||||
coin1 = '👍💰投币$1_notplay_coin'
|
||||
coin2 = '👍💰💰$2_notplay_coin'
|
||||
triple = '👍💰⭐三连$notplay_triple'
|
||||
secondPList = [follow, triple, like, coin1, coin2, unfollow, unlike]
|
||||
if mlid:
|
||||
favdel = f"☆取消收藏${mlid}_del_notplay_fav"
|
||||
secondPList.append(favdel)
|
||||
for fav in self.userConfig.get("fav_list", []):
|
||||
folder = fav['n'].replace("#", "﹟").replace("$", "﹩")
|
||||
ids = fav['v']
|
||||
fav = '⭐{}${}_add_notplay_fav'.format(folder, ids)
|
||||
secondPList.append(fav)
|
||||
defaultQn = int(self.userConfig['vodDefaultQn'])
|
||||
if defaultQn > 116:
|
||||
secondPList.append('⚠️限高1080$116_notplay_vodTMPQn')
|
||||
secondP = ['#'.join(secondPList)]
|
||||
AllPt = []
|
||||
AllPu = []
|
||||
if pages:
|
||||
AllPt = ['B站']
|
||||
if _is_stein_gate:
|
||||
AllPt = ['互动视频【快搜继续】']
|
||||
AllPu = ['#'.join(self.pool.map(self.get_normal_episodes, pages))]
|
||||
if secondP:
|
||||
AllPt.append('做点什么')
|
||||
AllPu.extend(secondP)
|
||||
if jo_Related:
|
||||
AllPt.append('相关推荐')
|
||||
AllPu.append('#'.join(self.pool.map(self.get_normal_episodes, jo_Related)))
|
||||
if self.userConfig['show_vod_hot_reply']:
|
||||
self.get_vod_hot_reply_event.wait()
|
||||
replyList = self.detailContent_args.get('Reply', '')
|
||||
if replyList:
|
||||
AllPt.append('热门评论')
|
||||
AllPu.extend([replyList])
|
||||
if ugc_season:
|
||||
for t in as_completed(ugc_season_task):
|
||||
AllPt.append(t.result()[0])
|
||||
AllPu.append(t.result()[1])
|
||||
vod['vod_play_from'] = "$$$".join(AllPt)
|
||||
vod['vod_play_url'] = "$$$".join(AllPu)
|
||||
#视频关系
|
||||
vod['vod_director'] = '🆙 ' + self.up_info[up_mid]['crname'] + ' 👥 ' + self.up_info[up_mid]['fans'] + ' ' + ' '.join(relation.result())
|
||||
#互动视频套用
|
||||
if _is_stein_gate:
|
||||
self.detailContent_args['AllPt'] = AllPt.copy()
|
||||
self.detailContent_args['AllPu'] = AllPu.copy()
|
||||
self.detailContent_args['vod_list'] = vod.copy()
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def series_detailContent(self, array):
|
||||
mid, type, sid = array.replace('list_', '').split('_')
|
||||
pg = 1
|
||||
ps = 99
|
||||
vod = {"vod_id": array, "vod_area": "bilidanmu", "vod_play_from": "B站"}
|
||||
urlL = []
|
||||
while True:
|
||||
if type == 'season':
|
||||
url = 'https://api.bilibili.com/x/polymer/web-space/seasons_archives_list?mid=%s&season_id=%s&page_num=%s&page_size=%s' % (mid, sid, pg, ps)
|
||||
else:
|
||||
url = 'https://api.bilibili.com/x/series/archives?mid=%s&series_id=%s&pn=%s&ps=%s' % (mid, sid, pg, ps)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
data = jo.get('data')
|
||||
if not vod.get("vod_name"):
|
||||
if data.get('meta'):
|
||||
vod["vod_name"] = data['meta']['name']
|
||||
vod["vod_pic"] = data['meta']['cover']
|
||||
vod["vod_content"] = data['meta']['description']
|
||||
else:
|
||||
vod["vod_name"] = data['archives'][0]['title']
|
||||
playUrl = '#'.join(map(self.get_normal_episodes, data.get('archives')))
|
||||
urlL.append(playUrl)
|
||||
total = data['page']['total']
|
||||
if (ps * pg) >= total:
|
||||
break
|
||||
pg += 1
|
||||
vod['vod_play_url'] = '#'.join(urlL)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def interaction_detailContent(self, array=''):
|
||||
array = array.split('_')
|
||||
cid = edgeid = 0
|
||||
for i in array:
|
||||
if i.startswith('edgeid'):
|
||||
edgeid = i.replace('edgeid', '')
|
||||
elif i.startswith('cid'):
|
||||
cid = i.replace('cid', '')
|
||||
aid = self.detailContent_args.get('aid')
|
||||
graph_version = self.detailContent_args.get('graph_version')
|
||||
url = 'https://api.bilibili.com/x/stein/edgeinfo_v2?aid={0}&graph_version={1}&edge_id={2}'.format(aid, graph_version, edgeid)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
data = jo.get('data')
|
||||
result = {}
|
||||
if data:
|
||||
questions = data['edges'].get('questions', [])
|
||||
choice_lis = []
|
||||
for question in questions:
|
||||
q_title = str(question.get('title', ''))
|
||||
if q_title:
|
||||
q_title += ' '
|
||||
for choice in question.get('choices', []):
|
||||
c_edgeid = str(choice['id'])
|
||||
c_cid = str(choice['cid'])
|
||||
option = str(choice.get('option', ''))
|
||||
choice_lis.append({
|
||||
"vod_id": 'edgeid' + c_edgeid + '_' + 'cid' + c_cid,
|
||||
"vod_name": '互动:' + q_title + option,
|
||||
})
|
||||
self.detailContent_args['interaction'] = choice_lis.copy()
|
||||
if edgeid:
|
||||
AllPt = self.detailContent_args['AllPt'].copy()
|
||||
if not choice_lis:
|
||||
AllPt[0] = '互动视频'
|
||||
AllPu = self.detailContent_args['AllPu'].copy()
|
||||
title = str(data['title']).replace("#", "﹟").replace("$", "﹩")
|
||||
url = '{0}${1}_{2}'.format(title, aid, cid)
|
||||
AllPu[0] = url
|
||||
vod = self.detailContent_args['vod_list'].copy()
|
||||
vod['vod_play_from'] = "$$$".join(AllPt)
|
||||
vod['vod_play_url'] = "$$$".join(AllPu)
|
||||
result['list'] = [vod]
|
||||
return result
|
||||
|
||||
def up_detailContent(self, array):
|
||||
self.detailContent_args['mid'] = mid = array[0].replace('up', '')
|
||||
self.get_up_info_event.clear()
|
||||
self.pool.submit(self.get_up_info, mid)
|
||||
first = '是否关注$ '
|
||||
follow = '关注$1_notplay_follow'
|
||||
unfollow = '取消关注$2_notplay_follow'
|
||||
qqfollow = '悄悄关注$3_notplay_follow'
|
||||
spfollow = '特别关注$-10_notplay_special_follow'
|
||||
unspfollow = '取消特别关注$0_notplay_special_follow'
|
||||
doWhat = [first, follow, qqfollow, spfollow, unfollow, unspfollow]
|
||||
doWhat = '#'.join(doWhat)
|
||||
self.get_up_info_event.wait()
|
||||
up_info = self.up_info[mid]
|
||||
vod = {
|
||||
"vod_id": 'up' + str(mid),
|
||||
"vod_name": up_info['name'] + " 个人主页",
|
||||
"vod_pic": up_info['face'],
|
||||
"vod_director": '🆙 ' + up_info['name'] + " " + up_info['following'] + ' UID:' + str(mid),
|
||||
"vod_content": up_info['desc'],
|
||||
'vod_play_from': '关注TA$$$视频投稿在动态标签——筛选——上个UP,选择后查看',
|
||||
'vod_play_url': doWhat
|
||||
}
|
||||
remark = "👥 " + up_info['fans'] + " 🎬 " + up_info['vod_count'] + " 👍 " + up_info['like_num']
|
||||
if self.isFongmi:
|
||||
vod["vod_remarks"] = remark
|
||||
tabfilter = self.config['filter'].get('动态')
|
||||
if not tabfilter:
|
||||
tabfilter = self.config['filter'].get('UP', [])
|
||||
vod["vod_actor"] = ' '.join(map(lambda x: '[a=cr:{"id": "' + str(mid) + '_' + x['v'] +'_getupvideos","name": "' + up_info['name'].replace('"', '\\"') + ' ' + x['n'] + '"}/]' + x['n'] + '[/a]', tabfilter[-1]['value']))
|
||||
else:
|
||||
vod["vod_actor"] = remark
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def setting_login_detailContent(self, key):
|
||||
cookie_dic_tmp = self.cookie_dic_tmp.get(key, '')
|
||||
message = ''
|
||||
if not cookie_dic_tmp:
|
||||
message = self.get_cookies(key)
|
||||
if message:
|
||||
message = f"【{message}】通过手机客户端扫码确认登录后点击相应按钮设置账号"
|
||||
else:
|
||||
message = '【已扫码并确认登录】请点击相应按钮设置当前获取的账号为:'
|
||||
vod = {
|
||||
"vod_name": "登录与设置",
|
||||
"vod_content": '通过手机客户端扫码并确认登录后,点击相应按钮设置cookie,设置后不需要管嗅探结果,直接返回二维码页面刷新,查看是否显示已登录,已登录即可重新打开APP以加载全部标签',
|
||||
}
|
||||
vod_play_from = ['登录$$$退出登录']
|
||||
vod_play_url = []
|
||||
first = message + '$ '
|
||||
login = '设置为主账号,动态收藏关注等内容源于此$' + str(key) + '_master_login_setting'
|
||||
login_vip = '设置为备用的VIP账号,仅用于播放会员番剧$' + str(key) + '_vip_login_setting'
|
||||
vod_play_url.append('#'.join([first, login, login_vip]))
|
||||
second = '点击相应按钮退出账号>>>$ '
|
||||
logout = '退出主账号$master_logout_setting'
|
||||
logout_vip = '退出备用的VIP账号$vip_logout_setting'
|
||||
vod_play_url.append('#'.join([second, logout, logout_vip]))
|
||||
cate_lis = [{
|
||||
'f': '主页站点推荐栏',
|
||||
'c': 'maxHomeVideoContent',
|
||||
'd': {
|
||||
'3': '3图',
|
||||
'4': '4图',
|
||||
'6': '6图',
|
||||
'8': '8图',
|
||||
'10': '10图',
|
||||
}
|
||||
},{
|
||||
'f': '视频画质',
|
||||
'c': 'vodDefaultQn',
|
||||
'd': self.vod_qn_id
|
||||
},{
|
||||
'f': '视频编码',
|
||||
'c': 'vodDefaultCodec',
|
||||
'd': self.vod_codec_id
|
||||
},{
|
||||
'f': '音频码率',
|
||||
'c': 'vodDefaultAudio',
|
||||
'd': self.vod_audio_id
|
||||
},{
|
||||
'f': '收藏默认显示',
|
||||
'c': 'favMode',
|
||||
'd': {
|
||||
'0': '默认收藏夹',
|
||||
'1': '追番',
|
||||
'2': '追剧',
|
||||
}
|
||||
},{
|
||||
|
||||
'f': '上传播放进度',
|
||||
'c': 'heartbeatInterval',
|
||||
'd': {
|
||||
'0': '关',
|
||||
'15': '开',
|
||||
}
|
||||
},{
|
||||
|
||||
'f': '直播筛选细化',
|
||||
'c': 'showLiveFilterTag',
|
||||
'd': {
|
||||
'0': '关',
|
||||
'1': '开',
|
||||
}
|
||||
}]
|
||||
for cate in cate_lis:
|
||||
vod_play_from.append(cate['f'])
|
||||
defaultConfig = cate['d'][str(int(self.userConfig[cate['c']]))]
|
||||
if 'vodDefaultAudio' == cate['c']:
|
||||
defaultConfig = str(defaultConfig).replace('000', 'k')
|
||||
url = ['当前:' + defaultConfig + '$ ']
|
||||
for id, name in cate['d'].items():
|
||||
if 'vodDefaultAudio' == cate['c']:
|
||||
name = str(name).replace('000', 'k')
|
||||
url.append(name + '$' + str(id) + '_' + cate['c'] + '_setting')
|
||||
vod_play_url.append('#'.join(url))
|
||||
vod['vod_play_from'] = '$$$'.join(vod_play_from)
|
||||
vod['vod_play_url'] = '$$$'.join(vod_play_url)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def setting_tab_filter_detailContent(self):
|
||||
vod = {
|
||||
"vod_name": "标签与筛选",
|
||||
"vod_content": '依次点击各标签,同一标签第一次点击为添加,第二次删除,可以返回到二维码页后重进本页查看预览,最后点击保存,未选择的将追加到末尾,如果未保存就重启app,将丢失未保存的配置',
|
||||
}
|
||||
vod_play_from = []
|
||||
vod_play_url = []
|
||||
cate_lis = [
|
||||
{'n': 'cateManual', 'v': '标签'},
|
||||
{'n': 'tuijianLis', 'v': '推荐[分区]'},
|
||||
{'n': 'rankingLis', 'v': '推荐[排行榜]'},
|
||||
{'n': 'cateManualLive', 'v': '直播'},
|
||||
]
|
||||
for cate in cate_lis:
|
||||
_List = cate['n']
|
||||
vod_play_from.append(cate['v'])
|
||||
List_tmp = self.userConfig.get(str(_List) + '_tmp', [])
|
||||
status = ''
|
||||
if List_tmp:
|
||||
status = '【未保存】'
|
||||
else:
|
||||
List_tmp = self.userConfig.get(_List, [])
|
||||
if not List_tmp:
|
||||
List_tmp = self.defaultConfig.get(_List)
|
||||
if List_tmp and type(List_tmp[0]) == dict:
|
||||
List_tmp = list(map(lambda x:x['n'], List_tmp))
|
||||
url = ['当前: ' + ','.join(List_tmp) + '$ ', f"{status}点击这里保存$_{_List}_save_setting", f"点击这里恢复默认并保存$_{_List}_clear_setting"]
|
||||
defaultConfig = self.defaultConfig[_List].copy()
|
||||
if _List == 'cateManual' and not 'UP' in defaultConfig:
|
||||
defaultConfig.append('UP')
|
||||
elif _List == 'cateManualLive':
|
||||
extra_live_filter = self.userConfig.get('cateManualLiveExtra', [])
|
||||
defaultConfig.extend(extra_live_filter.copy())
|
||||
for name in defaultConfig:
|
||||
value = str(name)
|
||||
if type(name) == dict:
|
||||
value = name['n'] + '@@@' + name['v'].replace('_', '@@@')
|
||||
name = name['n']
|
||||
url.append(f"{name}${value}_{_List}_setting")
|
||||
vod_play_url.append('#'.join(url))
|
||||
vod['vod_play_from'] = '$$$'.join(vod_play_from)
|
||||
vod['vod_play_url'] = '$$$'.join(vod_play_url)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def setting_liveExtra_detailContent(self):
|
||||
vod = {
|
||||
"vod_name": "查看直播细化标签",
|
||||
"vod_content": '点击想要添加的标签,同一标签第一次点击为添加,第二次删除,完成后在[标签与筛选]页继续操作,以添加到直播筛选分区列中',
|
||||
}
|
||||
vod_play_from = ['已添加']
|
||||
cateManualLiveExtra = self.userConfig.get('cateManualLiveExtra', [])
|
||||
vod_play_url = ['点击相应标签(只)可以删除$ #清空$clear_liveFilter_setting']
|
||||
for name in cateManualLiveExtra:
|
||||
value = name['v']
|
||||
name = name['n']
|
||||
vod_play_url.append(name + '$' + 'del_' + name + '_' + value + '_liveFilter_setting')
|
||||
vod_play_url = ['#'.join(vod_play_url)]
|
||||
cateLive = self.userConfig.get('cateLive', {})
|
||||
for parent, parent_dic in cateLive.items():
|
||||
area_dic = parent_dic['value']['value']
|
||||
if len(area_dic) == 1:
|
||||
continue
|
||||
vod_play_from.append(parent)
|
||||
url = []
|
||||
for area in area_dic:
|
||||
name = str(area['n']).replace('_', '-').replace("#", "﹟").replace("$", "﹩")
|
||||
id = str(area['v']).replace('_', '@@@').replace("#", "﹟").replace("$", "﹩")
|
||||
url.append(name + '$add_' + name + '_' + id + '_liveFilter_setting')
|
||||
vod_play_url.append('#'.join(url))
|
||||
vod['vod_play_from'] = '$$$'.join(vod_play_from)
|
||||
vod['vod_play_url'] = '$$$'.join(vod_play_url)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def get_all_season(self, season):
|
||||
season_id = str(season['season_id'])
|
||||
season_title = season['season_title']
|
||||
if season_id == self.detailContent_args['ssid']:
|
||||
self.detailContent_args['s_title'] = season_title
|
||||
pic = season['cover']
|
||||
remark = season['new_ep']['index_show']
|
||||
result = {
|
||||
"vod_id": season_id + 'ss',
|
||||
"vod_name": '系列:' + season_title,
|
||||
"vod_pic": self.format_img(pic),
|
||||
"vod_remarks": remark}
|
||||
return result
|
||||
|
||||
def get_bangumi_section(self, section):
|
||||
sec_title = section['title'].replace("#", "﹟").replace("$", "﹩")
|
||||
sec_type = section['type']
|
||||
if sec_type in [1, 2] and len(section['episode_ids']) == 0:
|
||||
episodes = section['episodes']
|
||||
playUrl = '#'.join(map(lambda x: self.get_normal_episodes(x)[0], episodes))
|
||||
return (sec_title, playUrl)
|
||||
|
||||
def ysContent(self, array):
|
||||
aid = array[0]
|
||||
if 'ep' in aid:
|
||||
self.detailContent_args['fromep'] = aid
|
||||
aid = 'ep_id=' + aid.replace('ep', '')
|
||||
elif 'ss' in aid:
|
||||
aid = 'season_id=' + aid.replace('ss', '')
|
||||
url = "https://api.bilibili.com/pgc/view/web/season?{0}".format(aid)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jRoot = json.loads(rsp.text)
|
||||
jo = jRoot['result']
|
||||
self.detailContent_args['ssid'] = str(jo['season_id'])
|
||||
title = jo['title']
|
||||
self.detailContent_args['s_title'] = jo['season_title']
|
||||
self.detailContent_args['title_type'] = '集'
|
||||
if jo['type'] in [1, 4]:
|
||||
self.detailContent_args['title_type'] = '话'
|
||||
#添加系列到搜索
|
||||
seasons = jo.get('seasons')
|
||||
if len(seasons) == 1:
|
||||
self.detailContent_args['s_title'] = seasons[0]['season_title']
|
||||
seasons = 0
|
||||
else:
|
||||
self.detailContent_args['seasons'] = list(self.pool.map(self.get_all_season, seasons))
|
||||
#获取正片
|
||||
episodes = jo.get('episodes')
|
||||
#获取花絮
|
||||
section_task = []
|
||||
for s in jo.get('section', []):
|
||||
if s:
|
||||
t = self.pool.submit(self.get_bangumi_section, s)
|
||||
section_task.append(t)
|
||||
pic = jo['cover']
|
||||
typeName = jo['share_sub_title']
|
||||
date = jo['publish']['pub_time'][0:4]
|
||||
dec = jo['evaluate']
|
||||
remark = jo['new_ep']['desc']
|
||||
stat = jo['stat']
|
||||
# 演员和导演框展示视频状态,包括以下内容:
|
||||
status = "▶" + self.zh(stat['views']) + " ❤" + self.zh(stat['favorites'])
|
||||
vod = {
|
||||
"vod_id": 'ss' + self.detailContent_args['ssid'],
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": typeName,
|
||||
"vod_year": date,
|
||||
"vod_actor": status,
|
||||
"vod_content": dec
|
||||
}
|
||||
if self.isFongmi:
|
||||
if seasons:
|
||||
remark += ' [a=cr:{"id": "_getbangumiseasons","name": "' + title.replace('"', '\\"') + '"}/]更多系列[/a]'
|
||||
seasons = 0
|
||||
if 'rating' in jo:
|
||||
remark = str(jo['rating']['score']) + '分 ' + remark
|
||||
self.userConfig['show_vod_hot_reply'] = False
|
||||
else:
|
||||
vod["vod_area"] = "bilidanmu"
|
||||
vod["vod_remarks"] = remark
|
||||
ZhuiPf = []
|
||||
ZhuiPu = []
|
||||
if self.userid:
|
||||
ZhuiPf = ['做点什么']
|
||||
ZhuiPu = '是否追番剧$ #❤追番剧$add_notplay_zhui#💔取消追番剧$del_notplay_zhui'
|
||||
defaultQn = int(self.userConfig['vodDefaultQn'])
|
||||
if defaultQn > 116:
|
||||
ZhuiPu += '#⚠️限高1080$116_notplay_vodTMPQn'
|
||||
ZhuiPu = [ZhuiPu]
|
||||
if seasons:
|
||||
ZhuiPf.append('更多系列')
|
||||
ZhuiPu.append('更多系列在快速搜索中查看$ #')
|
||||
FirstPf = []
|
||||
FirstPu = []
|
||||
PreviewPf = []
|
||||
PreviewPu = []
|
||||
ParsePf = []
|
||||
ParsePu = []
|
||||
if episodes:
|
||||
for x, y in self.pool.map(self.get_normal_episodes, episodes):
|
||||
if y:
|
||||
FirstPu.append(x)
|
||||
ParsePu.append(y)
|
||||
else:
|
||||
PreviewPu.append(x)
|
||||
if FirstPu:
|
||||
FirstPf = [self.detailContent_args['s_title']]
|
||||
FirstPu = ['#'.join(FirstPu)]
|
||||
if PreviewPu:
|
||||
PreviewPf = ['预告']
|
||||
PreviewPu = ['#'.join(PreviewPu)]
|
||||
if not self.detailContent_args.get('parse'):
|
||||
ParsePu = []
|
||||
if ParsePu:
|
||||
ParsePf = [str(self.detailContent_args['s_title']) + '【解析】']
|
||||
ParsePu = ['#'.join(ParsePu)]
|
||||
fromL = ParsePf + FirstPf + PreviewPf
|
||||
urlL = ParsePu + FirstPu + PreviewPu
|
||||
for t in as_completed(section_task):
|
||||
s = t.result()
|
||||
if s:
|
||||
fromL.append(s[0])
|
||||
urlL.append(s[1])
|
||||
fromep = self.detailContent_args.get('fromep', '')
|
||||
if '_' in fromep:
|
||||
fromL = ['B站'] + fromL
|
||||
urlL = [fromep] + urlL
|
||||
if self.userConfig['show_vod_hot_reply']:
|
||||
self.get_vod_hot_reply_event.wait()
|
||||
ReplyPu = self.detailContent_args.get('Reply', '')
|
||||
if ReplyPu:
|
||||
ZhuiPf.append('热门评论')
|
||||
ZhuiPu.append(ReplyPu)
|
||||
fromL.insert(1, '$$$'.join(ZhuiPf))
|
||||
urlL.insert(1, '$$$'.join(ZhuiPu))
|
||||
vod['vod_play_from'] = '$$$'.join(fromL)
|
||||
vod['vod_play_url'] = '$$$'.join(urlL)
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def get_live_api2_playurl(self, room_id):
|
||||
playFrom = []
|
||||
playUrl = []
|
||||
url = 'https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?room_id={0}&no_playurl=0&mask=1&qn=0&platform=web&protocol=0,1&format=0,1,2&codec=0,1&dolby=5&panorama=1'.format(room_id)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
playurl_info = jo['data'].get('playurl_info', '')
|
||||
if playurl_info:
|
||||
stream = playurl_info['playurl']['stream']
|
||||
liveDic = {
|
||||
'codec': {'avc': '0', 'hevc': '1'},
|
||||
'format': {'flv': '0', 'ts': '1', 'fmp4': '2'},
|
||||
}
|
||||
liveDic['qn'] = dict(self.pool.map(lambda x:(x['qn'], x['desc']), playurl_info['playurl']['g_qn_desc']))
|
||||
vodList = []
|
||||
for i in stream:
|
||||
vodList.extend(i['format'])
|
||||
api2_playUrl = {}
|
||||
for v in vodList:
|
||||
format = str(v.get('format_name'))
|
||||
for c in v['codec']:
|
||||
codec = str(c.get('codec_name'))
|
||||
accept_qn = c.get('accept_qn')
|
||||
for qn in accept_qn:
|
||||
url = format + '_' + codec + '$liveapi2_' + str(qn) + '_' + liveDic['format'][format] + '_' + liveDic['codec'][codec] + '_' + str(room_id)
|
||||
if not api2_playUrl.get(liveDic['qn'][qn]):
|
||||
api2_playUrl[liveDic['qn'][qn]] = []
|
||||
api2_playUrl[liveDic['qn'][qn]].append(url)
|
||||
for key, value in api2_playUrl.items():
|
||||
playFrom.append(key)
|
||||
playUrl.append('#'.join(value))
|
||||
result = {'From': playFrom, 'url': playUrl}
|
||||
return result
|
||||
|
||||
def live_detailContent(self, array):
|
||||
room_id = array[0]
|
||||
get_live_api2_playurl = self.pool.submit(self.get_live_api2_playurl, room_id)
|
||||
url = "https://api.live.bilibili.com/room/v1/Room/get_info?room_id=" + str(room_id)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jRoot = json.loads(rsp.text)
|
||||
result = {}
|
||||
if jRoot.get('code') == 0:
|
||||
jo = jRoot['data']
|
||||
self.detailContent_args['mid'] = mid = str(jo["uid"])
|
||||
self.get_up_info_event.clear()
|
||||
self.pool.submit(self.get_up_info, mid)
|
||||
title = jo['title'].replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
pic = jo.get("user_cover")
|
||||
desc = jo.get('description')
|
||||
typeName = jo.get('parent_area_name') + '--' + jo.get('area_name')
|
||||
live_status = jo.get('live_status', '')
|
||||
if live_status:
|
||||
live_status = "开播时间:" + jo.get('live_time').replace('-', '.')
|
||||
else:
|
||||
live_status = "未开播"
|
||||
vod = {
|
||||
"vod_id": room_id,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": typeName,
|
||||
"vod_content": desc,
|
||||
}
|
||||
remark = "房间号:" + room_id + " " + live_status
|
||||
if self.isFongmi:
|
||||
vod["vod_remarks"] = remark
|
||||
else:
|
||||
vod["vod_actor"] = remark
|
||||
vod["vod_area"] = "bililivedanmu"
|
||||
secondPFrom = ''
|
||||
secondP = ''
|
||||
if self.userid:
|
||||
secondPFrom = '关注Ta'
|
||||
first = '是否关注$ '
|
||||
follow = '➕关注$1_notplay_follow'
|
||||
unfollow = '➖取关$2_notplay_follow'
|
||||
secondPList = [first, follow, unfollow]
|
||||
secondP = '#'.join(secondPList)
|
||||
playFrom = get_live_api2_playurl.result().get('From', [])
|
||||
playUrl = get_live_api2_playurl.result().get('url', [])
|
||||
if playFrom:
|
||||
api1_playFrom = 'API_1'
|
||||
api1_playUrl = 'flv线路原画$platform=web&quality=4_' + room_id + '#flv线路高清$platform=web&quality=3_' + room_id + '#h5线路原画$platform=h5&quality=4_' + room_id + '#h5线路高清$platform=h5&quality=3_' + room_id
|
||||
playFrom.append(api1_playFrom)
|
||||
playUrl.append(api1_playUrl)
|
||||
if secondPFrom:
|
||||
playFrom.insert(1, secondPFrom)
|
||||
playUrl.insert(1, secondP)
|
||||
vod['vod_play_from'] = '$$$'.join(playFrom)
|
||||
vod['vod_play_url'] = '$$$'.join(playUrl)
|
||||
self.get_up_info_event.wait()
|
||||
up_info = self.up_info[mid]
|
||||
vod["vod_director"] = '🆙 ' + up_info['crname'] + " 👥 " + self.zh(jo.get('attention')) + ' ' + up_info['following']
|
||||
result['list'] = [vod]
|
||||
return result
|
||||
|
||||
search_key = ''
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
if not self.session_fake.cookies:
|
||||
self.pool.submit(self.getFakeCookie, True)
|
||||
for t in self.task_pool:
|
||||
t.cancel()
|
||||
self.task_pool = []
|
||||
self.search_key = key
|
||||
mid = self.detailContent_args.get('mid', '')
|
||||
if quick and mid:
|
||||
get_up_videos = self.pool.submit(self.get_up_videos, mid, 1, 'quicksearch')
|
||||
types = {'video': '','media_bangumi': '番剧: ', 'media_ft': '影视: ', 'bili_user': '用户: ', 'live': '直播: '}
|
||||
for type, value in types.items():
|
||||
t = self.pool.submit(self.get_search_content, key = key, pg = value, duration_diff = 0, order = '', type = type, ps = self.userConfig['page_size'])
|
||||
self.task_pool.append(t)
|
||||
result = {'list': []}
|
||||
for t in as_completed(self.task_pool):
|
||||
res = t.result().get('list', [])
|
||||
result['list'].extend(res)
|
||||
self.task_pool.remove(t)
|
||||
if quick:
|
||||
if not self.isFongmi:
|
||||
if mid:
|
||||
result['list'] = self.detailContent_args.get('interaction', []) + get_up_videos.result().get('list', []) + self.detailContent_args.get('Reply_jump', []) + result['list']
|
||||
else:
|
||||
result['list'] = self.detailContent_args.get('seasons', []) + result['list']
|
||||
return result
|
||||
|
||||
stop_heartbeat_event = threading.Event()
|
||||
|
||||
def start_heartbeat(self, aid, cid, ids):
|
||||
duration = ssid = epid = ''
|
||||
for i in ids:
|
||||
if 'ss' in i:
|
||||
ssid = i.replace('ss', '')
|
||||
elif 'ep' in i:
|
||||
epid = i.replace('ep', '')
|
||||
elif 'dur' in i:
|
||||
duration = int(i.replace('dur', ''))
|
||||
url = 'https://api.bilibili.com/x/player/v2?aid={0}&cid={1}'.format(aid, cid)
|
||||
rsp = self._get_sth(url)
|
||||
jo = json.loads(rsp.text)
|
||||
data = jo.get('data',{})
|
||||
interaction = data.get('interaction', {})
|
||||
if interaction.get('graph_version'):
|
||||
graph_version = interaction.get('graph_version')
|
||||
old = self.detailContent_args.get('graph_version')
|
||||
if old != graph_version:
|
||||
self.detailContent_args['graph_version'] = graph_version
|
||||
self.pool.submit(self.interaction_detailContent)
|
||||
heartbeatInterval = int(self.userConfig['heartbeatInterval'])
|
||||
if not self.userid or not heartbeatInterval:
|
||||
return
|
||||
if not duration:
|
||||
url = 'https://api.bilibili.com/x/web-interface/view?aid={0}&cid={1}'.format(aid, cid)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jRoot = json.loads(rsp.text)
|
||||
duration = jRoot['data']['duration']
|
||||
played_time = 0
|
||||
if int(data.get('last_play_cid', 0)) == int(cid):
|
||||
last_play_time = int(data.get('last_play_time'))
|
||||
if last_play_time > 0:
|
||||
played_time = int(last_play_time / 1000)
|
||||
heartbeat_times = int((duration - played_time) / heartbeatInterval) + 1
|
||||
url = 'https://api.bilibili.com/x/click-interface/web/heartbeat'
|
||||
data = {'aid': str(aid), 'cid': str(cid), 'csrf': str(self.csrf)}
|
||||
if ssid:
|
||||
data['sid'] = str(ssid)
|
||||
data['epid'] = str(epid)
|
||||
data['type'] = '4'
|
||||
heartbeat_count = 0
|
||||
self.stop_heartbeat_event.clear()
|
||||
while True:
|
||||
if heartbeat_count == heartbeatInterval or self.stop_heartbeat_event.is_set():
|
||||
played_time += heartbeat_count
|
||||
heartbeat_count = 0
|
||||
if not heartbeat_count:
|
||||
heartbeat_times -= 1
|
||||
if not heartbeat_times:
|
||||
#播完为-1
|
||||
played_time = -1
|
||||
self.stop_heartbeat_event.set()
|
||||
data['played_time'] = str(played_time)
|
||||
self.pool.submit(self._post_sth, url=url, data=data)
|
||||
if self.stop_heartbeat_event.is_set():
|
||||
break
|
||||
time.sleep(1)
|
||||
heartbeat_count += 1
|
||||
|
||||
wbi_key = {}
|
||||
def get_wbiKey(self, wts):
|
||||
r = self.fetch("https://api.bilibili.com/x/web-interface/nav", headers=self.header)
|
||||
wbi_img_url = r.json()['data']['wbi_img']['img_url']
|
||||
wbi_sub_url = r.json()['data']['wbi_img']['sub_url']
|
||||
oe = [46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12,
|
||||
38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62,
|
||||
11, 36, 20, 34, 44, 52]
|
||||
ae = wbi_img_url.split("/")[-1].split(".")[0] + wbi_sub_url.split("/")[-1].split(".")[0]
|
||||
le = reduce(lambda s, i: s + ae[i], oe, "")[:32]
|
||||
self.wbi_key = {
|
||||
"key": le,
|
||||
"wts": wts
|
||||
}
|
||||
|
||||
def encrypt_wbi(self, **params):
|
||||
wts = round(time.time())
|
||||
if not self.wbi_key or abs(self.wbi_key['wts']) < 120:
|
||||
self.get_wbiKey(wts)
|
||||
params["wts"] = wts
|
||||
params["dm_img_list"] = []
|
||||
dm_rand = ['QQ','Qg','Qw','RA','RQ']
|
||||
params["dm_img_str"] = random.choice(dm_rand)
|
||||
params["dm_cover_img_str"] = random.choice(dm_rand)
|
||||
params = dict(sorted(params.items()))
|
||||
params = {k : ''.join(filter(lambda chr: chr not in "!'()*", str(v))) for k, v in params.items()}
|
||||
Ae = urlencode(params)
|
||||
return Ae + "&w_rid=" + hashlib.md5((Ae + self.wbi_key['key']).encode(encoding='utf-8')).hexdigest()
|
||||
|
||||
def _get_sth(self, url, _type='master'):
|
||||
if _type == 'vip' and self.session_vip.cookies:
|
||||
rsp = self.session_vip.get(url, headers=self.header)
|
||||
elif _type == 'fake':
|
||||
if not self.session_fake.cookies:
|
||||
self.getFakeCookie_event.wait()
|
||||
rsp = self.session_fake.get(url, headers=self.header)
|
||||
else:
|
||||
rsp = self.session_master.get(url, headers=self.header)
|
||||
return rsp
|
||||
|
||||
def _post_sth(self, url, data):
|
||||
return self.session_master.post(url, headers=self.header, data=data)
|
||||
|
||||
def post_live_history(self, room_id):
|
||||
data = {'room_id': str(room_id), 'platform': 'pc', 'csrf': str(self.csrf)}
|
||||
url = 'https://api.live.bilibili.com/xlive/web-room/v1/index/roomEntryAction'
|
||||
self._post_sth(url=url, data=data)
|
||||
|
||||
def do_notplay(self, ids):
|
||||
aid = self.detailContent_args.get('aid')
|
||||
mid = self.detailContent_args.get('mid')
|
||||
ssid = self.detailContent_args.get('ssid')
|
||||
data = {'csrf': str(self.csrf)}
|
||||
url = ''
|
||||
if 'vodTMPQn' in ids:
|
||||
self.detailContent_args['vodTMPQn'] = str(ids[0])
|
||||
return
|
||||
elif 'follow' in ids:
|
||||
if 'special' in ids:
|
||||
data.update({'fids': str(mid), 'tagids': str(ids[0])})
|
||||
url = 'https://api.bilibili.com/x/relation/tags/addUsers'
|
||||
else:
|
||||
data.update({'fid': str(mid), 'act': str(ids[0])})
|
||||
url = 'https://api.bilibili.com/x/relation/modify'
|
||||
elif 'zhui' in ids:
|
||||
data.update({'season_id': str(ssid)})
|
||||
url = 'https://api.bilibili.com/pgc/web/follow/' + str(ids[0])
|
||||
elif 'like' in ids:
|
||||
data.update({'aid': str(aid), 'like': str(ids[0])})
|
||||
url = 'https://api.bilibili.com/x/web-interface/archive/like'
|
||||
elif 'coin' in ids:
|
||||
data.update({'aid': str(aid), 'multiply': str(ids[0]), 'select_like': '1'})
|
||||
url = 'https://api.bilibili.com/x/web-interface/coin/add'
|
||||
elif 'fav' in ids:
|
||||
data.update({'rid': str(aid), 'type': '2'})
|
||||
data[ids[1] + '_media_ids'] = str(ids[0])
|
||||
url = 'https://api.bilibili.com/x/v3/fav/resource/deal'
|
||||
elif 'triple' in ids:
|
||||
data.update({'aid': str(aid)})
|
||||
url = 'https://api.bilibili.com/x/web-interface/archive/like/triple'
|
||||
elif 'reply' in ids:
|
||||
data.update({'oid': str(ids[0]), 'rpid': str(ids[1]), 'type': '1', 'action': '1'})
|
||||
url = 'http://api.bilibili.com/x/v2/reply/action'
|
||||
self._post_sth(url=url, data=data)
|
||||
|
||||
def get_cid(self, video):
|
||||
url = "https://api.bilibili.com/x/web-interface/view?aid=%s" % str(video['aid'])
|
||||
rsp = self._get_sth(url)
|
||||
jRoot = json.loads(rsp.text)
|
||||
jo = jRoot['data']
|
||||
video['cid'] = jo['cid']
|
||||
video['duration'] = jo['duration']
|
||||
if 'redirect_url' in jo and 'bangumi' in jo['redirect_url']:
|
||||
video['ep'] = self.find_bangumi_id(jo['redirect_url'])
|
||||
|
||||
cookie_dic_tmp = {}
|
||||
|
||||
def get_cookies(self, key):
|
||||
url = 'https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=' + key
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
message = jo['data']['message']
|
||||
if not message:
|
||||
self.cookie_dic_tmp[key] = dict(self.session_fake.cookies)
|
||||
self.pool.submit(self.getFakeCookie)
|
||||
return message
|
||||
return '网络错误'
|
||||
|
||||
def set_cookie(self, key, _type):
|
||||
cookie_dic_tmp = self.cookie_dic_tmp.get(key, '')
|
||||
if not cookie_dic_tmp:
|
||||
message = self.get_cookies(key)
|
||||
if message:
|
||||
return
|
||||
users = self.userConfig.get('users', {})
|
||||
users[_type] = {'cookies_dic': self.cookie_dic_tmp.get(key, {})}
|
||||
self.userConfig.update({'users': users})
|
||||
self.getCookie(_type)
|
||||
self.dump_config()
|
||||
|
||||
def unset_cookie(self, _type):
|
||||
if _type == 'vip':
|
||||
self.session_vip.cookies.clear()
|
||||
else:
|
||||
self.session_master.cookies = self.session_fake.cookies
|
||||
self.userid = self.csrf = ''
|
||||
if _type in self.userConfig.get('users', {}):
|
||||
self.userConfig['users'].pop(_type)
|
||||
self.dump_config()
|
||||
|
||||
def set_normal_default(self, id, type):
|
||||
self.userConfig[type] = str(id)
|
||||
self.dump_config()
|
||||
|
||||
def set_normal_cateManual(self, name, _List, action):
|
||||
List_tmp = self.userConfig.get(str(_List) + '_tmp')
|
||||
if not List_tmp:
|
||||
List_tmp = self.userConfig[str(_List) + '_tmp'] = []
|
||||
if action == 'save':
|
||||
for _item in self.defaultConfig[_List]:
|
||||
if not _item in List_tmp.copy():
|
||||
self.userConfig[str(_List) + '_tmp'].append(_item)
|
||||
self.userConfig[_List] = self.userConfig[str(_List) + '_tmp'].copy()
|
||||
self.userConfig.pop(_List + '_tmp')
|
||||
self.dump_config()
|
||||
elif action == 'clear':
|
||||
self.userConfig[_List] = self.defaultConfig[_List].copy()
|
||||
self.userConfig.pop(str(_List) + '_tmp')
|
||||
self.dump_config()
|
||||
else:
|
||||
if _List == 'cateManualLive':
|
||||
name = name.split('@@@')
|
||||
if len(name) == 3:
|
||||
name[1] += '_' + str(name[2])
|
||||
name = {'n': name[0], 'v': str(name[1])}
|
||||
if name in List_tmp:
|
||||
self.userConfig[str(_List) + '_tmp'].remove(name)
|
||||
else:
|
||||
self.userConfig[str(_List) + '_tmp'].append(name)
|
||||
|
||||
def add_cateManualLiveExtra(self, action, name, id):
|
||||
_Extra = self.userConfig.get('cateManualLiveExtra', [])
|
||||
if not _Extra:
|
||||
_Extra = self.userConfig['cateManualLiveExtra'] = []
|
||||
if action == 'clear':
|
||||
for _ext in _Extra:
|
||||
_ext['v'] = _ext['v'].replace('@@@', '_')
|
||||
if _ext in self.userConfig.get('cateManualLive', []):
|
||||
self.userConfig['cateManualLive'].remove(_ext)
|
||||
if _ext in self.userConfig.get('cateManualLive_tmp', []):
|
||||
self.userConfig['cateManualLive_tmp'].remove(_ext)
|
||||
self.userConfig.pop('cateManualLiveExtra')
|
||||
elif id in list(map(lambda x:x['v'], self.userConfig.get('cateManualLiveExtra', []))):
|
||||
area_dict = {'n': name, 'v': id}
|
||||
self.userConfig['cateManualLiveExtra'].remove(area_dict)
|
||||
area_dict['v'] = id.replace('@@@', '_')
|
||||
if area_dict in self.userConfig.get('cateManualLive', []):
|
||||
self.userConfig['cateManualLive'].remove(area_dict)
|
||||
if area_dict in self.userConfig.get('cateManualLive_tmp', []):
|
||||
self.userConfig['cateManualLive_tmp'].remove(area_dict)
|
||||
else:
|
||||
area_dict = {'n': name, 'v': id}
|
||||
self.userConfig['cateManualLiveExtra'].append(area_dict)
|
||||
self.dump_config()
|
||||
|
||||
vod_qn_id = {
|
||||
'127': "8K",
|
||||
'126': "杜比视界",
|
||||
'125': "HDR",
|
||||
'120': "4K",
|
||||
'116': "1080P60帧",
|
||||
'112': "1080P+",
|
||||
'80': "1080P",
|
||||
'64': "720P",
|
||||
}
|
||||
vod_codec_id = {
|
||||
'7': 'avc',
|
||||
'12': 'hevc',
|
||||
'13': 'av1',
|
||||
}
|
||||
vod_audio_id = {
|
||||
'30280': '192000',
|
||||
'30232': '132000',
|
||||
'30216': '64000',
|
||||
}
|
||||
|
||||
def get_dash_media(self, video):
|
||||
qnid = str(video.get('id'))
|
||||
codecid = video.get('codecid')
|
||||
media_codecs = video.get('codecs')
|
||||
media_bandwidth = video.get('bandwidth')
|
||||
media_startWithSAP = video.get('startWithSap')
|
||||
media_mimeType = video.get('mimeType')
|
||||
media_BaseURL = video.get('baseUrl').replace('&', '&')
|
||||
media_SegmentBase_indexRange = video['SegmentBase'].get('indexRange')
|
||||
media_SegmentBase_Initialization = video['SegmentBase'].get('Initialization')
|
||||
mediaType = media_mimeType.split('/')[0]
|
||||
if mediaType == 'video':
|
||||
media_frameRate = video.get('frameRate')
|
||||
media_sar = video.get('sar')
|
||||
media_width = video.get('width')
|
||||
media_height = video.get('height')
|
||||
media_type_params = f"height='{media_height}' width='{media_width}' frameRate='{media_frameRate}' sar='{media_sar}'"
|
||||
elif mediaType == 'audio':
|
||||
audioSamplingRate = self.vod_audio_id.get(qnid, '192000')
|
||||
media_type_params = f"numChannels='2' sampleRate='{audioSamplingRate}'"
|
||||
if codecid:
|
||||
qnid += '_' + str(codecid)
|
||||
result = f"""
|
||||
<Representation id="{qnid}" bandwidth="{media_bandwidth}" codecs="{media_codecs}" mimeType="{media_mimeType}" {media_type_params} startWithSAP="{media_startWithSAP}">
|
||||
<BaseURL>{media_BaseURL}</BaseURL>
|
||||
<SegmentBase indexRange="{media_SegmentBase_indexRange}">
|
||||
<Initialization range="{media_SegmentBase_Initialization}"/>
|
||||
</SegmentBase>
|
||||
</Representation>"""
|
||||
return result
|
||||
|
||||
def get_dash_media_list(self, media_lis):
|
||||
if not media_lis:
|
||||
return ""
|
||||
mediaType = media_lis[0]['mimeType'].split('/')[0]
|
||||
defaultQn = defaultCodec = ''
|
||||
if mediaType == 'video':
|
||||
defaultQn = vodTMPQn = self.detailContent_args.get('vodTMPQn', '')
|
||||
if vodTMPQn:
|
||||
vodTMPQn = int(vodTMPQn)
|
||||
else:
|
||||
defaultQn = str(self.userConfig['vodDefaultQn'])
|
||||
vodTMPQn = 120
|
||||
defaultCodec = str(self.userConfig['vodDefaultCodec'])
|
||||
elif mediaType == 'audio':
|
||||
defaultQn = str(self.userConfig['vodDefaultAudio'])
|
||||
vodTMPQn = int(defaultQn)
|
||||
defaultCodec = '0'
|
||||
qn_codec = list(map(lambda x: str(x['id']) + '_' + str(x['codecid']), media_lis))
|
||||
Qn_available_lis = []
|
||||
#按设定的质量和设定的编码找
|
||||
if defaultQn + '_' + defaultCodec in qn_codec:
|
||||
Qn_available_lis.append(media_lis[qn_codec.index(defaultQn + '_' + defaultCodec)])
|
||||
#按设定的质量找推荐的编码
|
||||
if not Qn_available_lis and mediaType == 'video':
|
||||
for c in self.vod_codec_id.keys():
|
||||
if defaultQn + '_' + str(c) in qn_codec:
|
||||
Qn_available_lis.append(media_lis[qn_codec.index(defaultQn + '_' + str(c))])
|
||||
#找4K及以下最高可用画质/音质
|
||||
if not Qn_available_lis:
|
||||
qn_top = ''
|
||||
for q in qn_codec:
|
||||
q_c = q.split('_')
|
||||
if qn_top and int(qn_top) > int(q_c[0]):
|
||||
break
|
||||
elif mediaType == 'video' and int(q_c[0]) <= vodTMPQn and not qn_top or mediaType == 'audio' and not qn_top or int(q_c[0]) == qn_top:
|
||||
qn_top = int(q_c[0])
|
||||
#匹配设定的编码,否则全部
|
||||
if mediaType == 'video' and str(q_c[1]) == defaultCodec:
|
||||
Qn_available_lis = [media_lis[qn_codec.index(str(q))]]
|
||||
break
|
||||
Qn_available_lis.append(media_lis[qn_codec.index(str(q))])
|
||||
result = f"""
|
||||
<AdaptationSet>
|
||||
<ContentComponent contentType="{mediaType}"/>{''.join(map(self.get_dash_media, Qn_available_lis))}
|
||||
</AdaptationSet>"""
|
||||
return result
|
||||
|
||||
get_dash_event = threading.Event()
|
||||
def get_dash(self, ja):
|
||||
duration = ja.get('duration')
|
||||
minBufferTime = ja.get('minBufferTime')
|
||||
video_list = self.pool.submit(self.get_dash_media_list, ja.get('video'))
|
||||
audio_list = self.pool.submit(self.get_dash_media_list, ja.get('audio'))
|
||||
mpd = f"""<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" type="static" mediaPresentationDuration="PT{duration}S" minBufferTime="PT{minBufferTime}S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
|
||||
<Period duration="PT{duration}S" start="PT0S">{video_list.result()}{audio_list.result()}
|
||||
</Period>
|
||||
</MPD>"""
|
||||
with open(f"{dirname}/playurl.mpd", 'w', encoding="utf-8") as f:
|
||||
f.write(mpd)
|
||||
self.get_dash_event.set()
|
||||
#time.sleep(3)
|
||||
#os.remove(f"{dirname}/playurl.mpd")
|
||||
|
||||
def get_durl(self, ja):
|
||||
maxSize = -1
|
||||
position = -1
|
||||
for i in range(len(ja)):
|
||||
tmpJo = ja[i]
|
||||
if maxSize < int(tmpJo['size']):
|
||||
maxSize = int(tmpJo['size'])
|
||||
position = i
|
||||
url = ''
|
||||
if len(ja) > 0:
|
||||
if position == -1:
|
||||
position = 0
|
||||
url = ja[position]['url']
|
||||
return url
|
||||
|
||||
def miao(self, m):
|
||||
m = str(m).partition('.')[2] #取小数部分
|
||||
if len(m)==0:m = '000' #补齐三位小数
|
||||
if len(m)==1:m = m + '00'
|
||||
if len(m)==2:m = m + '0'
|
||||
return m #返回标准三位的毫秒数
|
||||
|
||||
def down_sub(self, url):
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
data = json.loads(rsp.text)['body']
|
||||
srt = ''
|
||||
for d in data:
|
||||
f = round(d['from'],3) # 开始时间 (round(n,3)四舍五入为三位小数)
|
||||
t = round(d['to'],3) # 结束时间
|
||||
c = d['content'] # 字幕内容
|
||||
ff = time.strftime("%H:%M:%S",time.gmtime(f)) + ',' + self.miao(f) # 开始时间,秒数转 时:分:秒 格式,加逗号、毫秒修正为三位
|
||||
tt = time.strftime("%H:%M:%S",time.gmtime(t)) + ',' + self.miao(t) # 结束时间,处理方式同上
|
||||
srt += '\n' + ff + ' ' + '-->' + ' ' + tt + '\n' + c + '\n\n' # 格式化为Srt字幕
|
||||
return srt
|
||||
|
||||
localProxyUrl = 'http://127.0.0.1:UndCover/proxy'
|
||||
|
||||
def get_subs(self, aid, cid):
|
||||
result = []
|
||||
query = self.encrypt_wbi(aid=aid, cid=cid)
|
||||
url = f'https://api.bilibili.com/x/player/wbi/v2?{query}'
|
||||
rsp = self._get_sth(url, 'master')
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] == 0:
|
||||
for sub in jRoot['data']['subtitle'].get('subtitles', []):
|
||||
lanDoc = str(sub.get('lan_doc', ''))
|
||||
lanUrl = sub.get('subtitle_url')
|
||||
if lanUrl.startswith('//'):
|
||||
lanUrl = 'https:' + lanUrl
|
||||
lanUrl = base64.b64encode(lanUrl.encode('utf-8')).decode('utf-8')
|
||||
result.append(
|
||||
{
|
||||
"url": f"{self.localProxyUrl}&siteType=3&siteKey=py_bilibili&type=subtitle&url={lanUrl}",
|
||||
"name": lanDoc,
|
||||
"format": "application/x-subrip"
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
self.stop_heartbeat_event.set()
|
||||
result = {'playUrl': '', 'url': ''}
|
||||
ids = id.split("_")
|
||||
if 'web' in id or 'liveapi2' == ids[0]:
|
||||
return self.live_playerContent(flag, id, vipFlags)
|
||||
if len(ids) < 2:
|
||||
return result
|
||||
aid = ids[0]
|
||||
cid = ids[1]
|
||||
if 'setting' in ids:
|
||||
if 'liveFilter' in id:
|
||||
id = ids[2]
|
||||
self.add_cateManualLiveExtra(aid, cid, id)
|
||||
elif cid in ['cateManual', 'cateManualLive', 'tuijianLis', 'rankingLis']:
|
||||
action = ids[2]
|
||||
self.set_normal_cateManual(aid, cid, action)
|
||||
elif 'login' in id:
|
||||
self.set_cookie(aid, cid)
|
||||
elif 'logout' in id:
|
||||
self.unset_cookie(aid)
|
||||
else:
|
||||
self.set_normal_default(aid, cid)
|
||||
return result
|
||||
elif 'notplay' in ids:
|
||||
self.pool.submit(self.do_notplay, ids)
|
||||
return result
|
||||
elif cid == 'cid' or not cid:
|
||||
video = {'aid': str(aid)}
|
||||
self.get_cid(video, )
|
||||
cid = video['cid']
|
||||
ids.append('dur' + str(video['duration']))
|
||||
ep = video.get('ep')
|
||||
if ep:
|
||||
id += '_' + ep
|
||||
ids.append(ep)
|
||||
query = self.encrypt_wbi(avid=aid, cid=cid, fnval=4048, fnver=0, fourk=1)
|
||||
url = f'https://api.bilibili.com/x/player/wbi/playurl?{query}'
|
||||
if 'ep' in id:
|
||||
if 'parse' in id:
|
||||
test = list(x for x in map(lambda x: x if 'ep' in x else None, ids) if x is not None)
|
||||
url = 'https://www.bilibili.com/bangumi/play/' + test[0]
|
||||
result["url"] = url
|
||||
result["flag"] = 'bilibili'
|
||||
result["parse"] = '1'
|
||||
result['jx'] = '1'
|
||||
result["header"] = str({"User-Agent": self.header["User-Agent"]})
|
||||
result["danmaku"] = 'https://api.bilibili.com/x/v1/dm/list.so?oid=' + str(cid)
|
||||
return result
|
||||
url = 'https://api.bilibili.com/pgc/player/web/playurl?aid={}&cid={}&fnval=4048&fnver=0&fourk=1'.format(aid, cid)
|
||||
rsp = self._get_sth(url, 'vip')
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] == 0:
|
||||
if 'data' in jRoot:
|
||||
jo = jRoot['data']
|
||||
elif 'result' in jRoot:
|
||||
jo = jRoot['result']
|
||||
else:
|
||||
return result
|
||||
else:
|
||||
return result
|
||||
ja = jo.get('dash')
|
||||
if ja:
|
||||
self.get_dash_event.clear()
|
||||
get_dash = self.pool.submit(self.get_dash, ja)
|
||||
self.get_dash_event.wait()
|
||||
result["url"] = f"{dirname}/playurl.mpd"
|
||||
else:
|
||||
result["url"] = self.get_durl(jo.get('durl', {}))
|
||||
result["parse"] = '0'
|
||||
result["contentType"] = ''
|
||||
result["header"] = self.header
|
||||
result["danmaku"] = 'https://api.bilibili.com/x/v1/dm/list.so?oid=' + str(cid)
|
||||
if self.isFongmi:
|
||||
result["subs"] = self.get_subs(aid, cid)
|
||||
#回传播放记录
|
||||
self.pool.submit(self.start_heartbeat, aid, cid, ids)
|
||||
return result
|
||||
|
||||
def live_playerContent(self, flag, id, vipFlags):
|
||||
result = {'playUrl': '', 'url': ''}
|
||||
ids = id.split("_")
|
||||
if len(ids) < 2:
|
||||
return result
|
||||
# 回传观看直播记录
|
||||
if self.userid and int(self.userConfig['heartbeatInterval']) > 0:
|
||||
self.pool.submit(self.post_live_history, ids[-1])
|
||||
if ids[0] == 'liveapi2':
|
||||
qn = int(ids[1])
|
||||
format = int(ids[2])
|
||||
codec = int(ids[3])
|
||||
room_id = int(ids[-1])
|
||||
url = 'https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?room_id={0}&protocol=0,1&format={1}&codec={2}&qn={3}&ptype=8&platform=web&dolby=5&panorama=1&no_playurl=0&mask=1'.format(room_id, format, codec, qn)
|
||||
rsp = self._get_sth(url, 'fake')
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 0:
|
||||
try:
|
||||
playurl = jo['data']['playurl_info'].get('playurl')
|
||||
codec = playurl['stream'][0]['format'][0]['codec'][0]
|
||||
except:
|
||||
return result
|
||||
base_url = str(codec['base_url'])
|
||||
host = str(codec['url_info'][0]['host'])
|
||||
extra = str(codec['url_info'][0]['extra'])
|
||||
playurl = host + base_url + extra
|
||||
result["url"] = playurl
|
||||
if ".flv" in playurl:
|
||||
result["contentType"] = 'video/x-flv'
|
||||
else:
|
||||
result["contentType"] = ''
|
||||
else:
|
||||
return result
|
||||
else:
|
||||
url = 'https://api.live.bilibili.com/room/v1/Room/playUrl?cid=%s&%s' % (ids[1], ids[0])
|
||||
# raise Exception(url)
|
||||
try:
|
||||
rsp = self._get_sth(url)
|
||||
except:
|
||||
return result
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['code'] == 0:
|
||||
jo = jRoot['data']
|
||||
ja = jo['durl']
|
||||
if len(ja) > 0:
|
||||
result["url"] = ja[0]['url']
|
||||
if "h5" in ids[0]:
|
||||
result["contentType"] = ''
|
||||
else:
|
||||
result["contentType"] = 'video/x-flv'
|
||||
else:
|
||||
return result
|
||||
result["parse"] = '0'
|
||||
# result['type'] ="m3u8"
|
||||
result["header"] = {
|
||||
"Referer": "https://live.bilibili.com",
|
||||
"User-Agent": self.header["User-Agent"]
|
||||
}
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {
|
||||
"关注": [{"key": "sort", "name": "分类",
|
||||
"value": [{"n": "正在直播", "v": "正在直播"}, {"n": "最常访问", "v": "最常访问"},
|
||||
{"n": "最近关注", "v": "最近关注"}, {"n": "特别关注", "v": "特别关注"},
|
||||
{"n": "悄悄关注", "v": "悄悄关注"}, {"n": "我的粉丝", "v": "我的粉丝"}]}],
|
||||
"动态": [{"key": "order", "name": "别人投稿排序",
|
||||
"value": [{"n": "最新发布", "v": "pubdate"}, {"n": "最多播放", "v": "click"},
|
||||
{"n": "最多收藏", "v": "stow"}, {"n": "最早发布", "v": "oldest"}, {"n": "合集和列表", "v": "series"}]}, ],
|
||||
"影视": [{"key": "tid", "name": "分类",
|
||||
"value": [{"n": "番剧", "v": "1"}, {"n": "国创", "v": "4"}, {"n": "电影", "v": "2"},
|
||||
{"n": "电视剧", "v": "5"}, {"n": "纪录片", "v": "3"}, {"n": "综艺", "v": "7"}]},
|
||||
{"key": "order", "name": "排序",
|
||||
"value": [{"n": "热门", "v": "热门"}, {"n": "播放数量", "v": "2"}, {"n": "更新时间", "v": "0"},
|
||||
{"n": "最高评分", "v": "4"}, {"n": "弹幕数量", "v": "1"}, {"n": "追看人数", "v": "3"},
|
||||
{"n": "开播时间", "v": "5"}, {"n": "上映时间", "v": "6"}]},
|
||||
{"key": "season_status", "name": "付费",
|
||||
"value": [{"n": "全部", "v": "-1"}, {"n": "免费", "v": "1"},
|
||||
{"n": "付费", "v": "2%2C6"}, {"n": "大会员", "v": "4%2C6"}]}],
|
||||
"频道": [{"key": "order", "name": "排序",
|
||||
"value": [{"n": "近期热门", "v": "hot"}, {"n": "月播放量", "v": "view"},
|
||||
{"n": "最新投稿", "v": "new"}, {"n": "频道精选", "v": "featured"}, ]}, ],
|
||||
"收藏": [{"key": "order", "name": "排序",
|
||||
"value": [{"n": "收藏时间", "v": "mtime"}, {"n": "播放量", "v": "view"},
|
||||
{"n": "投稿时间", "v": "pubtime"}]}, ],
|
||||
"历史": [{"key": "type", "name": "分类",
|
||||
"value": [{"n": "全部", "v": "all"}, {"n": "视频", "v": "archive"}, {"n": "直播", "v": "live"}, {"n": "UP主", "v": "UP主"}, {"n": "稍后再看", "v": "稍后再看"}]}, ],
|
||||
"搜索": [{"key": "type", "name": "类型",
|
||||
"value": [{"n": "视频", "v": "video"}, {"n": "番剧", "v": "media_bangumi"}, {"n": "影视", "v": "media_ft"},
|
||||
{"n": "直播", "v": "live"}, {"n": "用户", "v": "bili_user"}]},
|
||||
{"key": "order", "name": "视频排序",
|
||||
"value": [{"n": "综合排序", "v": "totalrank"}, {"n": "最多点击", "v": "click"}, {"n": "最新发布", "v": "pubdate"},
|
||||
{"n": "最多收藏", "v": "stow"}, {"n": "最多弹幕", "v": "dm"}]},
|
||||
{"key": "duration", "name": "视频时长",
|
||||
"value": [{"n": "全部", "v": "0"}, {"n": "60分钟以上", "v": "4"}, {"n": "30~60分钟", "v": "3"},
|
||||
{"n": "5~30分钟", "v": "2"}, {"n": "5分钟以下", "v": "1"}]}],
|
||||
}
|
||||
}
|
||||
|
||||
header = {
|
||||
'Origin': 'https://www.bilibili.com',
|
||||
'Referer': 'https://www.bilibili.com',
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15'
|
||||
}
|
||||
|
||||
def localProxy(self, param):
|
||||
action = {
|
||||
'url': '',
|
||||
'header': '',
|
||||
'param': '',
|
||||
'type': 'string',
|
||||
'after': ''
|
||||
}
|
||||
if param['type'] == 'subtitle':
|
||||
url = base64.b64decode(param['url']).decode('utf-8')
|
||||
content = self.down_sub(url)
|
||||
return [200, "application/octet-stream", action, content]
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,322 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
from difflib import SequenceMatcher
|
||||
from urllib.parse import quote, unquote
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "B站番剧"
|
||||
|
||||
def init(self, extend):
|
||||
try:
|
||||
self.extendDict = json.loads(extend)
|
||||
except:
|
||||
self.extendDict = {}
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"番剧": "1",
|
||||
"国创": "4",
|
||||
"电影": "2",
|
||||
"综艺": "7",
|
||||
"电视剧": "5",
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if filter:
|
||||
result['filters'] = self.config['filter']
|
||||
current_year = datetime.now().year
|
||||
for resultfilter in result['filters']:
|
||||
for rf in result['filters'][resultfilter]:
|
||||
yearList = []
|
||||
if rf['key'] == 'year':
|
||||
for rfv in rf['value']:
|
||||
if rfv['n'].isdigit():
|
||||
if int(rfv['n']) < current_year:
|
||||
pos = rf['value'].index(rfv)
|
||||
for year in range(current_year, int(rfv['n']), -1):
|
||||
yearList.append({'v': '[{},{})'.format(year, year+1), 'n': str(year)})
|
||||
rf['value'].insert(pos, yearList)
|
||||
break
|
||||
else:
|
||||
break
|
||||
elif rf['key'] == 'release_date':
|
||||
for rfv in rf['value']:
|
||||
if rfv['n'].isdigit():
|
||||
if int(rfv['n']) < current_year:
|
||||
pos = rf['value'].index(rfv)
|
||||
for year in range(current_year, int(rfv['n']), -1):
|
||||
yearList.append({'v': '[{}-01-01 00:00:00,{}-01-01 00:00:00)'.format(year, year + 1), 'n': str(year)})
|
||||
rf['value'].insert(pos, yearList)
|
||||
break
|
||||
else:
|
||||
break
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
return self.categoryContent('1', '1', False, {})
|
||||
|
||||
def categoryContent(self, cid, page, filter, ext):
|
||||
page = int(page)
|
||||
result = {}
|
||||
videos = []
|
||||
cookie, _, _ = self.getCookie('{}')
|
||||
url = 'https://api.bilibili.com/pgc/season/index/result?order=2&sort=0&pagesize=20&type=1&st={}&season_type={}&page={}'.format(cid, cid, page)
|
||||
for key in ext:
|
||||
url = url + '&{}={}' .format(key, quote(ext[key]))
|
||||
r = self.fetch(url, headers=self.header, cookies=cookie, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
vodList = data['data']['list']
|
||||
for vod in vodList:
|
||||
aid = str(vod['season_id']).strip()
|
||||
title = self.removeHtmlTags(self.cleanText(vod['title']))
|
||||
img = vod['cover'].strip()
|
||||
remark = vod['index_show'].strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
lenvideos = len(videos)
|
||||
if data['data']['has_next'] == 1:
|
||||
pagecount = page + 1
|
||||
else:
|
||||
pagecount = page
|
||||
result['list'] = videos
|
||||
result['page'] = page
|
||||
result['pagecount'] = pagecount
|
||||
result['limit'] = lenvideos
|
||||
result['total'] = lenvideos
|
||||
return result
|
||||
|
||||
def detailContent(self, did):
|
||||
did = did[0]
|
||||
url = "http://api.bilibili.com/pgc/view/web/season?season_id={0}".format(did)
|
||||
r = self.fetch(url, headers=self.header, timeout=10)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
vod = {
|
||||
"vod_id": did,
|
||||
"vod_name": self.removeHtmlTags(data['result']['title']),
|
||||
"vod_pic": data['result']['cover'],
|
||||
"type_name": data['result']['share_sub_title'],
|
||||
"vod_actor": data['result']['actors'].replace('\n', ','),
|
||||
"vod_content": self.removeHtmlTags(data['result']['evaluate'])
|
||||
}
|
||||
videoList = data['result']['episodes']
|
||||
playUrl = ''
|
||||
for video in videoList:
|
||||
eid = video['id']
|
||||
cid = video['cid']
|
||||
name = self.removeHtmlTags(video['share_copy']).replace("#", "-").replace('$', '*')
|
||||
remark = time.strftime('%H:%M:%S', time.gmtime(video['duration']/1000))
|
||||
if remark.startswith('00:'):
|
||||
remark = remark[3:]
|
||||
playUrl = playUrl + '[{}]/{}${}_{}#'.format(remark, name, eid, cid)
|
||||
vod['vod_play_from'] = 'B站番剧'
|
||||
vod['vod_play_url'] = playUrl.strip('#')
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
return self.searchContentPage(key, quick, '1')
|
||||
|
||||
def searchContentPage(self, key, quick, page):
|
||||
videos = []
|
||||
cookie = ''
|
||||
if 'cookie' in self.extendDict:
|
||||
cookie = self.extendDict['cookie']
|
||||
if 'json' in self.extendDict:
|
||||
r = self.fetch(self.extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
cookie, _, _ = self.getCookie(cookie)
|
||||
url = f'https://api.bilibili.com/x/web-interface/search/type?search_type=media_bangumi&keyword={key}&page={page}'
|
||||
r = self.fetch(url, headers=self.header, cookies=cookie, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if 'result' not in data['data']:
|
||||
return {'list': videos}, 1
|
||||
vodList = data['data']['result']
|
||||
for vod in vodList:
|
||||
sid = str(vod['season_id']).strip()
|
||||
title = self.removeHtmlTags(self.cleanText(vod['title']))
|
||||
if SequenceMatcher(None, title, key).ratio() < 0.6 and key not in title:
|
||||
continue
|
||||
img = vod['eps'][0]['cover'].strip()
|
||||
remark = self.removeHtmlTags(vod['index_show']).strip()
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, pid, vipFlags):
|
||||
result = {}
|
||||
pidList = pid.split("_")
|
||||
aid = pidList[0]
|
||||
cid = pidList[1]
|
||||
url = 'https://api.bilibili.com/pgc/player/web/playurl?ep_id={0}&cid={1}&qn=120&fnval=4048&fnver=0&fourk=1'.format(aid, cid)
|
||||
cookie = ''
|
||||
extendDict = self.extendDict
|
||||
if 'cookie' in extendDict:
|
||||
cookie = extendDict['cookie']
|
||||
if 'json' in extendDict:
|
||||
r = self.fetch(extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
cookiesDict, _, _ = self.getCookie(cookie)
|
||||
cookies = quote(json.dumps(cookiesDict))
|
||||
if 'thread' in extendDict:
|
||||
thread = str(extendDict['thread'])
|
||||
else:
|
||||
thread = '0'
|
||||
result["parse"] = '0'
|
||||
result["playUrl"] = ''
|
||||
result["url"] = f'http://127.0.0.1:UndCover/proxy?do=py&type=mpd&cookies={cookies}&url={quote(url)}&aid={aid}&cid={cid}&thread={thread}'
|
||||
result["header"] = self.header
|
||||
result['danmaku'] = 'https://api.bilibili.com/x/v1/dm/list.so?oid={}'.format(cid)
|
||||
result["format"] = 'application/dash+xml'
|
||||
return result
|
||||
|
||||
def localProxy(self, params):
|
||||
if params['type'] == "mpd":
|
||||
print('localProxympd', params)
|
||||
return self.proxyMpd(params)
|
||||
if params['type'] == "media":
|
||||
print('localProxymedia', params)
|
||||
return self.proxyMedia(params)
|
||||
return None
|
||||
|
||||
def proxyMpd(self, params):
|
||||
content, _, mediaType = self.getDash(params)
|
||||
if mediaType == 'mpd':
|
||||
action = {'url': '', 'header': self.header, 'param': '', 'type': 'string'}
|
||||
print('proxyMpd', action)
|
||||
return [200, "application/dash+xml", action, content]
|
||||
else:
|
||||
action = {'url': content, 'header': self.header, 'param': '', 'type': 'stream'}
|
||||
print('proxyMpd', action)
|
||||
return [200, "video/MP2T", action, '']
|
||||
|
||||
def proxyMedia(self, params, forceRefresh=False):
|
||||
_, dashinfos, _ = self.getDash(params)
|
||||
if 'videoid' in params:
|
||||
videoid = int(params['videoid'])
|
||||
playurl = dashinfos['video'][videoid]['baseUrl']
|
||||
elif 'audioid' in params:
|
||||
audioid = int(params['audioid'])
|
||||
playurl = dashinfos['audio'][audioid]['baseUrl']
|
||||
else:
|
||||
return [404, "text/plain", {}, ""]
|
||||
# try:
|
||||
# r = self.fetch(playurl, headers=params['headers'], stream=True)
|
||||
# statusCode = r.status_code
|
||||
# except:
|
||||
# statusCode = 404
|
||||
# try:
|
||||
# r.close()
|
||||
# except:
|
||||
# pass
|
||||
# if statusCode != 200 and self.retry == 0:
|
||||
# self.retry += 1
|
||||
# self.proxyPlayurl(params, True)
|
||||
action = {'url': playurl, 'header': self.header, 'param': '', 'type': 'stream'}
|
||||
print('proxyMedia', action)
|
||||
return [200, "video/MP2T", action, '']
|
||||
|
||||
def getDash(self, params, forceRefresh=False):
|
||||
aid = params['aid']
|
||||
cid = params['cid']
|
||||
url = unquote(params['url'])
|
||||
if 'thread' in params:
|
||||
thread = params['thread']
|
||||
else:
|
||||
thread = 0
|
||||
header = self.header.copy()
|
||||
cookieDict = json.loads(unquote(params['cookies']))
|
||||
key = 'bilimdmpdCache_{}_{}'.format(aid, cid)
|
||||
if not forceRefresh:
|
||||
data = self.getCache(key)
|
||||
print('getDash', data)
|
||||
if data:
|
||||
return data['content'], data['dashinfos'], data['type']
|
||||
|
||||
cookies = cookieDict
|
||||
r = self.fetch(url, cookies=cookies, headers=header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if data['code'] != 0:
|
||||
return '', {}, ''
|
||||
if not 'dash' in data['result']:
|
||||
purl = data['result']['durl'][0]['url']
|
||||
try:
|
||||
expiresAt = int(self.regStr(reg='deadline=(\d+)', src=purl).group(1)) - 60
|
||||
except:
|
||||
expiresAt = int(time.time()) + 600
|
||||
if int(thread) > 0:
|
||||
try:
|
||||
self.fetch('http://127.0.0.1:7777')
|
||||
except:
|
||||
self.fetch('http://127.0.0.1:9978/go')
|
||||
purl = f'http://127.0.0.1:7777?url={quote(purl)}&thread={thread}'
|
||||
self.setCache(key, {'content': purl, 'type': 'mp4', 'dashinfos': {}, 'expiresAt': expiresAt})
|
||||
return purl, {}, 'mp4'
|
||||
|
||||
dashinfos = data['result']['dash']
|
||||
duration = dashinfos['duration']
|
||||
minBufferTime = dashinfos['minBufferTime']
|
||||
videoinfo = ''
|
||||
videoid = 0
|
||||
deadlineList = []
|
||||
# videoList = sorted(dashinfos['video'], key=lambda x: x['bandwidth'], reverse=True)
|
||||
for video in dashinfos['video']:
|
||||
try:
|
||||
deadline = int(self.regStr(reg='deadline=(\d+)', src=video['baseUrl']).group(1))
|
||||
except:
|
||||
deadline = int(time.time()) + 600
|
||||
deadlineList.append(deadline)
|
||||
codecs = vid
|
||||
@@ -0,0 +1,730 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
from urllib.parse import quote, unquote
|
||||
|
||||
import requests
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "B站视频"
|
||||
|
||||
def init(self, extend):
|
||||
try:
|
||||
self.extendDict = json.loads(extend)
|
||||
except:
|
||||
self.extendDict = {}
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
result['filters'] = {}
|
||||
cookie = ''
|
||||
if 'cookie' in self.extendDict:
|
||||
cookie = self.extendDict['cookie']
|
||||
if 'json' in self.extendDict:
|
||||
r = self.fetch(self.extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
_, _, _ = self.getCookie(cookie)
|
||||
bblogin = self.getCache('bblogin')
|
||||
if bblogin:
|
||||
result['class'] = []
|
||||
else:
|
||||
result['class'] = []
|
||||
if 'json' in self.extendDict:
|
||||
r = self.fetch(self.extendDict['json'], timeout=10)
|
||||
params = r.json()
|
||||
if 'classes' in params:
|
||||
result['class'] = result['class'] + params['classes']
|
||||
if filter:
|
||||
if 'filter' in params:
|
||||
result['filters'] = params['filter']
|
||||
elif 'categories' in self.extendDict or 'type' in self.extendDict:
|
||||
if 'categories' in self.extendDict:
|
||||
cateList = self.extendDict['categories'].split('#')
|
||||
else:
|
||||
cateList = self.extendDict['type'].split('#')
|
||||
for cate in cateList:
|
||||
result['class'].append({'type_name': cate, 'type_id': cate})
|
||||
if not 'class' in result or result['class'] == []:
|
||||
result['class'] = [{"type_name": "沙雕动漫", "type_id": "沙雕动漫"}]
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
cookie = ''
|
||||
if 'cookie' in self.extendDict:
|
||||
cookie = self.extendDict['cookie']
|
||||
if 'json' in self.extendDict:
|
||||
r = self.fetch(self.extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
cookie, imgKey, subKey = self.getCookie(cookie)
|
||||
url = 'https://api.bilibili.com/x/web-interface/index/top/feed/rcmd?y_num=1&fresh_type=3&feed_version=SEO_VIDEO&fresh_idx_1h=1&fetch_row=1&fresh_idx=1&brush=0&homepage_ver=1&ps=20'
|
||||
r = requests.get(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
try:
|
||||
result['list'] = []
|
||||
vodList = data['data']['item']
|
||||
for vod in vodList:
|
||||
aid = str(vod['id']).strip()
|
||||
title = self.removeHtmlTags(vod['title']).strip()
|
||||
img = vod['pic'].strip()
|
||||
remark = time.strftime('%H:%M:%S', time.gmtime(vod['duration']))
|
||||
if remark.startswith('00:'):
|
||||
remark = remark[3:]
|
||||
if remark == '00:00':
|
||||
continue
|
||||
result['list'].append({
|
||||
'vod_id': aid,
|
||||
'vod_name': title,
|
||||
'vod_pic': img,
|
||||
'vod_remarks': remark
|
||||
})
|
||||
except:
|
||||
pass
|
||||
return result
|
||||
|
||||
def categoryContent(self, cid, page, filter, ext):
|
||||
page = int(page)
|
||||
result = {}
|
||||
videos = []
|
||||
cookie = ''
|
||||
pagecount = page
|
||||
if 'cookie' in self.extendDict:
|
||||
cookie = self.extendDict['cookie']
|
||||
if 'json' in self.extendDict:
|
||||
r = self.fetch(self.extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
cookie, imgKey, subKey = self.getCookie(cookie)
|
||||
if cid == '动态':
|
||||
if page > 1:
|
||||
offset = self.getCache('offset')
|
||||
if not offset:
|
||||
offset = ''
|
||||
url = f'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=all&offset={offset}&page={page}'
|
||||
else:
|
||||
url = f'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=all&page={page}'
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
self.setCache('offset', data['data']['offset'])
|
||||
vodList = data['data']['items']
|
||||
if data['data']['has_more']:
|
||||
pagecount = page + 1
|
||||
for vod in vodList:
|
||||
if vod['type'] != 'DYNAMIC_TYPE_AV':
|
||||
continue
|
||||
vid = str(vod['modules']['module_dynamic']['major']['archive']['aid']).strip()
|
||||
remark = vod['modules']['module_dynamic']['major']['archive']['duration_text'].strip()
|
||||
title = self.removeHtmlTags(vod['modules']['module_dynamic']['major']['archive']['title']).strip()
|
||||
img = vod['modules']['module_dynamic']['major']['archive']['cover']
|
||||
videos.append({
|
||||
"vod_id": vid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
elif cid == "收藏夹":
|
||||
userid = self.getUserid(cookie)
|
||||
if userid is None:
|
||||
return {}, 1
|
||||
url = f'http://api.bilibili.com/x/v3/fav/folder/created/list-all?up_mid={userid}&jsonp=jsonp'
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
vodList = data['data']['list']
|
||||
pagecount = page
|
||||
for vod in vodList:
|
||||
vid = vod['id']
|
||||
title = vod['title'].strip()
|
||||
remark = vod['media_count']
|
||||
img = 'https://api-lmteam.koyeb.app/files/shoucang.png'
|
||||
videos.append({
|
||||
"vod_id": f'fav&&&{vid}',
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_tag": 'folder',
|
||||
"vod_remarks": remark
|
||||
})
|
||||
elif cid.startswith('fav&&&'):
|
||||
cid = cid[6:]
|
||||
url = f'http://api.bilibili.com/x/v3/fav/resource/list?media_id={cid}&pn={page}&ps=20&platform=web&type=0'
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if data['data']['has_more']:
|
||||
pagecount = page + 1
|
||||
else:
|
||||
pagecount = page
|
||||
vodList = data['data']['medias']
|
||||
for vod in vodList:
|
||||
vid = str(vod['id']).strip()
|
||||
title = self.removeHtmlTags(vod['title']).replace(""", '"')
|
||||
img = vod['cover'].strip()
|
||||
remark = time.strftime('%H:%M:%S', time.gmtime(vod['duration']))
|
||||
if remark.startswith('00:'):
|
||||
remark = remark[3:]
|
||||
videos.append({
|
||||
"vod_id": vid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
elif cid.startswith('UP主&&&'):
|
||||
cid = cid[6:]
|
||||
params = {'mid': cid, 'ps': 30, 'pn': page}
|
||||
params = self.encWbi(params, imgKey, subKey)
|
||||
url = 'https://api.bilibili.com/x/space/wbi/arc/search?'
|
||||
for key in params:
|
||||
url += f'&{key}={quote(params[key])}'
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if page < data['data']['page']['count']:
|
||||
pagecount = page + 1
|
||||
else:
|
||||
pagecount = page
|
||||
if page == 1:
|
||||
videos = [{"vod_id": f'UP主&&&{tid}', "vod_name": '播放列表'}]
|
||||
vodList = data['data']['list']['vlist']
|
||||
for vod in vodList:
|
||||
vid = str(vod['aid']).strip()
|
||||
title = self.removeHtmlTags(vod['title']).replace(""", '"')
|
||||
img = vod['pic'].strip()
|
||||
remarkinfos = vod['length'].split(':')
|
||||
minutes = int(remarkinfos[0])
|
||||
if minutes >= 60:
|
||||
hours = str(minutes // 60)
|
||||
minutes = str(minutes % 60)
|
||||
if len(hours) == 1:
|
||||
hours = '0' + hours
|
||||
if len(minutes) == 1:
|
||||
minutes = '0' + minutes
|
||||
remark = hours + ':' + minutes + ':' + remarkinfos[1]
|
||||
else:
|
||||
remark = vod['length']
|
||||
videos.append({
|
||||
"vod_id": vid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
elif cid == '历史记录':
|
||||
url = f'http://api.bilibili.com/x/v2/history?pn={page}'
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if len(data['data']) == 300:
|
||||
pagecount = page + 1
|
||||
else:
|
||||
pagecount = page
|
||||
vodList = data['data']
|
||||
for vod in vodList:
|
||||
if vod['duration'] <= 0:
|
||||
continue
|
||||
vid = str(vod["aid"]).strip()
|
||||
img = vod["pic"].strip()
|
||||
title = self.removeHtmlTags(vod["title"]).replace(""", '"')
|
||||
if vod['progress'] != -1:
|
||||
process = time.strftime('%H:%M:%S', time.gmtime(vod['progress']))
|
||||
totalTime = time.strftime('%H:%M:%S', time.gmtime(vod['duration']))
|
||||
if process.startswith('00:'):
|
||||
process = process[3:]
|
||||
if totalTime.startswith('00:'):
|
||||
totalTime = totalTime[3:]
|
||||
remark = process + '|' + totalTime
|
||||
videos.append({
|
||||
"vod_id": vid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
else:
|
||||
url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={}&page={}'
|
||||
for key in ext:
|
||||
if key == 'tid':
|
||||
cid = ext[key]
|
||||
continue
|
||||
url += f'&{key}={ext[key]}'
|
||||
url = url.format(cid, page)
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
pagecount = data['data']['numPages']
|
||||
vodList = data['data']['result']
|
||||
for vod in vodList:
|
||||
if vod['type'] != 'video':
|
||||
continue
|
||||
vid = str(vod['aid']).strip()
|
||||
title = self.removeHtmlTags(self.cleanText(vod['title']))
|
||||
img = 'https:' + vod['pic'].strip()
|
||||
remarkinfo = vod['duration'].split(':')
|
||||
minutes = int(remarkinfo[0])
|
||||
seconds = remarkinfo[1]
|
||||
if len(seconds) == 1:
|
||||
seconds = '0' + seconds
|
||||
if minutes >= 60:
|
||||
hour = str(minutes // 60)
|
||||
minutes = str(minutes % 60)
|
||||
if len(hour) == 1:
|
||||
hour = '0' + hour
|
||||
if len(minutes) == 1:
|
||||
minutes = '0' + minutes
|
||||
remark = f'{hour}:{minutes}:{seconds}'
|
||||
else:
|
||||
minutes = str(minutes)
|
||||
if len(minutes) == 1:
|
||||
minutes = '0' + minutes
|
||||
remark = f'{minutes}:{seconds}'
|
||||
videos.append({
|
||||
"vod_id": vid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
lenvideos = len(videos)
|
||||
result['list'] = videos
|
||||
result['page'] = page
|
||||
result['pagecount'] = pagecount
|
||||
result['limit'] = lenvideos
|
||||
result['total'] = lenvideos
|
||||
return result
|
||||
|
||||
def detailContent(self, did):
|
||||
aid = did[0]
|
||||
if aid.startswith('UP主&&&'):
|
||||
bizId = aid[6:]
|
||||
oid = ''
|
||||
url = f'https://api.bilibili.com/x/v2/medialist/resource/list?mobi_app=web&type=1&oid={oid}&biz_id={bizId}&otype=1&ps=100&direction=false&desc=true&sort_field=1&tid=0&with_current=false'
|
||||
r = self.fetch(url, headers=self.header, timeout=5)
|
||||
videoList = r.json()['data']['media_list']
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": '播放列表',
|
||||
'vod_play_from': 'B站视频'
|
||||
}
|
||||
playUrl = ''
|
||||
for video in videoList:
|
||||
remark = time.strftime('%H:%M:%S', time.gmtime(video['duration']))
|
||||
name = self.removeHtmlTags(video['title']).strip().replace("#", "-").replace('$', '*')
|
||||
if remark.startswith('00:'):
|
||||
remark = remark[3:]
|
||||
playUrl += f"[{remark}]/{name}$bvid&&&{video['bv_id']}#"
|
||||
vod['vod_play_url'] = playUrl.strip('#')
|
||||
result = {'list': [vod]}
|
||||
return result
|
||||
url = f"https://api.bilibili.com/x/web-interface/view?aid={aid}"
|
||||
r = self.fetch(url, headers=self.header, timeout=10)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if "staff" in data['data']:
|
||||
director = ''
|
||||
for staff in data['data']['staff']:
|
||||
director += '[a=cr:{{"id":"UP主&&&{}","name":"{}"}}/]{}[/a],'.format(staff['mid'], staff['name'], staff['name'])
|
||||
else:
|
||||
director = '[a=cr:{{"id":"UP主&&&{}","name":"{}"}}/]{}[/a]'.format(data['data']['owner']['mid'], data['data']['owner']['name'], data['data']['owner']['name'])
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": self.removeHtmlTags(data['data']['title']),
|
||||
"vod_pic": data['data']['pic'],
|
||||
"type_name": data['data']['tname'],
|
||||
"vod_year": datetime.fromtimestamp(data['data']['pubdate']).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"vod_content": data['data']['desc'].replace('\xa0', ' ').replace('\n\n', '\n').strip(),
|
||||
"vod_director": director
|
||||
}
|
||||
videoList = data['data']['pages']
|
||||
playUrl = ''
|
||||
for video in videoList:
|
||||
remark = time.strftime('%H:%M:%S', time.gmtime(video['duration']))
|
||||
name = self.removeHtmlTags(video['part']).strip().replace("#", "-").replace('$', '*')
|
||||
if remark.startswith('00:'):
|
||||
remark = remark[3:]
|
||||
playUrl = playUrl + f"[{remark}]/{name}${aid}_{video['cid']}#"
|
||||
url = f'https://api.bilibili.com/x/web-interface/archive/related?aid={aid}'
|
||||
r = self.fetch(url, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
videoList = data['data']
|
||||
playUrl = playUrl.strip('#') + '$$$'
|
||||
for video in videoList:
|
||||
remark = time.strftime('%H:%M:%S', time.gmtime(video['duration']))
|
||||
if remark.startswith('00:'):
|
||||
remark = remark[3:]
|
||||
name = self.removeHtmlTags(video['title']).strip().replace("#", "-").replace('$', '*')
|
||||
playUrl = playUrl + '[{}]/{}${}_{}#'.format(remark, name, video['aid'], video['cid'])
|
||||
vod['vod_play_from'] = 'B站视频$$$相关视频'
|
||||
vod['vod_play_url'] = playUrl.strip('#')
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
return self.searchContentPage(key, quick, '1')
|
||||
|
||||
def searchContentPage(self, key, quick, page):
|
||||
videos = []
|
||||
if quick:
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
cookie = ''
|
||||
if 'cookie' in self.extendDict:
|
||||
cookie = self.extendDict['cookie']
|
||||
if 'json' in self.extendDict:
|
||||
r = self.fetch(self.extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
cookie, _, _ = self.getCookie(cookie)
|
||||
url = f'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={key}&page={page}'
|
||||
r = self.fetch(url, headers=self.header, cookies=cookie, timeout=5)
|
||||
jo = json.loads(self.cleanText(r.text))
|
||||
if 'result' not in jo['data']:
|
||||
return {'list': videos}, 1
|
||||
vodList = jo['data']['result']
|
||||
for vod in vodList:
|
||||
aid = str(vod['aid']).strip()
|
||||
title = self.removeHtmlTags(self.cleanText(vod['title']))
|
||||
img = 'https:' + vod['pic'].strip()
|
||||
try:
|
||||
remarkinfo = vod['duration'].split(':')
|
||||
minutes = int(remarkinfo[0])
|
||||
seconds = remarkinfo[1]
|
||||
except:
|
||||
continue
|
||||
if len(seconds) == 1:
|
||||
seconds = '0' + seconds
|
||||
if minutes >= 60:
|
||||
hour = str(minutes // 60)
|
||||
minutes = str(minutes % 60)
|
||||
if len(hour) == 1:
|
||||
hour = '0' + hour
|
||||
if len(minutes) == 1:
|
||||
minutes = '0' + minutes
|
||||
remark = f'{hour}:{minutes}:{seconds}'
|
||||
else:
|
||||
minutes = str(minutes)
|
||||
if len(minutes) == 1:
|
||||
minutes = '0' + minutes
|
||||
remark = f'{minutes}:{seconds}'
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, pid, vipFlags):
|
||||
result = {}
|
||||
if pid.startswith('bvid&&&'):
|
||||
url = "https://api.bilibili.com/x/web-interface/view?bvid={}".format(pid[7:])
|
||||
r = self.fetch(url, headers=self.header, timeout=10)
|
||||
data = r.json()['data']
|
||||
aid = data['aid']
|
||||
cid = data['cid']
|
||||
else:
|
||||
idList = pid.split("_")
|
||||
aid = idList[0]
|
||||
cid = idList[1]
|
||||
url = 'https://api.bilibili.com/x/player/playurl?avid={}&cid={}&qn=120&fnval=4048&fnver=0&fourk=1'.format(aid, cid)
|
||||
cookie = ''
|
||||
extendDict = self.extendDict
|
||||
if 'cookie' in extendDict:
|
||||
cookie = extendDict['cookie']
|
||||
if 'json' in extendDict:
|
||||
r = self.fetch(extendDict['json'], timeout=10)
|
||||
if 'cookie' in r.json():
|
||||
cookie = r.json()['cookie']
|
||||
if cookie == '':
|
||||
cookie = '{}'
|
||||
elif type(cookie) == str and cookie.startswith('http'):
|
||||
cookie = self.fetch(cookie, timeout=10).text.strip()
|
||||
try:
|
||||
if type(cookie) == dict:
|
||||
cookie = json.dumps(cookie, ensure_ascii=False)
|
||||
except:
|
||||
pass
|
||||
cookiesDict, _, _ = self.getCookie(cookie)
|
||||
cookies = quote(json.dumps(cookiesDict))
|
||||
if 'thread' in extendDict:
|
||||
thread = str(extendDict['thread'])
|
||||
else:
|
||||
thread = '0'
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = f'http://127.0.0.1:9978/proxy?do=py&type=mpd&cookies={cookies}&url={quote(url)}&aid={aid}&cid={cid}&thread={thread}'
|
||||
result["header"] = self.header
|
||||
result['danmaku'] = 'https://api.bilibili.com/x/v1/dm/list.so?oid={}'.format(cid)
|
||||
result["format"] = 'application/dash+xml'
|
||||
return result
|
||||
|
||||
def localProxy(self, params):
|
||||
if params['type'] == "mpd":
|
||||
return self.proxyMpd(params)
|
||||
if params['type'] == "media":
|
||||
return self.proxyMedia(params)
|
||||
return None
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def proxyMpd(self, params):
|
||||
content, durlinfos, mediaType = self.getDash(params)
|
||||
if mediaType == 'mpd':
|
||||
return [200, "application/dash+xml", content]
|
||||
else:
|
||||
url = ''
|
||||
urlList = [content] + durlinfos['durl'][0]['backup_url'] if 'backup_url' in durlinfos['durl'][0] and durlinfos['durl'][0]['backup_url'] else [content]
|
||||
for url in urlList:
|
||||
if 'mcdn.bilivideo.cn' not in url:
|
||||
break
|
||||
header = self.header.copy()
|
||||
if 'range' in params:
|
||||
header['Range'] = params['range']
|
||||
if '127.0.0.1:7777' in url:
|
||||
header["Location"] = url
|
||||
return [302, "video/MP2T", None, header]
|
||||
r = requests.get(url, headers=header, stream=True)
|
||||
return [206, "application/octet-stream", r.content]
|
||||
|
||||
def proxyMedia(self, params, forceRefresh=False):
|
||||
_, dashinfos, _ = self.getDash(params)
|
||||
if 'videoid' in params:
|
||||
videoid = int(params['videoid'])
|
||||
dashinfo = dashinfos['video'][videoid]
|
||||
elif 'audioid' in params:
|
||||
audioid = int(params['audioid'])
|
||||
dashinfo = dashinfos['audio'][audioid]
|
||||
else:
|
||||
return [404, "text/plain", ""]
|
||||
url = ''
|
||||
urlList = [dashinfo['baseUrl']] + dashinfo['backupUrl'] if 'backupUrl' in dashinfo and dashinfo['backupUrl'] else [dashinfo['baseUrl']]
|
||||
for url in urlList:
|
||||
if 'mcdn.bilivideo.cn' not in url:
|
||||
break
|
||||
if url == "":
|
||||
return [404, "text/plain", ""]
|
||||
header = self.header.copy()
|
||||
if 'range' in params:
|
||||
header['Range'] = params['range']
|
||||
r = requests.get(url, headers=header, stream=True)
|
||||
return [206, "application/octet-stream", r.content]
|
||||
|
||||
def getDash(self, params, forceRefresh=False):
|
||||
aid = params['aid']
|
||||
cid = params['cid']
|
||||
url = unquote(params['url'])
|
||||
if 'thread' in params:
|
||||
thread = params['thread']
|
||||
else:
|
||||
thread = 0
|
||||
header = self.header.copy()
|
||||
cookieDict = json.loads(params['cookies'])
|
||||
key = f'bilivdmpdcache_{aid}_{cid}'
|
||||
if forceRefresh:
|
||||
self.delCache(key)
|
||||
else:
|
||||
data = self.getCache(key)
|
||||
if data:
|
||||
return data['content'], data['dashinfos'], data['type']
|
||||
|
||||
cookies = cookieDict.copy()
|
||||
r = self.fetch(url, cookies=cookies, headers=header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if data['code'] != 0:
|
||||
return '', {}, ''
|
||||
if not 'dash' in data['data']:
|
||||
purl = data['data']['durl'][0]['url']
|
||||
try:
|
||||
expiresAt = int(re.search(r'deadline=(\d+)', purl).group(1)) - 60
|
||||
except:
|
||||
expiresAt = int(time.time()) + 600
|
||||
if int(thread) > 0:
|
||||
try:
|
||||
self.fetch('http://127.0.0.1:7777')
|
||||
except:
|
||||
self.fetch('http://127.0.0.1:9978/go')
|
||||
purl = f'http://127.0.0.1:7777?url={quote(purl)}&thread={thread}'
|
||||
self.setCache(key, {'content': purl, 'type': 'mp4', 'dashinfos': data['data'], 'expiresAt': expiresAt})
|
||||
return purl, data['data'], 'mp4'
|
||||
|
||||
dashinfos = data['data']['dash']
|
||||
duration = dashinfos['duration']
|
||||
minBufferTime = dashinfos['minBufferTime']
|
||||
videoinfo = ''
|
||||
videoid = 0
|
||||
deadlineList = []
|
||||
for video in dashinfos['video']:
|
||||
try:
|
||||
deadline = int(re.search(r'deadline=(\d+)', video['baseUrl']).group(1))
|
||||
except:
|
||||
deadline = int(time.time()) + 600
|
||||
deadlineList.append(deadline)
|
||||
codecs = video['codecs']
|
||||
bandwidth = video['bandwidth']
|
||||
frameRate = video['frameRate']
|
||||
height = video['height']
|
||||
width = video['width']
|
||||
void = video['id']
|
||||
vidparams = params.copy()
|
||||
vidparams['videoid'] = videoid
|
||||
baseUrl = f'http://127.0.0.1:9978/proxy?do=py&type=media&cookies={quote(json.dumps(cookies))}&url={quote(url)}&aid={aid}&cid={cid}&videoid={videoid}'
|
||||
videoinfo = videoinfo + f""" <Representation bandwidth="{bandwidth}" codecs="{codecs}" frameRate="{frameRate}" height="{height}" id="{void}" width="{width}">
|
||||
<BaseURL>{baseUrl}</BaseURL>
|
||||
<SegmentBase indexRange="{video['SegmentBase']['indexRange']}">
|
||||
<Initialization range="{video['SegmentBase']['Initialization']}"/>
|
||||
</SegmentBase>
|
||||
</Representation>\n"""
|
||||
videoid += 1
|
||||
audioinfo = ''
|
||||
audioid = 0
|
||||
# audioList = sorted(dashinfos['audio'], key=lambda x: x['bandwidth'], reverse=True)
|
||||
for audio in dashinfos['audio']:
|
||||
try:
|
||||
deadline = int(re.search(r'deadline=(\d+)', audio['baseUrl']).group(1))
|
||||
except:
|
||||
deadline = int(time.time()) + 600
|
||||
deadlineList.append(deadline)
|
||||
bandwidth = audio['bandwidth']
|
||||
codecs = audio['codecs']
|
||||
aoid = audio['id']
|
||||
aidparams = params.copy()
|
||||
aidparams['audioid'] = audioid
|
||||
baseUrl = f'http://127.0.0.1:9978/proxy?do=py&type=media&cookies={quote(json.dumps(cookies))}&url={quote(url)}&aid={aid}&cid={cid}&audioid={audioid}'
|
||||
audioinfo = audioinfo + f""" <Representation audioSamplingRate="44100" bandwidth="{bandwidth}" codecs="{codecs}" id="{aoid}">
|
||||
<BaseURL>{baseUrl}</BaseURL>
|
||||
<SegmentBase indexRange="{audio['SegmentBase']['indexRange']}">
|
||||
<Initialization range="{audio['SegmentBase']['Initialization']}"/>
|
||||
</SegmentBase>
|
||||
</Representation>\n"""
|
||||
audioid += 1
|
||||
mpd = f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" mediaPresentationDuration="PT{duration}S" minBufferTime="PT{minBufferTime}S">
|
||||
<Period>
|
||||
<AdaptationSet mimeType="video/mp4" startWithSAP="1" scanType="progressive" segmentAlignment="true">
|
||||
{videoinfo.strip()}
|
||||
</AdaptationSet>
|
||||
<AdaptationSet mimeType="audio/mp4" startWithSAP="1" segmentAlignment="true" lang="und">
|
||||
{audioinfo.strip()}
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>"""
|
||||
expiresAt = min(deadlineList) - 60
|
||||
self.setCache(key, {'type': 'mpd', 'content': mpd.replace('&', '&'), 'dashinfos': dashinfos, 'expiresAt': expiresAt})
|
||||
return mpd.replace('&', '&'), dashinfos, 'mpd'
|
||||
|
||||
def getCookie(self, cookie):
|
||||
if '{' in cookie and '}' in cookie:
|
||||
cookies = json.loads(cookie)
|
||||
else:
|
||||
cookies = dict([co.strip().split('=', 1) for co in cookie.strip(';').split(';')])
|
||||
bblogin = self.getCache('bblogin')
|
||||
if bblogin:
|
||||
imgKey = bblogin['imgKey']
|
||||
subKey = bblogin['subKey']
|
||||
return cookies, imgKey, subKey
|
||||
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36"
|
||||
}
|
||||
r = requests.get("http://api.bilibili.com/x/web-interface/nav", cookies=cookies, headers=header, timeout=10)
|
||||
data = json.loads(r.text)
|
||||
code = data["code"]
|
||||
if code == 0:
|
||||
imgKey = data['data']['wbi_img']['img_url'].rsplit('/', 1)[1].split('.')[0]
|
||||
subKey = data['data']['wbi_img']['sub_url'].rsplit('/', 1)[1].split('.')[0]
|
||||
self.setCache('bblogin', {'imgKey': imgKey, 'subKey': subKey, 'expiresAt': int(time.time()) + 1200})
|
||||
return cookies, imgKey, subKey
|
||||
r = self.fetch("https://www.bilibili.com/", headers=header, timeout=5)
|
||||
cookies = r.cookies.get_dict()
|
||||
imgKey = ''
|
||||
subKey = ''
|
||||
return cookies, imgKey, subKey
|
||||
|
||||
def getUserid(self, cookie):
|
||||
# 获取自己的userid(cookies拥有者)
|
||||
url = 'http://api.bilibili.com/x/space/myinfo'
|
||||
r = self.fetch(url, cookies=cookie, headers=self.header, timeout=5)
|
||||
data = json.loads(self.cleanText(r.text))
|
||||
if data['code'] == 0:
|
||||
return data['data']['mid']
|
||||
|
||||
def removeHtmlTags(self, src):
|
||||
from re import sub, compile
|
||||
clean = compile('<.*?>')
|
||||
return sub(clean, '', src)
|
||||
|
||||
def encWbi(self, params, imgKey, subKey):
|
||||
from hashlib import md5
|
||||
from functools import reduce
|
||||
from urllib.parse import urlencode
|
||||
mixinKeyEncTab = [46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52]
|
||||
orig = imgKey + subKey
|
||||
mixinKey = reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32]
|
||||
params['wts'] = round(time.time()) # 添加 wts 字段
|
||||
params = dict(sorted(params.items())) # 按照 key 重排参数
|
||||
# 过滤 value 中的 "!'()*" 字符
|
||||
params = {
|
||||
k: ''.join(filter(lambda chr: chr not in "!'()*", str(v)))
|
||||
for k, v
|
||||
in params.items()
|
||||
}
|
||||
query = urlencode(params) # 序列化参数
|
||||
params['w_rid'] = md5((query + mixinKey).encode()).hexdigest() # 计算 w_rid
|
||||
return params
|
||||
|
||||
retry = 0
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36",
|
||||
"Referer": "https://www.bilibili.com"
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
from requests import session, utils
|
||||
import os
|
||||
import time
|
||||
import base64
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "B站影视"
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"番剧": "1",
|
||||
"国创": "4",
|
||||
"电影": "2",
|
||||
"综艺": "7",
|
||||
"电视剧": "5",
|
||||
"纪录片": "3"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name':k,
|
||||
'type_id':cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
tid = self.homeContent(False)['class'][0]['type_id']
|
||||
return self.categoryContent(tid, 1, False, {})
|
||||
|
||||
cookies = ''
|
||||
def getCookie(self):
|
||||
try:
|
||||
cookies_str = self.fetch("buvid3=12A78977-8E04-8DA0-EACA-4280A2CBF70F26536infoc; buvid4=AC82CF17-BB02-2BA5-AEB2-880F381C8E3A15597-022020401-bEJsC6owQKOC964b3kF8aA%3D%3D; CURRENT_BLACKGAP=0; i-wanna-go-back=-1; is-2022-channel=1; b_nut=100; _uuid=C3D57961-F8CA-8BB3-EA87-1B545E435B81013328infoc; header_theme_version=CLOSE; nostalgia_conf=-1; rpdid=|(Y|)|Yukuu0J'uY~~|~|RmY; DedeUserID=3493112737433767; DedeUserID__ckMd5=b48704cc9d5767a2; CURRENT_QUALITY=80; b_ut=5; home_feed_column=5; CURRENT_FNVAL=4048; fingerprint=6072d6d047af63027d42e7b07fdc0e14; buvid_fp_plain=undefined; buvid_fp=6072d6d047af63027d42e7b07fdc0e14; bp_video_offset_3493112737433767=829654181129224199; PVID=1; innersign=0; b_lsid=7197A2E1_18A6572474D; bsource=search_baidu; SESSDATA=a3b66263%2C1709471105%2C827d3%2A92J3ek47bxV2D3NICqYMcLiGLc8j5GPYyNJ5Kany321n1pWi76HJvQF51AUZv0Xpjf5K2lxwAAQwA; bili_jct=8fefab3e2a608c421e3d5fa72de5a823; sid=77j01eei; browser_resolution=1920-398").text
|
||||
cookies_dic = dict([co.strip().split('=') for co in cookies_str.split(';')])
|
||||
rsp = session()
|
||||
cookies_jar = utils.cookiejar_from_dict(cookies_dic)
|
||||
rsp.cookies = cookies_jar
|
||||
content = self.fetch("http://api.bilibili.com/x/web-interface/nav", cookies=rsp.cookies)
|
||||
res = json.loads(content.text)
|
||||
except:
|
||||
res = {}
|
||||
res["code"] = 404
|
||||
if res["code"] == 0:
|
||||
self.cookies = rsp.cookies
|
||||
else:
|
||||
rsp = self.fetch("https://www.bilibili.com/")
|
||||
self.cookies = rsp.cookies
|
||||
return rsp.cookies
|
||||
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
url = 'https://api.bilibili.com/pgc/season/index/result?order=2&season_status=-1&style_id=-1&sort=0&area=-1&pagesize=20&type=1&st={0}&season_type={0}&page={1}'.format(tid,pg)
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
rsp = self.fetch(url, cookies=self.cookies)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']['list']
|
||||
for vod in vodList:
|
||||
aid = str(vod['season_id']).strip()
|
||||
title = vod['title'].strip()
|
||||
img = vod['cover'].strip()
|
||||
remark = vod['index_show'].strip()
|
||||
videos.append({
|
||||
"vod_id":aid,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def cleanSpace(self,str):
|
||||
return str.replace('\n','').replace('\t','').replace('\r','').replace(' ','')
|
||||
|
||||
def detailContent(self,array):
|
||||
aid = array[0]
|
||||
url = "http://api.bilibili.com/pgc/view/web/season?season_id={0}".format(aid)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
jRoot = json.loads(rsp.text)
|
||||
jo = jRoot['result']
|
||||
id = jo['season_id']
|
||||
title = jo['title']
|
||||
pic = jo['cover']
|
||||
areas = jo['areas'][0]['name']
|
||||
typeName = jo['share_sub_title']
|
||||
dec = jo['evaluate']
|
||||
remark = jo['new_ep']['desc']
|
||||
vod = {
|
||||
"vod_id":id,
|
||||
"vod_name":title,
|
||||
"vod_pic":pic,
|
||||
"type_name":typeName,
|
||||
"vod_year":"",
|
||||
"vod_area":areas,
|
||||
"vod_remarks":remark,
|
||||
"vod_actor":"",
|
||||
"vod_director":"",
|
||||
"vod_content":dec
|
||||
}
|
||||
ja = jo['episodes']
|
||||
playUrl = ''
|
||||
for tmpJo in ja:
|
||||
eid = tmpJo['id']
|
||||
cid = tmpJo['cid']
|
||||
part = tmpJo['title'].replace("#", "-")
|
||||
playUrl = playUrl + '{0}${1}_{2}#'.format(part, eid, cid)
|
||||
|
||||
vod['vod_play_from'] = 'B站影视'
|
||||
vod['vod_play_url'] = playUrl
|
||||
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def searchContent(self,key,quick):
|
||||
url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=media_bangumi&keyword={0}'.format(key) # 番剧搜索
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
rsp = self.fetch(url, cookies=self.cookies)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
rs = jo['data']
|
||||
if rs['numResults'] == 0:
|
||||
url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=media_ft&keyword={0}'.format(key) # 影视搜索
|
||||
rspRetry = self.fetch(url, cookies=self.cookies)
|
||||
content = rspRetry.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']['result']
|
||||
for vod in vodList:
|
||||
aid = str(vod['season_id']).strip()
|
||||
title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = vod['eps'][0]['cover'].strip()
|
||||
remark = vod['index_show']
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
ids = id.split("_")
|
||||
header = {
|
||||
"Referer": "https://www.bilibili.com",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
url = 'https://api.bilibili.com/pgc/player/web/playurl?qn=116&ep_id={0}&cid={1}'.format(ids[0],ids[1])
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
rsp = self.fetch(url,cookies=self.cookies,headers=header)
|
||||
jRoot = json.loads(rsp.text)
|
||||
if jRoot['message'] != 'success':
|
||||
url = ''
|
||||
else:
|
||||
jo = jRoot['result']
|
||||
ja = jo['durl']
|
||||
maxSize = -1
|
||||
position = -1
|
||||
for i in range(len(ja)):
|
||||
tmpJo = ja[i]
|
||||
if maxSize < int(tmpJo['size']):
|
||||
maxSize = int(tmpJo['size'])
|
||||
position = i
|
||||
url = ''
|
||||
if len(ja) > 0:
|
||||
if position == -1:
|
||||
position = 0
|
||||
url = ja[position]['url']
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = url
|
||||
result["header"] = {
|
||||
"Referer":"https://www.bilibili.com",
|
||||
"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
result["contentType"] = 'video/x-flv'
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,530 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
from requests import session, utils
|
||||
import time
|
||||
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "哔哩"
|
||||
|
||||
def init(self, extend=""):
|
||||
# 初始化,获取收藏夹分区,获取userid
|
||||
self.userid = self.get_userid()
|
||||
url = 'http://api.bilibili.com/x/v3/fav/folder/created/list-all?up_mid=%s&jsonp=jsonp' % (self.userid)
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
fav_list = []
|
||||
if jo['code'] == 0:
|
||||
for fav in jo['data'].get('list'):
|
||||
fav_dict = {'n': fav['title'], 'v': fav['id']}
|
||||
fav_list.append(fav_dict)
|
||||
if self.config["filter"].get('收藏夹'):
|
||||
for i in self.config["filter"].get('收藏夹'):
|
||||
if i['key'] == 'mlid':
|
||||
i['value'] = fav_list
|
||||
#用户userid
|
||||
userid=''
|
||||
def get_userid(self):
|
||||
#获取自己的userid(cookies拥有者)
|
||||
url = 'http://api.bilibili.com/x/space/myinfo'
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
return jo['data']['mid']
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
cateManual = {
|
||||
"频道": "频道",
|
||||
"热门": "热门",
|
||||
"推荐": "推荐",
|
||||
"排行榜": "排行榜",
|
||||
"健身": "刘畊宏 9月21日",
|
||||
"演唱会": "演唱会",
|
||||
"动物世界": "动物世界",
|
||||
"相声小品": "相声小品",
|
||||
"假窗-白噪音": "窗+白噪音"
|
||||
}
|
||||
if self.login:
|
||||
cateManual.update({"动态": "动态"})
|
||||
cateManual.update({"收藏夹": "收藏夹"})
|
||||
cateManual.update({"历史记录": "历史记录"})
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if (filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
tid = self.homeContent(False)['class'][0]['type_id']
|
||||
return self.categoryContent(tid, 1, False, {})
|
||||
|
||||
def get_rcmd(self,pg):
|
||||
result = {}
|
||||
url= 'https://api.bilibili.com/x/web-interface/index/top/feed/rcmd?y_num={0}&fresh_type=3&feed_version=SEO_VIDEO&fresh_idx_1h=1&fetch_row=1&fresh_idx=1&brush=0&homepage_ver=1&ps=20'.format(pg)
|
||||
rsp = self.fetch(url,cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data']['item']
|
||||
for vod in vodList:
|
||||
aid = str(vod['id']).strip()
|
||||
title = vod['title'].strip().replace("<em class=\"keyword\">","").replace("</em>","")
|
||||
img = vod['pic'].strip()
|
||||
remark = str(vod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id":aid,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_dynamic(self,pg):
|
||||
result = {}
|
||||
if int(pg) > 1:
|
||||
return result
|
||||
offset = ''
|
||||
videos = []
|
||||
for i in range(0,10):
|
||||
url= 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=all&page={0}&offset={1}'.format(pg,offset)
|
||||
rsp = self.fetch(url,cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
offset = jo['data']['offset']
|
||||
vodList = jo['data']['items']
|
||||
for vod in vodList:
|
||||
if vod['type'] == 'DYNAMIC_TYPE_AV':
|
||||
ivod = vod['modules']['module_dynamic']['major']['archive']
|
||||
aid = str(ivod['aid']).strip()
|
||||
title = ivod['title'].strip().replace("<em class=\"keyword\">","").replace("</em>","")
|
||||
img = ivod['cover'].strip()
|
||||
remark = str(ivod['duration_text']).strip()
|
||||
videos.append({
|
||||
"vod_id":aid,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def second_to_time(self, a):
|
||||
# 将秒数转化为 时分秒的格式
|
||||
if a < 3600:
|
||||
return time.strftime("%M:%S", time.gmtime(a))
|
||||
else:
|
||||
return time.strftime("%H:%M:%S", time.gmtime(a))
|
||||
|
||||
def get_history(self, pg):
|
||||
result = {}
|
||||
url = 'http://api.bilibili.com/x/v2/history?pn=%s' % pg
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content) # 解析api接口,转化成json数据对象
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data']
|
||||
for vod in vodList:
|
||||
if vod['duration'] > 0: # 筛选掉非视频的历史记录
|
||||
aid = str(vod["aid"]).strip() # 获取 aid
|
||||
# 获取标题
|
||||
title = vod["title"].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""",'"')
|
||||
# 封面图片
|
||||
img = vod["pic"].strip()
|
||||
# 获取已观看时间
|
||||
if str(vod['progress']) == '-1':
|
||||
process = str(self.second_to_time(vod['duration'])).strip()
|
||||
else:
|
||||
process = str(self.second_to_time(vod['progress'])).strip()
|
||||
# 获取视频总时长
|
||||
total_time = str(self.second_to_time(vod['duration'])).strip()
|
||||
# 组合 已观看时间 / 总时长 ,赋值给 remark
|
||||
remark = process + ' / ' + total_time
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_hot(self, pg):
|
||||
result = {}
|
||||
url = 'https://api.bilibili.com/x/web-interface/popular?ps=20&pn={0}'.format(pg)
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data']['list']
|
||||
for vod in vodList:
|
||||
aid = str(vod['aid']).strip()
|
||||
title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = vod['pic'].strip()
|
||||
remark = str(vod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_rank(self):
|
||||
result = {}
|
||||
url = 'https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all'
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
videos = []
|
||||
vodList = jo['data']['list']
|
||||
for vod in vodList:
|
||||
aid = str(vod['aid']).strip()
|
||||
title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = vod['pic'].strip()
|
||||
remark = str(vod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = 1
|
||||
result['pagecount'] = 1
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_channel(self, pg, cid):
|
||||
result = {}
|
||||
if int(pg) > 1:
|
||||
return result
|
||||
offset = ''
|
||||
videos = []
|
||||
for i in range(0, 5):
|
||||
url = 'https://api.bilibili.com/x/web-interface/web/channel/multiple/list?channel_id={0}&sort_type=hot&offset={1}&page_size=30'.format(cid, offset)
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
print(content)
|
||||
jo = json.loads(content)
|
||||
if jo['code'] == 0:
|
||||
offset = jo['data']['offset']
|
||||
vodList = jo['data']['list']
|
||||
for vod in vodList:
|
||||
if vod['card_type'] == 'rank':
|
||||
rankVods = vod['items']
|
||||
for ivod in rankVods:
|
||||
aid = str(ivod['id']).strip()
|
||||
title = ivod['name'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = ivod['cover'].strip()
|
||||
remark = str(ivod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
elif vod['card_type'] == 'archive':
|
||||
aid = str(vod['id']).strip()
|
||||
title = vod['name'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
img = vod['cover'].strip()
|
||||
remark = str(vod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_fav_detail(self, pg, mlid, order):
|
||||
result = {}
|
||||
url = 'http://api.bilibili.com/x/v3/fav/resource/list?media_id=%s&order=%s&pn=%s&ps=20&platform=web&type=0' % (
|
||||
mlid, order, pg)
|
||||
rsp = self.fetch(url, cookies=self.getCookie())
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']['medias']
|
||||
for vod in vodList:
|
||||
aid = str(vod['id']).strip()
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = vod['cover'].strip()
|
||||
remark = str(self.second_to_time(vod['duration'])).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
|
||||
})
|
||||
# videos=self.filter_duration(videos, duration_diff)
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def get_fav(self, pg, order, extend):
|
||||
# 获取自己的up_mid(也就是用户uid)
|
||||
mlid = ''
|
||||
fav_config = self.config["filter"].get('收藏夹')
|
||||
# 默认显示第一个收藏夹内容
|
||||
if fav_config:
|
||||
for i in fav_config:
|
||||
if i['key'] == 'mlid':
|
||||
if len(i['value']) > 0:
|
||||
mlid = i['value'][0]['v']
|
||||
if 'mlid' in extend:
|
||||
mlid = extend['mlid']
|
||||
if mlid:
|
||||
return self.get_fav_detail(pg=pg, mlid=mlid, order=order)
|
||||
else:
|
||||
return {}
|
||||
|
||||
cookies = ''
|
||||
login = False
|
||||
def getCookie(self):
|
||||
try:
|
||||
cookies_str = self.fetch("cook所在链接").text
|
||||
cookies_dic = dict([co.strip().split('=') for co in cookies_str.split(';')])
|
||||
rsp = session()
|
||||
cookies_jar = utils.cookiejar_from_dict(cookies_dic)
|
||||
rsp.cookies = cookies_jar
|
||||
content = self.fetch("http://api.bilibili.com/x/web-interface/nav", cookies=rsp.cookies)
|
||||
res = json.loads(content.text)
|
||||
except:
|
||||
res = {}
|
||||
res["code"] = 404
|
||||
if res["code"] == 0:
|
||||
self.login = True
|
||||
self.cookies = rsp.cookies
|
||||
else:
|
||||
rsp = self.fetch("https://www.bilibili.com/")
|
||||
self.cookies = rsp.cookies
|
||||
self.login = False
|
||||
return rsp.cookies
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
result = {}
|
||||
if tid == "热门":
|
||||
return self.get_hot(pg=pg)
|
||||
if tid == "排行榜":
|
||||
return self.get_rank()
|
||||
if tid == '动态':
|
||||
return self.get_dynamic(pg=pg)
|
||||
if tid == '历史记录':
|
||||
return self.get_history(pg=pg)
|
||||
if tid == '推荐':
|
||||
return self.get_rcmd(pg=pg)
|
||||
if tid == "收藏夹":
|
||||
self.box_video_type = '收藏夹'
|
||||
order = 'mtime'
|
||||
if 'order' in extend:
|
||||
order = extend['order']
|
||||
return self.get_fav(pg=pg, order=order, extend=extend)
|
||||
if tid == '频道':
|
||||
cid = '9222'
|
||||
if 'cid' in extend:
|
||||
cid = extend['cid']
|
||||
return self.get_channel(pg=pg, cid=cid)
|
||||
url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={0}&page={1}'.format(tid, pg)
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
rsp = self.fetch(url, cookies=self.cookies)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']['result']
|
||||
for vod in vodList:
|
||||
aid = str(vod['aid']).strip()
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = 'https:' + vod['pic'].strip()
|
||||
remark = str(vod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def cleanSpace(self, str):
|
||||
return str.replace('\n', '').replace('\t', '').replace('\r', '').replace(' ', '')
|
||||
|
||||
def detailContent(self, array):
|
||||
aid = array[0]
|
||||
url = "https://api.bilibili.com/x/web-interface/view?aid={0}".format(aid)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
jRoot = json.loads(rsp.text)
|
||||
jo = jRoot['data']
|
||||
title = jo['title'].replace("<em class=\"keyword\">", "").replace("</em>", "")
|
||||
pic = jo['pic']
|
||||
desc = jo['desc']
|
||||
timeStamp = jo['pubdate']
|
||||
timeArray = time.localtime(timeStamp)
|
||||
year = str(time.strftime("%Y", timeArray))
|
||||
dire = jo['owner']['name']
|
||||
typeName = jo['tname']
|
||||
remark = str(jo['duration']).strip()
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": typeName,
|
||||
"vod_year": year,
|
||||
"vod_area": "",
|
||||
"vod_remarks": remark,
|
||||
"vod_actor": "",
|
||||
"vod_director": dire,
|
||||
"vod_content": desc
|
||||
}
|
||||
ja = jo['pages']
|
||||
playUrl = ''
|
||||
for tmpJo in ja:
|
||||
cid = tmpJo['cid']
|
||||
part = tmpJo['part'].replace("#", "-")
|
||||
playUrl = playUrl + '{0}${1}_{2}#'.format(part, aid, cid)
|
||||
|
||||
vod['vod_play_from'] = 'B站视频'
|
||||
vod['vod_play_url'] = playUrl
|
||||
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
header = {
|
||||
"Referer": "https://www.bilibili.com",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={0}'.format(key)
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
rsp = self.fetch(url, cookies=self.cookies,headers=header)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
if jo['code'] != 0:
|
||||
rspRetry = self.fetch(url, cookies=self.getCookie())
|
||||
content = rspRetry.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']['result']
|
||||
for vod in vodList:
|
||||
aid = str(vod['aid']).strip()
|
||||
title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace(""", '"')
|
||||
img = 'https:' + vod['pic'].strip()
|
||||
remark = str(vod['duration']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
result = {}
|
||||
|
||||
ids = id.split("_")
|
||||
url = 'https://api.bilibili.com:443/x/player/playurl?avid={0}&cid={1}&qn=120&fnval=0&128=128&fourk=1'.format(ids[0], ids[1])
|
||||
if len(self.cookies) <= 0:
|
||||
self.getCookie()
|
||||
rsp = self.fetch(url, cookies=self.cookies)
|
||||
jRoot = json.loads(rsp.text)
|
||||
jo = jRoot['data']
|
||||
ja = jo['durl']
|
||||
|
||||
maxSize = -1
|
||||
position = -1
|
||||
for i in range(len(ja)):
|
||||
tmpJo = ja[i]
|
||||
if maxSize < int(tmpJo['size']):
|
||||
maxSize = int(tmpJo['size'])
|
||||
position = i
|
||||
|
||||
url = ''
|
||||
if len(ja) > 0:
|
||||
if position == -1:
|
||||
position = 0
|
||||
url = ja[position]['url']
|
||||
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = url
|
||||
result["header"] = {
|
||||
"Referer": "https://www.bilibili.com",
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
result["contentType"] = 'video/mp4'
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {"收藏夹": [{"key": "order","name": "排序","value": [{"n": "收藏时间","v": "mtime"},{"n": "播放量","v": "view"},{"n": "投稿时间","v": "pubtime"}]},{"key": "mlid","name": "收藏夹分区","value": []}],"频道":[{"key":"cid","name":"分类","value":[{'n': '搞笑', 'v': 1833}, {'n': '美食', 'v': 20215}, {'n': '鬼畜', 'v': 68}, {'n': '天官赐福', 'v': 2544632}, {'n': '英雄联盟', 'v': 9222}, {'n': '美妆', 'v': 832569}, {'n': '必剪创作', 'v': 15775524}, {'n': '单机游戏', 'v': 17683}, {'n': '搞笑', 'v': 1833}, {'n': '科普', 'v': 5417}, {'n': '影视剪辑', 'v': 318570}, {'n': 'vlog', 'v': 2511282}, {'n': '声优', 'v': 1645}, {'n': '动漫杂谈', 'v': 530918}, {'n': 'COSPLAY', 'v': 88}, {'n': '漫展', 'v': 22551}, {'n': 'MAD', 'v': 281}, {'n': '手书', 'v': 608}, {'n': '英雄联盟', 'v': 9222}, {'n': '王者荣耀', 'v': 1404375}, {'n': '单机游戏', 'v': 17683}, {'n': '我的世界', 'v': 47988}, {'n': '守望先锋', 'v': 926988}, {'n': '恐怖游戏', 'v': 17941}, {'n': '英雄联盟', 'v': 9222}, {'n': '王者荣耀', 'v': 1404375}, {'n': '守望先锋', 'v': 926988}, {'n': '炉石传说', 'v': 318756}, {'n': 'DOTA2', 'v': 47034}, {'n': 'CS:GO', 'v': 99842}, {'n': '鬼畜', 'v': 68}, {'n': '鬼畜调教', 'v': 497221}, {'n': '诸葛亮', 'v': 51330}, {'n': '二次元鬼畜', 'v': 29415}, {'n': '王司徒', 'v': 987568}, {'n': '万恶之源', 'v': 21}, {'n': '美妆', 'v': 832569}, {'n': '服饰', 'v': 313718}, {'n': '减肥', 'v': 20805}, {'n': '穿搭', 'v': 1139735}, {'n': '发型', 'v': 13896}, {'n': '化妆教程', 'v': 261355}, {'n': '电音', 'v': 14426}, {'n': '欧美音乐', 'v': 17034}, {'n': '中文翻唱', 'v': 8043}, {'n': '洛天依', 'v': 8564}, {'n': '翻唱', 'v': 386}, {'n': '日文翻唱', 'v': 85689}, {'n': '科普', 'v': 5417}, {'n': '技术宅', 'v': 368}, {'n': '历史', 'v': 221}, {'n': '科学', 'v': 1364}, {'n': '人文', 'v': 40737}, {'n': '科幻', 'v': 5251}, {'n': '手机', 'v': 7007}, {'n': '手机评测', 'v': 143751}, {'n': '电脑', 'v': 1339}, {'n': '摄影', 'v': 25450}, {'n': '笔记本', 'v': 1338}, {'n': '装机', 'v': 413678}, {'n': '课堂教育', 'v': 3233375}, {'n': '公开课', 'v': 31864}, {'n': '演讲', 'v': 2739}, {'n': 'PS教程', 'v': 335752}, {'n': '编程', 'v': 28784}, {'n': '英语学习', 'v': 360005}, {'n': '喵星人', 'v': 1562}, {'n': '萌宠', 'v': 6943}, {'n': '汪星人', 'v': 9955}, {'n': '大熊猫', 'v': 22919}, {'n': '柴犬', 'v': 30239}, {'n': '吱星人', 'v': 6947}, {'n': '美食', 'v': 20215}, {'n': '甜点', 'v': 35505}, {'n': '吃货', 'v': 6942}, {'n': '厨艺', 'v': 239855}, {'n': '烘焙', 'v': 218245}, {'n': '街头美食', 'v': 1139423}, {'n': 'A.I.Channel', 'v': 3232987}, {'n': '虚拟UP主', 'v': 4429874}, {'n': '神楽めあ', 'v': 7562902}, {'n': '白上吹雪', 'v': 7355391}, {'n': '彩虹社', 'v': 1099778}, {'n': 'hololive', 'v': 8751822}, {'n': 'EXO', 'v': 191032}, {'n': '防弹少年团', 'v': 536395}, {'n': '肖战', 'v': 1450880}, {'n': '王一博', 'v': 902215}, {'n': '易烊千玺', 'v': 15186}, {'n': 'BLACKPINK', 'v': 1749296}, {'n': '宅舞', 'v': 9500}, {'n': '街舞', 'v': 5574}, {'n': '舞蹈教学', 'v': 157087}, {'n': '明星舞蹈', 'v': 6012204}, {'n': '韩舞', 'v': 159571}, {'n': '古典舞', 'v': 161247}, {'n': '旅游', 'v': 6572}, {'n': '绘画', 'v': 2800}, {'n': '手工', 'v': 11265}, {'n': 'vlog', 'v': 2511282}, {'n': 'DIY', 'v': 3620}, {'n': '手绘', 'v': 1210}, {'n': '综艺', 'v': 11687}, {'n': '国家宝藏', 'v': 105286}, {'n': '脱口秀', 'v': 4346}, {'n': '日本综艺', 'v': 81265}, {'n': '国内综艺', 'v': 641033}, {'n': '人类观察', 'v': 282453}, {'n': '影评', 'v': 111377}, {'n': '电影解说', 'v': 1161117}, {'n': '影视混剪', 'v': 882598}, {'n': '影视剪辑', 'v': 318570}, {'n': '漫威', 'v': 138600}, {'n': '超级英雄', 'v': 13881}, {'n': '影视混剪', 'v': 882598}, {'n': '影视剪辑', 'v': 318570}, {'n': '诸葛亮', 'v': 51330}, {'n': '韩剧', 'v': 53056}, {'n': '王司徒', 'v': 987568}, {'n': '泰剧', 'v': 179103}, {'n': '郭德纲', 'v': 8892}, {'n': '相声', 'v': 5783}, {'n': '张云雷', 'v': 1093613}, {'n': '秦霄贤', 'v': 3327368}, {'n': '孟鹤堂', 'v': 1482612}, {'n': '岳云鹏', 'v': 24467}, {'n': '假面骑士', 'v': 2069}, {'n': '特摄', 'v': 2947}, {'n': '奥特曼', 'v': 963}, {'n': '迪迦奥特曼', 'v': 13784}, {'n': '超级战队', 'v': 32881}, {'n': '铠甲勇士', 'v': 11564}, {'n': '健身', 'v': 4344}, {'n': '篮球', 'v': 1265}, {'n': '体育', 'v': 41103}, {'n': '帕梅拉', 'v': 257412}, {'n': '极限运动', 'v': 8876}, {'n': '足球', 'v': 584}, {'n': '星海', 'v': 178862}, {'n': '张召忠', 'v': 116480}, {'n': '航母', 'v': 57834}, {'n': '航天', 'v': 81618}, {'n': '导弹', 'v': 14958}, {'n': '战斗机', 'v': 24304}]}]}
|
||||
}
|
||||
header = {}
|
||||
|
||||
def localProxy(self, param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,461 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
import re
|
||||
from urllib import request, parse
|
||||
import urllib
|
||||
import urllib.request
|
||||
import time
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "中央电视台"#可搜索
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电视剧": "电视剧",
|
||||
"动画片": "动画片",
|
||||
"纪录片": "纪录片",
|
||||
"特别节目": "特别节目",
|
||||
"节目大全":"节目大全"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name':k,
|
||||
'type_id':cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
result = {
|
||||
'list':[]
|
||||
}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
month = ""#月
|
||||
year = ""#年
|
||||
area=''#地区
|
||||
channel=''#频道
|
||||
datafl=''#类型
|
||||
letter=''#字母
|
||||
pagecount=24
|
||||
if tid=='动画片':
|
||||
id=urllib.parse.quote(tid)
|
||||
if 'datadq-area' in extend.keys():
|
||||
area=urllib.parse.quote(extend['datadq-area'])
|
||||
if 'dataszm-letter' in extend.keys():
|
||||
letter=extend['dataszm-letter']
|
||||
if 'datafl-sc' in extend.keys():
|
||||
datafl=urllib.parse.quote(extend['datafl-sc'])
|
||||
url='https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955899450127&area={0}&sc={4}&fc={1}&letter={2}&p={3}&n=24&serviceId=tvcctv&topv=1&t=json'.format(area,id,letter,pg,datafl)
|
||||
elif tid=='纪录片':
|
||||
id=urllib.parse.quote(tid)
|
||||
if 'datapd-channel' in extend.keys():
|
||||
channel=urllib.parse.quote(extend['datapd-channel'])
|
||||
if 'datafl-sc' in extend.keys():
|
||||
datafl=urllib.parse.quote(extend['datafl-sc'])
|
||||
if 'datanf-year' in extend.keys():
|
||||
year=extend['datanf-year']
|
||||
if 'dataszm-letter' in extend.keys():
|
||||
letter=extend['dataszm-letter']
|
||||
url='https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955924871139&fc={0}&channel={1}&sc={2}&year={3}&letter={4}&p={5}&n=24&serviceId=tvcctv&topv=1&t=json'.format(id,channel,datafl,year,letter,pg)
|
||||
elif tid=='电视剧':
|
||||
id=urllib.parse.quote(tid)
|
||||
if 'datafl-sc' in extend.keys():
|
||||
datafl=urllib.parse.quote(extend['datafl-sc'])
|
||||
if 'datanf-year' in extend.keys():
|
||||
year=extend['datanf-year']
|
||||
if 'dataszm-letter' in extend.keys():
|
||||
letter=extend['dataszm-letter']
|
||||
url='https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955853485115&area={0}&sc={1}&fc={2}&year={3}&letter={4}&p={5}&n=24&serviceId=tvcctv&topv=1&t=json'.format(area,datafl,id,year,letter,pg)
|
||||
elif tid=='特别节目':
|
||||
id=urllib.parse.quote(tid)
|
||||
if 'datapd-channel' in extend.keys():
|
||||
channel=urllib.parse.quote(extend['datapd-channel'])
|
||||
if 'datafl-sc' in extend.keys():
|
||||
datafl=urllib.parse.quote(extend['datafl-sc'])
|
||||
if 'dataszm-letter' in extend.keys():
|
||||
letter=extend['dataszm-letter']
|
||||
url='https://api.cntv.cn/list/getVideoAlbumList?channelid=CHAL1460955953877151&channel={0}&sc={1}&fc={2}&bigday=&letter={3}&p={4}&n=24&serviceId=tvcctv&topv=1&t=json'.format(channel,datafl,id,letter,pg)
|
||||
elif tid=='节目大全':
|
||||
cid=''#频道
|
||||
if 'cid' in extend.keys():
|
||||
cid=extend['cid']
|
||||
fc=''#分类
|
||||
if 'fc' in extend.keys():
|
||||
fc=extend['fc']
|
||||
fl=''#字母
|
||||
if 'fl' in extend.keys():
|
||||
fl=extend['fl']
|
||||
url = 'https://api.cntv.cn/lanmu/columnSearch?&fl={0}&fc={1}&cid={2}&p={3}&n=20&serviceId=tvcctv&t=json&cb=ko'.format(fl,fc,cid,pg)
|
||||
pagecount=20
|
||||
else:
|
||||
url = 'https://tv.cctv.com/epg/index.shtml'
|
||||
|
||||
videos=[]
|
||||
htmlText =self.webReadFile(urlStr=url,header=self.header)
|
||||
if tid=='节目大全':
|
||||
index=htmlText.rfind(');')
|
||||
if index>-1:
|
||||
htmlText=htmlText[3:index]
|
||||
videos =self.get_list1(html=htmlText,tid=tid)
|
||||
else:
|
||||
videos =self.get_list(html=htmlText,tid=tid)
|
||||
#print(videos)
|
||||
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999 if len(videos)>=pagecount else pg
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
def detailContent(self,array):
|
||||
result={}
|
||||
aid = array[0].split('###')
|
||||
tid = aid[0]
|
||||
logo = aid[3]
|
||||
lastVideo = aid[2]
|
||||
title = aid[1]
|
||||
id= aid[4]
|
||||
|
||||
vod_year= aid[5]
|
||||
actors= aid[6]
|
||||
brief= aid[7]
|
||||
fromId='CCTV'
|
||||
if tid=="节目大全":
|
||||
lastUrl = 'https://api.cntv.cn/video/videoinfoByGuid?guid={0}&serviceId=tvcctv'.format(id)
|
||||
htmlTxt = self.webReadFile(urlStr=lastUrl,header=self.header)
|
||||
topicId=json.loads(htmlTxt)['ctid']
|
||||
Url = "https://api.cntv.cn/NewVideo/getVideoListByColumn?id={0}&d=&p=1&n=100&sort=desc&mode=0&serviceId=tvcctv&t=json".format(topicId)
|
||||
htmlTxt = self.webReadFile(urlStr=Url,header=self.header)
|
||||
else:
|
||||
Url='https://api.cntv.cn/NewVideo/getVideoListByAlbumIdNew?id={0}&serviceId=tvcctv&p=1&n=100&mode=0&pub=1'.format(id)
|
||||
jRoot = ''
|
||||
videoList = []
|
||||
try:
|
||||
if tid=="搜索":
|
||||
fromId='中央台'
|
||||
videoList=[title+"$"+lastVideo]
|
||||
else:
|
||||
htmlTxt=self.webReadFile(urlStr=Url,header=self.header)
|
||||
jRoot = json.loads(htmlTxt)
|
||||
data=jRoot['data']
|
||||
jsonList=data['list']
|
||||
videoList=self.get_EpisodesList(jsonList=jsonList)
|
||||
if len(videoList)<1:
|
||||
htmlTxt=self.webReadFile(urlStr=lastVideo,header=self.header)
|
||||
if tid=="电视剧" or tid=="纪录片":
|
||||
patternTxt=r"'title':\s*'(?P<title>.+?)',\n{0,1}\s*'brief':\s*'(.+?)',\n{0,1}\s*'img':\s*'(.+?)',\n{0,1}\s*'url':\s*'(?P<url>.+?)'"
|
||||
elif tid=="特别节目":
|
||||
patternTxt=r'class="tp1"><a\s*href="(?P<url>https://.+?)"\s*target="_blank"\s*title="(?P<title>.+?)"></a></div>'
|
||||
elif tid=="动画片":
|
||||
patternTxt=r"'title':\s*'(?P<title>.+?)',\n{0,1}\s*'img':\s*'(.+?)',\n{0,1}\s*'brief':\s*'(.+?)',\n{0,1}\s*'url':\s*'(?P<url>.+?)'"
|
||||
elif tid=="节目大全":
|
||||
patternTxt=r'href="(?P<url>.+?)" target="_blank" alt="(?P<title>.+?)" title=".+?">'
|
||||
videoList=self.get_EpisodesList_re(htmlTxt=htmlTxt,patternTxt=patternTxt)
|
||||
fromId='央视'
|
||||
except:
|
||||
pass
|
||||
if len(videoList) == 0:
|
||||
return {}
|
||||
vod = {
|
||||
"vod_id":array[0],
|
||||
"vod_name":title,
|
||||
"vod_pic":logo,
|
||||
"type_name":tid,
|
||||
"vod_year":vod_year,
|
||||
"vod_area":"",
|
||||
"vod_remarks":'',
|
||||
"vod_actor":actors,
|
||||
"vod_director":'',
|
||||
"vod_content":brief
|
||||
}
|
||||
vod['vod_play_from'] = fromId
|
||||
vod['vod_play_url'] = "#".join(videoList)
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def get_lineList(self,Txt,mark,after):
|
||||
circuit=[]
|
||||
origin=Txt.find(mark)
|
||||
while origin>8:
|
||||
end=Txt.find(after,origin)
|
||||
circuit.append(Txt[origin:end])
|
||||
origin=Txt.find(mark,end)
|
||||
return circuit
|
||||
def get_RegexGetTextLine(self,Text,RegexText,Index):
|
||||
returnTxt=[]
|
||||
pattern = re.compile(RegexText, re.M|re.S)
|
||||
ListRe=pattern.findall(Text)
|
||||
if len(ListRe)<1:
|
||||
return returnTxt
|
||||
for value in ListRe:
|
||||
returnTxt.append(value)
|
||||
return returnTxt
|
||||
def searchContent(self,key,quick):
|
||||
key=urllib.parse.quote(key)
|
||||
Url='https://search.cctv.com/ifsearch.php?page=1&qtext={0}&sort=relevance&pageSize=20&type=video&vtime=-1&datepid=1&channel=&pageflag=0&qtext_str={0}'.format(key)
|
||||
htmlTxt=self.webReadFile(urlStr=Url,header=self.header)
|
||||
videos=self.get_list_search(html=htmlTxt,tid='搜索')
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
url=''
|
||||
parse=0
|
||||
headers = {
|
||||
'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
|
||||
}
|
||||
if flag=='CCTV':
|
||||
url=self.get_m3u8(urlTxt=id)
|
||||
else:
|
||||
try:
|
||||
html=self.webReadFile(urlStr=id,header=self.header)
|
||||
guid=self.get_RegexGetText(Text=html,RegexText=r'var\sguid\s*=\s*"(.+?)";',Index=1)
|
||||
url=self.get_m3u8(urlTxt=guid)
|
||||
except :
|
||||
url=id
|
||||
parse=1
|
||||
if url.find('https:')<0:
|
||||
url=id
|
||||
parse=1
|
||||
result["parse"] = parse#1=嗅探,0=播放
|
||||
result["playUrl"] = ''
|
||||
result["url"] = url
|
||||
result["header"] =headers
|
||||
return result
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {
|
||||
"电视剧":[
|
||||
{"key":"datafl-sc","name":"类型","value":[{"n":"全部","v":""},{"n":"谍战","v":"谍战"},{"n":"悬疑","v":"悬疑"},{"n":"刑侦","v":"刑侦"},{"n":"历史","v":"历史"},{"n":"古装","v":"古装"},{"n":"武侠","v":"武侠"},{"n":"军旅","v":"军旅"},{"n":"战争","v":"战争"},{"n":"喜剧","v":"喜剧"},{"n":"青春","v":"青春"},{"n":"言情","v":"言情"},{"n":"偶像","v":"偶像"},{"n":"家庭","v":"家庭"},{"n":"年代","v":"年代"},{"n":"革命","v":"革命"},{"n":"农村","v":"农村"},{"n":"都市","v":"都市"},{"n":"其他","v":"其他"}]},
|
||||
{"key":"datadq-area","name":"地区","value":[{"n":"全部","v":""},{"n":"中国大陆","v":"中国大陆"},{"n":"中国香港","v":"香港"},{"n":"美国","v":"美国"},{"n":"欧洲","v":"欧洲"},{"n":"泰国","v":"泰国"}]},
|
||||
{"key":"datanf-year","name":"年份","value":[{"n":"全部","v":""},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"},{"n":"1999","v":"1999"},{"n":"1998","v":"1998"},{"n":"1997","v":"1997"}]},
|
||||
{"key":"dataszm-letter","name":"字母","value":[{"n":"全部","v":""},{"n":"A","v":"A"},{"n":"C","v":"C"},{"n":"E","v":"E"},{"n":"F","v":"F"},{"n":"G","v":"G"},{"n":"H","v":"H"},{"n":"I","v":"I"},{"n":"J","v":"J"},{"n":"K","v":"K"},{"n":"L","v":"L"},{"n":"M","v":"M"},{"n":"N","v":"N"},{"n":"O","v":"O"},{"n":"P","v":"P"},{"n":"Q","v":"Q"},{"n":"R","v":"R"},{"n":"S","v":"S"},{"n":"T","v":"T"},{"n":"U","v":"U"},{"n":"V","v":"V"},{"n":"W","v":"W"},{"n":"X","v":"X"},{"n":"Y","v":"Y"},{"n":"Z","v":"Z"},{"n":"0-9","v":"0-9"}]}
|
||||
],
|
||||
"动画片":[
|
||||
{"key":"datafl-sc","name":"类型","value":[{"n":"全部","v":""},{"n":"亲子","v":"亲子"},{"n":"搞笑","v":"搞笑"},{"n":"冒险","v":"冒险"},{"n":"动作","v":"动作"},{"n":"宠物","v":"宠物"},{"n":"体育","v":"体育"},{"n":"益智","v":"益智"},{"n":"历史","v":"历史"},{"n":"教育","v":"教育"},{"n":"校园","v":"校园"},{"n":"言情","v":"言情"},{"n":"武侠","v":"武侠"},{"n":"经典","v":"经典"},{"n":"未来","v":"未来"},{"n":"古代","v":"古代"},{"n":"神话","v":"神话"},{"n":"真人","v":"真人"},{"n":"励志","v":"励志"},{"n":"热血","v":"热血"},{"n":"奇幻","v":"奇幻"},{"n":"童话","v":"童话"},{"n":"剧情","v":"剧情"},{"n":"夺宝","v":"夺宝"},{"n":"其他","v":"其他"}]},
|
||||
{"key":"datadq-area","name":"地区","value":[{"n":"全部","v":""},{"n":"中国大陆","v":"中国大陆"},{"n":"美国","v":"美国"},{"n":"欧洲","v":"欧洲"}]},
|
||||
{"key":"dataszm-letter","name":"字母","value":[{"n":"全部","v":""},{"n":"A","v":"A"},{"n":"C","v":"C"},{"n":"E","v":"E"},{"n":"F","v":"F"},{"n":"G","v":"G"},{"n":"H","v":"H"},{"n":"I","v":"I"},{"n":"J","v":"J"},{"n":"K","v":"K"},{"n":"L","v":"L"},{"n":"M","v":"M"},{"n":"N","v":"N"},{"n":"O","v":"O"},{"n":"P","v":"P"},{"n":"Q","v":"Q"},{"n":"R","v":"R"},{"n":"S","v":"S"},{"n":"T","v":"T"},{"n":"U","v":"U"},{"n":"V","v":"V"},{"n":"W","v":"W"},{"n":"X","v":"X"},{"n":"Y","v":"Y"},{"n":"Z","v":"Z"},{"n":"0-9","v":"0-9"}]}
|
||||
],
|
||||
"纪录片":[
|
||||
{"key":"datapd-channel","name":"频道","value":[{"n":"全部","v":""},{"n":"CCTV{1 综合","v":"CCTV{1 综合"},{"n":"CCTV{2 财经","v":"CCTV{2 财经"},{"n":"CCTV{3 综艺","v":"CCTV{3 综艺"},{"n":"CCTV{4 中文国际","v":"CCTV{4 中文国际"},{"n":"CCTV{5 体育","v":"CCTV{5 体育"},{"n":"CCTV{6 电影","v":"CCTV{6 电影"},{"n":"CCTV{7 国防军事","v":"CCTV{7 国防军事"},{"n":"CCTV{8 电视剧","v":"CCTV{8 电视剧"},{"n":"CCTV{9 纪录","v":"CCTV{9 纪录"},{"n":"CCTV{10 科教","v":"CCTV{10 科教"},{"n":"CCTV{11 戏曲","v":"CCTV{11 戏曲"},{"n":"CCTV{12 社会与法","v":"CCTV{12 社会与法"},{"n":"CCTV{13 新闻","v":"CCTV{13 新闻"},{"n":"CCTV{14 少儿","v":"CCTV{14 少儿"},{"n":"CCTV{15 音乐","v":"CCTV{15 音乐"},{"n":"CCTV{17 农业农村","v":"CCTV{17 农业农村"}]},
|
||||
{"key":"datafl-sc","name":"类型","value":[{"n":"全部","v":""},{"n":"人文历史","v":"人文历史"},{"n":"人物","v":"人物"},{"n":"军事","v":"军事"},{"n":"探索","v":"探索"},{"n":"社会","v":"社会"},{"n":"时政","v":"时政"},{"n":"经济","v":"经济"},{"n":"科技","v":"科技"}]},
|
||||
{"key":"datanf-year","name":"年份","value":[{"n":"全部","v":""},{"n":"2023","v":"2023"},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"}]},
|
||||
{"key":"dataszm-letter","name":"字母","value":[{"n":"全部","v":""},{"n":"A","v":"A"},{"n":"C","v":"C"},{"n":"E","v":"E"},{"n":"F","v":"F"},{"n":"G","v":"G"},{"n":"H","v":"H"},{"n":"I","v":"I"},{"n":"J","v":"J"},{"n":"K","v":"K"},{"n":"L","v":"L"},{"n":"M","v":"M"},{"n":"N","v":"N"},{"n":"O","v":"O"},{"n":"P","v":"P"},{"n":"Q","v":"Q"},{"n":"R","v":"R"},{"n":"S","v":"S"},{"n":"T","v":"T"},{"n":"U","v":"U"},{"n":"V","v":"V"},{"n":"W","v":"W"},{"n":"X","v":"X"},{"n":"Y","v":"Y"},{"n":"Z","v":"Z"},{"n":"0-9","v":"0-9"}]}
|
||||
],
|
||||
"特别节目":[
|
||||
{"key":"datapd-channel","name":"频道","value":[{"n":"全部","v":""},{"n":"CCTV{1 综合","v":"CCTV{1 综合"},{"n":"CCTV{2 财经","v":"CCTV{2 财经"},{"n":"CCTV{3 综艺","v":"CCTV{3 综艺"},{"n":"CCTV{4 中文国际","v":"CCTV{4 中文国际"},{"n":"CCTV{5 体育","v":"CCTV{5 体育"},{"n":"CCTV{6 电影","v":"CCTV{6 电影"},{"n":"CCTV{7 国防军事","v":"CCTV{7 国防军事"},{"n":"CCTV{8 电视剧","v":"CCTV{8 电视剧"},{"n":"CCTV{9 纪录","v":"CCTV{9 纪录"},{"n":"CCTV{10 科教","v":"CCTV{10 科教"},{"n":"CCTV{11 戏曲","v":"CCTV{11 戏曲"},{"n":"CCTV{12 社会与法","v":"CCTV{12 社会与法"},{"n":"CCTV{13 新闻","v":"CCTV{13 新闻"},{"n":"CCTV{14 少儿","v":"CCTV{14 少儿"},{"n":"CCTV{15 音乐","v":"CCTV{15 音乐"},{"n":"CCTV{17 农业农村","v":"CCTV{17 农业农村"}]},
|
||||
{"key":"datafl-sc","name":"类型","value":[{"n":"全部","v":""},{"n":"全部","v":"全部"},{"n":"新闻","v":"新闻"},{"n":"经济","v":"经济"},{"n":"综艺","v":"综艺"},{"n":"体育","v":"体育"},{"n":"军事","v":"军事"},{"n":"影视","v":"影视"},{"n":"科教","v":"科教"},{"n":"戏曲","v":"戏曲"},{"n":"青少","v":"青少"},{"n":"音乐","v":"音乐"},{"n":"社会","v":"社会"},{"n":"公益","v":"公益"},{"n":"其他","v":"其他"}]},
|
||||
{"key":"dataszm-letter","name":"字母","value":[{"n":"全部","v":""},{"n":"A","v":"A"},{"n":"C","v":"C"},{"n":"E","v":"E"},{"n":"F","v":"F"},{"n":"G","v":"G"},{"n":"H","v":"H"},{"n":"I","v":"I"},{"n":"J","v":"J"},{"n":"K","v":"K"},{"n":"L","v":"L"},{"n":"M","v":"M"},{"n":"N","v":"N"},{"n":"O","v":"O"},{"n":"P","v":"P"},{"n":"Q","v":"Q"},{"n":"R","v":"R"},{"n":"S","v":"S"},{"n":"T","v":"T"},{"n":"U","v":"U"},{"n":"V","v":"V"},{"n":"W","v":"W"},{"n":"X","v":"X"},{"n":"Y","v":"Y"},{"n":"Z","v":"Z"},{"n":"0-9","v":"0-9"}]}
|
||||
],
|
||||
"节目大全":[{"key":"cid","name":"频道","value":[{"n":"全部","v":""},{"n":"CCTV-1综合","v":"EPGC1386744804340101"},{"n":"CCTV-2财经","v":"EPGC1386744804340102"},{"n":"CCTV-3综艺","v":"EPGC1386744804340103"},{"n":"CCTV-4中文国际","v":"EPGC1386744804340104"},{"n":"CCTV-5体育","v":"EPGC1386744804340107"},{"n":"CCTV-6电影","v":"EPGC1386744804340108"},{"n":"CCTV-7国防军事","v":"EPGC1386744804340109"},{"n":"CCTV-8电视剧","v":"EPGC1386744804340110"},{"n":"CCTV-9纪录","v":"EPGC1386744804340112"},{"n":"CCTV-10科教","v":"EPGC1386744804340113"},{"n":"CCTV-11戏曲","v":"EPGC1386744804340114"},{"n":"CCTV-12社会与法","v":"EPGC1386744804340115"},{"n":"CCTV-13新闻","v":"EPGC1386744804340116"},{"n":"CCTV-14少儿","v":"EPGC1386744804340117"},{"n":"CCTV-15音乐","v":"EPGC1386744804340118"},{"n":"CCTV-16奥林匹克","v":"EPGC1634630207058998"},{"n":"CCTV-17农业农村","v":"EPGC1563932742616872"},{"n":"CCTV-5+体育赛事","v":"EPGC1468294755566101"}]},{"key":"fc","name":"分类","value":[{"n":"全部","v":""},{"n":"新闻","v":"新闻"},{"n":"体育","v":"体育"},{"n":"综艺","v":"综艺"},{"n":"健康","v":"健康"},{"n":"生活","v":"生活"},{"n":"科教","v":"科教"},{"n":"经济","v":"经济"},{"n":"农业","v":"农业"},{"n":"法治","v":"法治"},{"n":"军事","v":"军事"},{"n":"少儿","v":"少儿"},{"n":"动画","v":"动画"},{"n":"纪实","v":"纪实"},{"n":"戏曲","v":"戏曲"},{"n":"音乐","v":"音乐"},{"n":"影视","v":"影视"}]},{"key":"fl","name":"字母","value":[{"n":"全部","v":""},{"n":"A","v":"A"},{"n":"B","v":"B"},{"n":"C","v":"C"},{"n":"D","v":"D"},{"n":"E","v":"E"},{"n":"F","v":"F"},{"n":"G","v":"G"},{"n":"H","v":"H"},{"n":"I","v":"I"},{"n":"J","v":"J"},{"n":"K","v":"K"},{"n":"L","v":"L"},{"n":"M","v":"M"},{"n":"N","v":"N"},{"n":"O","v":"O"},{"n":"P","v":"P"},{"n":"Q","v":"Q"},{"n":"R","v":"R"},{"n":"S","v":"S"},{"n":"T","v":"T"},{"n":"U","v":"U"},{"n":"V","v":"V"},{"n":"W","v":"W"},{"n":"X","v":"X"},{"n":"Y","v":"Y"},{"n":"Z","v":"Z"}]},{"key":"year","name":"年份","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"},{"n":"2011","v":"2011"},{"n":"2010","v":"2010"},{"n":"2009","v":"2009"},{"n":"2008","v":"2008"},{"n":"2007","v":"2007"},{"n":"2006","v":"2006"},{"n":"2005","v":"2005"},{"n":"2004","v":"2004"},{"n":"2003","v":"2003"},{"n":"2002","v":"2002"},{"n":"2001","v":"2001"},{"n":"2000","v":"2000"}]},{"key":"month","name":"月份","value":[{"n":"全部","v":""},{"n":"12","v":"12"},{"n":"11","v":"11"},{"n":"10","v":"10"},{"n":"09","v":"09"},{"n":"08","v":"08"},{"n":"07","v":"07"},{"n":"06","v":"06"},{"n":"05","v":"05"},{"n":"04","v":"04"},{"n":"03","v":"03"},{"n":"02","v":"02"},{"n":"01","v":"01"}]}]
|
||||
}
|
||||
}
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36",
|
||||
"Host": "tv.cctv.com",
|
||||
"Referer": "https://tv.cctv.com/"
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
#-----------------------------------------------自定义函数-----------------------------------------------
|
||||
#访问网页
|
||||
def webReadFile(self,urlStr,header):
|
||||
html=''
|
||||
req=urllib.request.Request(url=urlStr)#,headers=header
|
||||
with urllib.request.urlopen(req) as response:
|
||||
html = response.read().decode('utf-8')
|
||||
return html
|
||||
#判断网络地址是否存在
|
||||
def TestWebPage(self,urlStr,header):
|
||||
html=''
|
||||
req=urllib.request.Request(url=urlStr,method='HEAD')#,headers=header
|
||||
with urllib.request.urlopen(req) as response:
|
||||
html = response.getcode ()
|
||||
return html
|
||||
#正则取文本
|
||||
def get_RegexGetText(self,Text,RegexText,Index):
|
||||
returnTxt=""
|
||||
Regex=re.search(RegexText, Text, re.M|re.S)
|
||||
if Regex is None:
|
||||
returnTxt=""
|
||||
else:
|
||||
returnTxt=Regex.group(Index)
|
||||
return returnTxt
|
||||
#取集数
|
||||
def get_EpisodesList(self,jsonList):
|
||||
videos=[]
|
||||
for vod in jsonList:
|
||||
url = vod['guid']
|
||||
title =vod['title']
|
||||
if len(url) == 0:
|
||||
continue
|
||||
videos.append(title+"$"+url)
|
||||
return videos
|
||||
#取集数
|
||||
def get_EpisodesList_re(self,htmlTxt,patternTxt):
|
||||
ListRe=re.finditer(patternTxt, htmlTxt, re.M|re.S)
|
||||
videos=[]
|
||||
for vod in ListRe:
|
||||
url = vod.group('url')
|
||||
title =vod.group('title')
|
||||
if len(url) == 0:
|
||||
continue
|
||||
videos.append(title+"$"+url)
|
||||
return videos
|
||||
#取剧集区
|
||||
def get_lineList(self,Txt,mark,after):
|
||||
circuit=[]
|
||||
origin=Txt.find(mark)
|
||||
while origin>8:
|
||||
end=Txt.find(after,origin)
|
||||
circuit.append(Txt[origin:end])
|
||||
origin=Txt.find(mark,end)
|
||||
return circuit
|
||||
#正则取文本,返回数组
|
||||
def get_RegexGetTextLine(self,Text,RegexText,Index):
|
||||
returnTxt=[]
|
||||
pattern = re.compile(RegexText, re.M|re.S)
|
||||
ListRe=pattern.findall(Text)
|
||||
if len(ListRe)<1:
|
||||
return returnTxt
|
||||
for value in ListRe:
|
||||
returnTxt.append(value)
|
||||
return returnTxt
|
||||
#删除html标签
|
||||
def removeHtml(self,txt):
|
||||
soup = re.compile(r'<[^>]+>',re.S)
|
||||
txt =soup.sub('', txt)
|
||||
return txt.replace(" "," ")
|
||||
#取m3u8
|
||||
def get_m3u8(self,urlTxt):
|
||||
url = "https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid={0}".format(urlTxt)
|
||||
html=self.webReadFile(urlStr=url,header=self.header)
|
||||
jo =json.loads(html)
|
||||
link = jo['hls_url'].strip()
|
||||
html = self.webReadFile(urlStr=link,header=self.header)
|
||||
content = html.strip()
|
||||
arr = content.split('\n')
|
||||
urlPrefix = self.get_RegexGetText(Text=link,RegexText='(http[s]?://[a-zA-z0-9.]+)/',Index=1)
|
||||
subUrl = arr[-1].split('/')
|
||||
subUrl[3] = '1200'
|
||||
subUrl[-1] = '1200.m3u8'
|
||||
hdUrl = urlPrefix + '/'.join(subUrl)
|
||||
|
||||
url = urlPrefix + arr[-1]
|
||||
|
||||
hdRsp = self.TestWebPage(urlStr=hdUrl,header=self.header)
|
||||
if hdRsp == 200:
|
||||
url = hdUrl
|
||||
else:
|
||||
url=''
|
||||
return url
|
||||
#搜索
|
||||
def get_list_search(self,html,tid):
|
||||
jRoot = json.loads(html)
|
||||
jsonList=jRoot['list']
|
||||
videos=[]
|
||||
for vod in jsonList:
|
||||
url = vod['urllink']
|
||||
title =self.removeHtml(txt=vod['title'])
|
||||
img=vod['imglink']
|
||||
id=vod['id']
|
||||
brief=vod['channel']
|
||||
year=vod['uploadtime']
|
||||
if len(url) == 0:
|
||||
continue
|
||||
guid="{0}###{1}###{2}###{3}###{4}###{5}###{6}###{7}".format(tid,title,url,img,id,year,'',brief)
|
||||
videos.append({
|
||||
"vod_id":guid,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":year
|
||||
})
|
||||
return videos
|
||||
return videos
|
||||
def get_list1(self,html,tid):
|
||||
jRoot = json.loads(html)
|
||||
videos = []
|
||||
data=jRoot['response']
|
||||
if data is None:
|
||||
return []
|
||||
jsonList=data['docs']
|
||||
for vod in jsonList:
|
||||
id = vod['lastVIDE']['videoSharedCode']
|
||||
title =vod['column_name']
|
||||
url=vod['column_website']
|
||||
img=vod['column_logo']
|
||||
year=vod['column_playdate']
|
||||
brief=vod['column_brief']
|
||||
actors=''
|
||||
if len(url) == 0:
|
||||
continue
|
||||
guid="{0}###{1}###{2}###{3}###{4}###{5}###{6}###{7}".format(tid,title,url,img,id,year,actors,brief)
|
||||
#print(vod_id)
|
||||
videos.append({
|
||||
"vod_id":guid,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":''
|
||||
})
|
||||
#print(videos)
|
||||
return videos
|
||||
#分类取结果
|
||||
def get_list(self,html,tid):
|
||||
jRoot = json.loads(html)
|
||||
videos = []
|
||||
data=jRoot['data']
|
||||
if data is None:
|
||||
return []
|
||||
jsonList=data['list']
|
||||
for vod in jsonList:
|
||||
url = vod['url']
|
||||
title =vod['title']
|
||||
img=vod['image']
|
||||
id=vod['id']
|
||||
try:
|
||||
brief=vod['brief']
|
||||
except:
|
||||
brief=''
|
||||
try:
|
||||
year=vod['year']
|
||||
except:
|
||||
year=''
|
||||
try:
|
||||
actors=vod['actors']
|
||||
except:
|
||||
actors=''
|
||||
if len(url) == 0:
|
||||
continue
|
||||
guid="{0}###{1}###{2}###{3}###{4}###{5}###{6}###{7}".format(tid,title,url,img,id,year,actors,brief)
|
||||
#print(vod_id)
|
||||
videos.append({
|
||||
"vod_id":guid,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":''
|
||||
})
|
||||
return videos
|
||||
@@ -0,0 +1,218 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import sys
|
||||
import re
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import urllib.parse
|
||||
import json
|
||||
import base64
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "创艺影视"
|
||||
|
||||
def init(self, extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电影": "1",
|
||||
"剧集": "2",
|
||||
"动漫": "4",
|
||||
"综艺": "3",
|
||||
"纪录片": "30"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
|
||||
result['class'] = classes
|
||||
if (filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {
|
||||
'list': []
|
||||
}
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
result = {}
|
||||
header = {"User-Agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36"}
|
||||
url = 'https://www.30dian.cn/vodtype/{0}-{1}.html'.format(tid, pg)
|
||||
rsp = self.fetch(url,headers=header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
aList = root.xpath("//div[@class='module-list module-lines-list']/div/div")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = name = a.xpath("./div[@class='module-item-cover']/div/a/@title")[0]
|
||||
pic = a.xpath("./div[@class='module-item-cover']/div/img/@data-src")[0]
|
||||
mark = a.xpath("./div[@class='module-item-text']/text()")[0]
|
||||
sid = self.regStr(reg=r'voddetail\/(.*?).html', src=a.xpath("./div[@class='module-item-cover']/div/a/@href")[0])
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": name,
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": mark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 999
|
||||
result['limit'] = 5
|
||||
result['total'] = 9999
|
||||
return result
|
||||
|
||||
def detailContent(self, array):
|
||||
tid = array[0]
|
||||
url = 'https://www.30dian.cn/voddetail/{0}.html'.format(tid)
|
||||
header = {"User-Agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36"}
|
||||
rsp = self.fetch(url,headers=header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
divContent = root.xpath("//div[@class='box view-heading']")[0]
|
||||
title = divContent.xpath(".//div[@class='video-info-header']/h1/text()")[0].strip()
|
||||
pic = divContent.xpath(".//div[@class='module-item-pic']/img/@data-src")[0]
|
||||
vod = {
|
||||
"vod_id": tid,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": "",
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": "",
|
||||
"vod_actor": "",
|
||||
"vod_director": "",
|
||||
"vod_content": ""
|
||||
}
|
||||
vod_play_from = '$$$'
|
||||
playFrom = []
|
||||
titles = root.xpath(".//div[contains(@class,'module-player-tab')]/div[@class='module-tab-items']/div[@class='module-tab-content']")[0]
|
||||
vodHeader = titles.xpath("./div/span/text()")
|
||||
for v in vodHeader:
|
||||
playFrom.append(self.cleanText(v).replace(" ", ""))
|
||||
vod_play_from = vod_play_from.join(playFrom)
|
||||
vod_play_url = '$$$'
|
||||
playList = []
|
||||
vodList = root.xpath(".//div[@class='module']/div[contains(@id,'glist-')]")
|
||||
for vl in vodList:
|
||||
vodItems = []
|
||||
aList = vl.xpath(".//div[@class='scroll-content']/a")
|
||||
if len(aList) <= 0:
|
||||
name = '无法找到播放源'
|
||||
tId = '00000'
|
||||
vodItems.append(name + "$" + tId)
|
||||
else:
|
||||
for tA in aList:
|
||||
href = tA.xpath('./@href')[0]
|
||||
name = tA.xpath("./span/text()")[0].strip()
|
||||
tId = self.regStr(href, '/vodplay/(\\S+).html')
|
||||
vodItems.append(name + "$" + tId)
|
||||
joinStr = '#'
|
||||
joinStr = joinStr.join(vodItems)
|
||||
playList.append(joinStr)
|
||||
vod_play_url = vod_play_url.join(playList)
|
||||
|
||||
vod['vod_play_from'] = vod_play_from
|
||||
vod['vod_play_url'] = vod_play_url
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
url = 'https://www.30dian.cn/vodsearch/-------------.html?wd={0}'.format(key)
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36"}
|
||||
rsp = self.fetch(url, headers=header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
aList = root.xpath("//div[@class='module-items']/div")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = a.xpath(".//div[@class='module-item-pic']/img/@alt")[0]
|
||||
pic = a.xpath(".//div[@class='module-item-pic']/img/@data-src")[0]
|
||||
sid = a.xpath(".//div[@class='video-info']/div[@class='video-info-header']/a/@href")[0]
|
||||
sid = self.regStr(sid,'/voddetail/(\\S+).html')
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": name,
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": ''
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
def parseCBC(self, enc, key, iv):
|
||||
keyBytes = key.encode("utf-8")
|
||||
ivBytes = iv.encode("utf-8")
|
||||
cipher = AES.new(keyBytes, AES.MODE_CBC, ivBytes)
|
||||
msg = cipher.decrypt(enc)
|
||||
paddingLen = msg[len(msg) - 1]
|
||||
return msg[0:-paddingLen]
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
result = {}
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36"}
|
||||
if id == '00000':
|
||||
return {}
|
||||
url = 'https://www.30dian.cn/vodplay/{0}.html'.format(id)
|
||||
rsp = self.fetch(url, headers=header)
|
||||
jo = self.regStr(reg='var player_data=(.*?)</script>', src=self.cleanText(rsp.text))
|
||||
scripts = json.loads(jo)
|
||||
ukey = scripts['url']
|
||||
pf = scripts['from']
|
||||
purl = urllib.parse.unquote(ukey)
|
||||
if purl.startswith('http'):
|
||||
purl = purl
|
||||
if pf == 'wjm3u8':
|
||||
prsp = self.fetch(purl, headers=header)
|
||||
purle = prsp.text.strip('\n').split('\n')[-1]
|
||||
purls = re.findall(r"http.*://.*?/", purl)[0].strip('/')
|
||||
purl = purls + purle
|
||||
else:
|
||||
scrurl = 'https://vip.30dian.cn/?url={0}'.format(purl)
|
||||
script = self.fetch(scrurl,headers=header)
|
||||
html = script.text
|
||||
pat = 'var le_token = \\"([\\d\\w]+)\\"'
|
||||
cpat = 'getVideoInfo\\(\\"(.*)\\"\\)'
|
||||
content = self.regStr(html, cpat)
|
||||
iv = self.regStr(html, pat)
|
||||
key = 'A42EAC0C2B408472'
|
||||
purl = self.parseCBC(base64.b64decode(content), key, iv).decode()
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = purl
|
||||
result["header"] = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"}
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def localProxy(self, param):
|
||||
action = {
|
||||
'url': '',
|
||||
'header': '',
|
||||
'param': '',
|
||||
'type': 'string',
|
||||
'after': ''
|
||||
}
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,273 @@
|
||||
# coding=utf-8
|
||||
# !/usr/bin/python
|
||||
import re
|
||||
import sys
|
||||
import base64
|
||||
import hashlib
|
||||
import urllib
|
||||
import requests
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "厂长资源"
|
||||
|
||||
def init(self, extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"豆瓣电影Top250": "dbtop250",
|
||||
"最新电影": "zuixindianying",
|
||||
"电视剧": "dsj",
|
||||
"国产剧": "gcj",
|
||||
"美剧": "meijutt",
|
||||
"韩剧": "hanjutv",
|
||||
"番剧": "fanju",
|
||||
"动漫": "dm"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
url = "https://czzy33.com/"
|
||||
rsp = requests.get(url, headers=self.header, timeout=5)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
aList = root.xpath("//div[@class='mi_btcon']//ul/li")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = a.xpath('./a/img/@alt')[0]
|
||||
pic = a.xpath('./a/img/@data-original')[0]
|
||||
mark = a.xpath("./div[@class='hdinfo']/span/text()")
|
||||
if mark != []:
|
||||
mark = mark[0]
|
||||
else:
|
||||
mark = 'HD'
|
||||
sid = a.xpath("./a/@href")[0]
|
||||
sid = self.regStr(sid, "/movie/(\\S+).html")
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": name,
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": mark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = 1
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
result = {}
|
||||
header = {
|
||||
'Origin': 'https://czzy.fun/',
|
||||
'Referer': 'https://czzy.fun/',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
|
||||
'Cookie': 'esc_search_captcha=1'
|
||||
}
|
||||
url = 'https://czzy.fun/{0}/page/{1}'.format(tid,pg)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
aList = root.xpath("//div[contains(@class,'bt_img mi_ne_kd mrb')]/ul/li")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = a.xpath('./a/img/@alt')[0]
|
||||
pic = a.xpath('./a/img/@data-original')[0]
|
||||
mark = a.xpath(".//div[@class='jidi']/span/text()")
|
||||
if mark ==[]:
|
||||
mark = a.xpath("./div[@class='hdinfo']/span/text()")
|
||||
mark = mark[0]
|
||||
sid = a.xpath("./a/@href")[0]
|
||||
sid = self.regStr(sid, "/movie/(\\S+).html")
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": name,
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": mark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, array):
|
||||
tid = array[0]
|
||||
url = 'https://czzy.fun/movie/{0}.html'.format(tid)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
node = root.xpath("//div[@class='dyxingq']")[0]
|
||||
pic = node.xpath(".//div[@class='dyimg fl']/img/@src")[0]
|
||||
title = node.xpath('.//h1/text()')[0]
|
||||
detail = root.xpath(".//div[@class='yp_context']//p/text()")[0]
|
||||
vod = {
|
||||
"vod_id": tid,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": "",
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": "",
|
||||
"vod_actor": "",
|
||||
"vod_director": "",
|
||||
"vod_content": detail
|
||||
}
|
||||
infoArray = node.xpath(".//ul[@class='moviedteail_list']/li")
|
||||
for info in infoArray:
|
||||
content = info.xpath('string(.)')
|
||||
if content.startswith('地区'):
|
||||
tpyeare = ''
|
||||
for inf in info:
|
||||
tn = inf.text
|
||||
tpyeare = tpyeare +'/'+'{0}'.format(tn)
|
||||
vod['vod_area'] = tpyeare.strip('/')
|
||||
if content.startswith('年份'):
|
||||
vod['vod_year'] = content.replace("年份:","")
|
||||
if content.startswith('主演'):
|
||||
tpyeact = ''
|
||||
for inf in info:
|
||||
tn = inf.text
|
||||
tpyeact = tpyeact +'/'+'{0}'.format(tn)
|
||||
vod['vod_actor'] = tpyeact.strip('/')
|
||||
if content.startswith('导演'):
|
||||
tpyedire = ''
|
||||
for inf in info:
|
||||
tn = inf.text
|
||||
tpyedire = tpyedire +'/'+'{0}'.format(tn)
|
||||
vod['vod_director'] = tpyedire .strip('/')
|
||||
vod_play_from = '$$$'
|
||||
playFrom = ['厂长']
|
||||
vod_play_from = vod_play_from.join(playFrom)
|
||||
vod_play_url = '$$$'
|
||||
playList = []
|
||||
vodList = root.xpath("//div[@class='paly_list_btn']")
|
||||
for vl in vodList:
|
||||
vodItems = []
|
||||
aList = vl.xpath('./a')
|
||||
for tA in aList:
|
||||
href = tA.xpath('./@href')[0]
|
||||
name = tA.xpath('./text()')[0].replace('\xa0','')
|
||||
tId = self.regStr(href, '/v_play/(\\S+).html')
|
||||
vodItems.append(name + "$" + tId)
|
||||
joinStr = '#'
|
||||
joinStr = joinStr.join(vodItems)
|
||||
playList.append(joinStr)
|
||||
vod_play_url = vod_play_url.join(playList)
|
||||
|
||||
vod['vod_play_from'] = vod_play_from
|
||||
vod['vod_play_url'] = vod_play_url
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
url = 'https://czzy.fun/?s={0}'.format(urllib.parse.quote(key))
|
||||
rsp = requests.get(url, headers=self.header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
vodList = root.xpath("//div[contains(@class,'mi_ne_kd')]/ul/li/a")
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
name = vod.xpath('./img/@alt')[0]
|
||||
pic = vod.xpath('./img/@data-original')[0]
|
||||
href = vod.xpath('./@href')[0]
|
||||
tid = self.regStr(href, 'movie/(\\S+).html')
|
||||
res = vod.xpath('./div[@class="jidi"]/span/text()')
|
||||
if len(res) == 0:
|
||||
remark = '全1集'
|
||||
else:
|
||||
remark = vod.xpath('./div[@class="jidi"]/span/text()')[0]
|
||||
videos.append({
|
||||
"vod_id": tid,
|
||||
"vod_name": name,
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {
|
||||
'Origin': 'https://czzy.fun/',
|
||||
'Referer': 'https://czzy.fun/',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
|
||||
'Cookie': 'esc_search_captcha=1'
|
||||
}
|
||||
|
||||
def parseCBC(self, enc, key, iv):
|
||||
keyBytes = key.encode("utf-8")
|
||||
ivBytes = iv.encode("utf-8")
|
||||
cipher = AES.new(keyBytes, AES.MODE_CBC, ivBytes)
|
||||
msg = cipher.decrypt(enc)
|
||||
paddingLen = msg[len(msg) - 1]
|
||||
return msg[0:-paddingLen]
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
result = {}
|
||||
url = 'https://czzy.fun/v_play/{0}.html'.format(id)
|
||||
rsp = self.fetch(url, headers=self.header)
|
||||
pat = '\\"([^\\"]+)\\";var [\\d\\w]+=function dncry.*md5.enc.Utf8.parse\\(\\"([\\d\\w]+)\\".*md5.enc.Utf8.parse\\(([\\d]+)\\)'
|
||||
html = rsp.text
|
||||
content = self.regStr(html, pat)
|
||||
if content == '':
|
||||
str3 = url
|
||||
pars = 1
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
|
||||
}
|
||||
else:
|
||||
key = self.regStr(html, pat, 2)
|
||||
iv = self.regStr(html, pat, 3)
|
||||
decontent = self.parseCBC(base64.b64decode(content), key, iv).decode()
|
||||
urlPat = 'video: \\{url: \\\"([^\\\"]+)\\\"'
|
||||
vttPat = 'subtitle: \\{url:\\\"([^\\\"]+\\.vtt)\\\"'
|
||||
str3 = self.regStr(decontent, urlPat)
|
||||
str4 = self.regStr(decontent, vttPat)
|
||||
self.loadVtt(str3)
|
||||
pars = 0
|
||||
header = ''
|
||||
if len(str4) > 0:
|
||||
result['subf'] = '/vtt/utf-8'
|
||||
result['subt'] = ''
|
||||
result = {
|
||||
'parse': pars,
|
||||
'playUrl': '',
|
||||
'url': str3,
|
||||
'header': header
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
def loadVtt(self, url):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def localProxy(self, param):
|
||||
action = {}
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,127 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
|
||||
host_url = 'https://frodo.douban.com/api/v2'
|
||||
apikey = "?apikey=0ac44ae016490db2204ce0a042db2916"
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "豆瓣"
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"热门电影": "hot_gaia",
|
||||
"热播剧集": "tv_hot",
|
||||
"热播综艺": "show_hot",
|
||||
"电影筛选": "movie",
|
||||
"电视筛选": "tv",
|
||||
"电影榜单": "rank_list_movie",
|
||||
"电视榜单": "rank_list_tv"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name':k,
|
||||
'type_id':cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
url = host_url + '/subject_collection/subject_real_time_hotest/items' + apikey
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
jo = json.loads(rsp.text)
|
||||
joList = jo.get("subject_collection_items")
|
||||
lists = []
|
||||
for item in joList:
|
||||
rating = item['rating']['value'] if item['rating'] else ""
|
||||
lists.append({
|
||||
"vod_id": f'msearch:{item.get("type", "")}__{item.get("id", "")}',
|
||||
"vod_name": item['title'],
|
||||
"vod_pic": item['pic']['normal'],
|
||||
"vod_remarks": rating
|
||||
})
|
||||
result = {
|
||||
'list':lists
|
||||
}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
if extend:
|
||||
sort = extend.pop('sort') if "sort" in extend else "T"
|
||||
tags = ",".join(item for item in extend.values())
|
||||
else:
|
||||
sort = "T"
|
||||
tags = ""
|
||||
if tid == "hot_gaia":
|
||||
urlpath = f"/movie/{tid}"
|
||||
getdata = "items"
|
||||
sort = extend.get("sort", "recommend")
|
||||
area = extend.get("area", "全部")
|
||||
sort = sort + "&area=" + area
|
||||
elif tid == "tv_hot" or tid == "show_hot":
|
||||
urlpath = f"/subject_collection/{tid}/items"
|
||||
getdata = "subject_collection_items"
|
||||
elif tid.startswith("rank_list"):
|
||||
id = "movie_real_time_hotest" if tid == "rank_list_movie" else "tv_real_time_hotest"
|
||||
urlpath = f"/subject_collection/{id}/items"
|
||||
getdata = "subject_collection_items"
|
||||
else:
|
||||
urlpath = f"/{tid}/recommend"
|
||||
getdata = "items"
|
||||
|
||||
url = host_url + urlpath + apikey + '&sort=' + sort + '&tags=' + tags + '&start=' + str((int(pg) - 1) * 30)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
jo = json.loads(rsp.text)
|
||||
jolist = jo[getdata]
|
||||
|
||||
videos = []
|
||||
for vod in jolist:
|
||||
rating = vod.get("rating", "").get("value", "") if vod.get("rating", "") else ""
|
||||
pic = vod.get("pic", "").get("normal", "") if vod.get("pic", "") else ""
|
||||
videos.append({
|
||||
"vod_id": f'msearch:{vod.get("type", "")}__{vod.get("id", "")}',
|
||||
"vod_name": vod['title'],
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": rating
|
||||
})
|
||||
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self,array):
|
||||
pass
|
||||
def searchContent(self,key,quick):
|
||||
pass
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
pass
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {"hot_gaia":[{"key":"sort","name":"排序","value":[{"n":"热度","v":"recommend"},{"n":"最新","v":"time"},{"n":"评分","v":"rank"}]},{"key":"area","name":"地区","value":[{"n":"全部","v":"全部"},{"n":"华语","v":"华语"},{"n":"欧美","v":"欧美"},{"n":"韩国","v":"韩国"},{"n":"日本","v":"日本"}]}],"tv_hot":[{"key":"type","name":"分类","value":[{"n":"综合","v":"tv_hot"},{"n":"国产剧","v":"tv_domestic"},{"n":"欧美剧","v":"tv_american"},{"n":"日剧","v":"tv_japanese"},{"n":"韩剧","v":"tv_korean"},{"n":"动画","v":"tv_animation"}]}],"show_hot":[{"key":"type","name":"分类","value":[{"n":"综合","v":"show_hot"},{"n":"国内","v":"show_domestic"},{"n":"国外","v":"show_foreign"}]}],"movie":[{"key":"类型","name":"类型","value":[{"n":"全部类型","v":""},{"n":"喜剧","v":"喜剧"},{"n":"爱情","v":"爱情"},{"n":"动作","v":"动作"},{"n":"科幻","v":"科幻"},{"n":"动画","v":"动画"},{"n":"悬疑","v":"悬疑"},{"n":"犯罪","v":"犯罪"},{"n":"惊悚","v":"惊悚"},{"n":"冒险","v":"冒险"},{"n":"音乐","v":"音乐"},{"n":"历史","v":"历史"},{"n":"奇幻","v":"奇幻"},{"n":"恐怖","v":"恐怖"},{"n":"战争","v":"战争"},{"n":"传记","v":"传记"},{"n":"歌舞","v":"歌舞"},{"n":"武侠","v":"武侠"},{"n":"情色","v":"情色"},{"n":"灾难","v":"灾难"},{"n":"西部","v":"西部"},{"n":"纪录片","v":"纪录片"},{"n":"短片","v":"短片"}]},{"key":"地区","name":"地区","value":[{"n":"全部地区","v":""},{"n":"华语","v":"华语"},{"n":"欧美","v":"欧美"},{"n":"韩国","v":"韩国"},{"n":"日本","v":"日本"},{"n":"中国大陆","v":"中国大陆"},{"n":"美国","v":"美国"},{"n":"中国香港","v":"中国香港"},{"n":"中国台湾","v":"中国台湾"},{"n":"英国","v":"英国"},{"n":"法国","v":"法国"},{"n":"德国","v":"德国"},{"n":"意大利","v":"意大利"},{"n":"西班牙","v":"西班牙"},{"n":"印度","v":"印度"},{"n":"泰国","v":"泰国"},{"n":"俄罗斯","v":"俄罗斯"},{"n":"加拿大","v":"加拿大"},{"n":"澳大利亚","v":"澳大利亚"},{"n":"爱尔兰","v":"爱尔兰"},{"n":"瑞典","v":"瑞典"},{"n":"巴西","v":"巴西"},{"n":"丹麦","v":"丹麦"}]},{"key":"sort","name":"排序","value":[{"n":"近期热度","v":"T"},{"n":"首映时间","v":"R"},{"n":"高分优先","v":"S"}]},{"key":"年代","name":"年代","value":[{"n":"全部年代","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2010年代","v":"2010年代"},{"n":"2000年代","v":"2000年代"},{"n":"90年代","v":"90年代"},{"n":"80年代","v":"80年代"},{"n":"70年代","v":"70年代"},{"n":"60年代","v":"60年代"},{"n":"更早","v":"更早"}]}],"tv":[{"key":"类型","name":"类型","value":[{"n":"不限","v":""},{"n":"电视剧","v":"电视剧"},{"n":"综艺","v":"综艺"}]},{"key":"电视剧形式","name":"电视剧形式","value":[{"n":"不限","v":""},{"n":"喜剧","v":"喜剧"},{"n":"爱情","v":"爱情"},{"n":"悬疑","v":"悬疑"},{"n":"动画","v":"动画"},{"n":"武侠","v":"武侠"},{"n":"古装","v":"古装"},{"n":"家庭","v":"家庭"},{"n":"犯罪","v":"犯罪"},{"n":"科幻","v":"科幻"},{"n":"恐怖","v":"恐怖"},{"n":"历史","v":"历史"},{"n":"战争","v":"战争"},{"n":"动作","v":"动作"},{"n":"冒险","v":"冒险"},{"n":"传记","v":"传记"},{"n":"剧情","v":"剧情"},{"n":"奇幻","v":"奇幻"},{"n":"惊悚","v":"惊悚"},{"n":"灾难","v":"灾难"},{"n":"歌舞","v":"歌舞"},{"n":"音乐","v":"音乐"}]},{"key":"综艺形式","name":"综艺形式","value":[{"n":"不限","v":""},{"n":"真人秀","v":"真人秀"},{"n":"脱口秀","v":"脱口秀"},{"n":"音乐","v":"音乐"},{"n":"歌舞","v":"歌舞"}]},{"key":"地区","name":"地区","value":[{"n":"全部地区","v":""},{"n":"华语","v":"华语"},{"n":"欧美","v":"欧美"},{"n":"国外","v":"国外"},{"n":"韩国","v":"韩国"},{"n":"日本","v":"日本"},{"n":"中国大陆","v":"中国大陆"},{"n":"中国香港","v":"中国香港"},{"n":"美国","v":"美国"},{"n":"英国","v":"英国"},{"n":"泰国","v":"泰国"},{"n":"中国台湾","v":"中国台湾"},{"n":"意大利","v":"意大利"},{"n":"法国","v":"法国"},{"n":"德国","v":"德国"},{"n":"西班牙","v":"西班牙"},{"n":"俄罗斯","v":"俄罗斯"},{"n":"瑞典","v":"瑞典"},{"n":"巴西","v":"巴西"},{"n":"丹麦","v":"丹麦"},{"n":"印度","v":"印度"},{"n":"加拿大","v":"加拿大"},{"n":"爱尔兰","v":"爱尔兰"},{"n":"澳大利亚","v":"澳大利亚"}]},{"key":"sort","name":"排序","value":[{"n":"近期热度","v":"T"},{"n":"首播时间","v":"R"},{"n":"高分优先","v":"S"}]},{"key":"年代","name":"年代","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2010年代","v":"2010年代"},{"n":"2000年代","v":"2000年代"},{"n":"90年代","v":"90年代"},{"n":"80年代","v":"80年代"},{"n":"70年代","v":"70年代"},{"n":"60年代","v":"60年代"},{"n":"更早","v":"更早"}]},{"key":"平台","name":"平台","value":[{"n":"全部","v":""},{"n":"腾讯视频","v":"腾讯视频"},{"n":"爱奇艺","v":"爱奇艺"},{"n":"优酷","v":"优酷"},{"n":"湖南卫视","v":"湖南卫视"},{"n":"Netflix","v":"Netflix"},{"n":"HBO","v":"HBO"},{"n":"BBC","v":"BBC"},{"n":"NHK","v":"NHK"},{"n":"CBS","v":"CBS"},{"n":"NBC","v":"NBC"},{"n":"tvN","v":"tvN"}]}],"rank_list_movie":[{"key":"榜单","name":"榜单","value":[{"n":"实时热门电影","v":"movie_real_time_hotest"},{"n":"一周口碑电影榜","v":"movie_weekly_best"},{"n":"豆瓣电影Top250","v":"movie_top250"}]}],"rank_list_tv":[{"key":"榜单","name":"榜单","value":[{"n":"实时热门电视","v":"tv_real_time_hotest"},{"n":"华语口碑剧集榜","v":"tv_chinese_best_weekly"},{"n":"全球口碑剧集榜","v":"tv_global_best_weekly"},{"n":"国内口碑综艺榜","v":"show_chinese_best_weekly"},{"n":"国外口碑综艺榜","v":"show_global_best_weekly"}]}]}
|
||||
}
|
||||
header = {
|
||||
"Host": "frodo.douban.com",
|
||||
"Connection": "Keep-Alive",
|
||||
"Referer": "https://servicewechat.com/wx2f9b06c1de1ccfca/84/page-frame.html",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat"
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,136 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
|
||||
import requests
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "斗鱼"
|
||||
def init(self,extend=""):
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"热门游戏": "热门游戏",
|
||||
"主机游戏": "主机游戏",
|
||||
"原创IP": "原创IP"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
|
||||
result['class'] = classes
|
||||
if (filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
url = 'http://live.yj1211.work/api/live/getRecommendByPlatformArea?platform=douyu&size=20&area={0}&page={1}'.format(tid, pg)
|
||||
rsp = self.fetch(url)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']
|
||||
for vod in vodList:
|
||||
aid = (vod['roomId']).strip()
|
||||
title = vod['roomName'].strip()
|
||||
img = vod['roomPic'].strip()
|
||||
remark = (vod['ownerName']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
def detailContent(self,array):
|
||||
aid = array[0]
|
||||
url = "http://live.yj1211.work/api/live/getRoomInfo?platform=douyu&roomId={0}".format(aid)
|
||||
rsp = self.fetch(url)
|
||||
jRoot = json.loads(rsp.text)
|
||||
jo = jRoot['data']
|
||||
title = jo['roomName']
|
||||
pic = jo['roomPic']
|
||||
desc = str(jo['online'])
|
||||
dire = jo['ownerName']
|
||||
typeName = jo['categoryName']
|
||||
remark = jo['categoryName']
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": typeName,
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": remark,
|
||||
"vod_actor": '在线人数:' + desc,
|
||||
"vod_director": dire,
|
||||
"vod_content": ""
|
||||
}
|
||||
playUrl = '原画' + '${0}#'.format(aid)
|
||||
vod['vod_play_from'] = '斗鱼直播'
|
||||
vod['vod_play_url'] = playUrl
|
||||
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def searchContent(self,key,quick):
|
||||
result = {}
|
||||
return result
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
url = 'https://getplayurl.lmteam.repl.co/live?platform=douyu&rid={0}'.format(id)
|
||||
rsp = requests.get(url, allow_redirects=False)
|
||||
if 'Location' in rsp.headers:
|
||||
url = rsp.headers['Location']
|
||||
else:
|
||||
url = ''
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = url
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
def localProxy(self,param):
|
||||
action = {
|
||||
'url':'',
|
||||
'header':'',
|
||||
'param':'',
|
||||
'type':'string',
|
||||
'after':''
|
||||
}
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,297 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
from uuid import uuid4
|
||||
from urllib.parse import quote
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "EMBY"
|
||||
|
||||
def init(self, extend):
|
||||
try:
|
||||
extendDict = json.loads(extend)
|
||||
self.baseUrl = extendDict['server'].strip('/')
|
||||
self.username = extendDict['username']
|
||||
self.password = extendDict['password']
|
||||
self.thread = extendDict['thread'] if 'thread' in extendDict else 0
|
||||
except:
|
||||
self.baseUrl = ''
|
||||
self.username = ''
|
||||
self.password = ''
|
||||
self.thread = 0
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeContent(self, filter):
|
||||
try:
|
||||
embyInfos = self.getAccessToken()
|
||||
except:
|
||||
return {'msg': '获取Emby服务器信息出错'}
|
||||
|
||||
header = self.header.copy()
|
||||
header['Content-Type'] = "application/json; charset=UTF-8"
|
||||
url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Views"
|
||||
params = {
|
||||
"X-Emby-Client": embyInfos['SessionInfo']['Client'],
|
||||
"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
|
||||
"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
|
||||
"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
|
||||
"X-Emby-Token": embyInfos['AccessToken']
|
||||
}
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
typeInfos = r.json()["Items"]
|
||||
classList = []
|
||||
for typeInfo in typeInfos:
|
||||
if "播放列表" in typeInfo['Name'] or '相机' in typeInfo['Name']:
|
||||
continue
|
||||
classList.append({"type_name": typeInfo['Name'], "type_id": typeInfo['Id']})
|
||||
result = {'class': classList}
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
return {}
|
||||
|
||||
def categoryContent(self, cid, page, filter, ext):
|
||||
try:
|
||||
embyInfos = self.getAccessToken()
|
||||
except:
|
||||
return {'list': [], 'msg': '获取Emby服务器信息出错'}
|
||||
|
||||
result = {}
|
||||
page = int(page)
|
||||
header = self.header.copy()
|
||||
header['Content-Type'] = "application/json; charset=UTF-8"
|
||||
url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items"
|
||||
params = {
|
||||
"X-Emby-Client": embyInfos['SessionInfo']['Client'],
|
||||
"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
|
||||
"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
|
||||
"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
|
||||
"X-Emby-Token": embyInfos['AccessToken'],
|
||||
"SortBy": "DateLastContentAdded,SortName",
|
||||
"IncludeItemTypes": "Movie,Series",
|
||||
"SortOrder": "Descending",
|
||||
"ParentId": cid,
|
||||
"Recursive": "true",
|
||||
"Limit": "30",
|
||||
"ImageTypeLimit": 1,
|
||||
"StartIndex": str((page - 1) * 30),
|
||||
"EnableImageTypes": "Primary,Backdrop,Thumb,Banner",
|
||||
"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating,Status,CriticRating,EndDate,Path",
|
||||
"EnableUserData": "true"
|
||||
}
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
videoList = r.json()['Items']
|
||||
videos = []
|
||||
for video in videoList:
|
||||
name = self.cleanText(video['Name'])
|
||||
videos.append({
|
||||
"vod_id": video['Id'],
|
||||
"vod_name": name,
|
||||
"vod_pic": f"{self.baseUrl}/emby/Items/{video['Id']}/Images/Primary?maxWidth=400&tag={video['ImageTags']['Primary']}&quality=90" if 'Primary' in video['ImageTags'] else '',
|
||||
"vod_remarks": video['ProductionYear'] if 'ProductionYear' in video else ''
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = page
|
||||
result['pagecount'] = page + 1 if page * 30 < int(r.json()['TotalRecordCount']) else page
|
||||
result['limit'] = len(videos)
|
||||
result['total'] = int(r.json()['TotalRecordCount']) if "TotalRecordCount" in r.json() else 0
|
||||
return result
|
||||
|
||||
def detailContent(self, did):
|
||||
try:
|
||||
embyInfos = self.getAccessToken()
|
||||
except:
|
||||
return {'list': [], 'msg': '获取Emby服务器信息出错'}
|
||||
|
||||
header = self.header.copy()
|
||||
header['Content-Type'] = "application/json; charset=UTF-8"
|
||||
url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items/{did[0]}"
|
||||
params = {
|
||||
"X-Emby-Client": embyInfos['SessionInfo']['Client'],
|
||||
"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
|
||||
"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
|
||||
"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
|
||||
"X-Emby-Token": embyInfos['AccessToken']
|
||||
}
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
videoInfos = r.json()
|
||||
vod = {
|
||||
"vod_id": did[0],
|
||||
"vod_name": videoInfos['Name'],
|
||||
"vod_pic": f'{self.baseUrl}/emby/Items/{did[0]}/Images/Primary?maxWidth=400&tag={videoInfos["ImageTags"]["Primary"]}&quality=90' if 'Primary' in videoInfos['ImageTags'] else '',
|
||||
"type_name": videoInfos['Genres'][0] if len(videoInfos['Genres']) > 0 else '',
|
||||
"vod_year": videoInfos['ProductionYear'] if 'ProductionYear' in videoInfos else '',
|
||||
"vod_content": videoInfos['Overview'].replace('\xa0', ' ').replace('\n\n', '\n').strip() if 'Overview' in videoInfos else '',
|
||||
"vod_play_from": "EMBY"
|
||||
}
|
||||
playUrl = ''
|
||||
if not videoInfos['IsFolder']:
|
||||
playUrl += f"{videoInfos['Name'].strip()}${videoInfos['Id']}#"
|
||||
else:
|
||||
url = f"{self.baseUrl}/emby/Shows/{did[0]}/Seasons"
|
||||
params.update(
|
||||
{
|
||||
"UserId": embyInfos['User']['Id'],
|
||||
"EnableImages": "true",
|
||||
"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating",
|
||||
"EnableUserData": "true",
|
||||
"EnableTotalRecordCount": "false"
|
||||
}
|
||||
)
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
if r.status_code == 200:
|
||||
playInfos = r.json()['Items']
|
||||
for playInfo in playInfos:
|
||||
url = f"{self.baseUrl}/emby/Shows/{playInfo['Id']}/Episodes"
|
||||
params.update(
|
||||
{
|
||||
"SeasonId": playInfo['Id'],
|
||||
"Fields": "BasicSyncInfo,CanDelete,CommunityRating,PrimaryImageAspectRatio,ProductionYear,Overview"
|
||||
}
|
||||
)
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
videoList = r.json()['Items']
|
||||
for video in videoList:
|
||||
playUrl += f"{playInfo['Name'].replace('#', '-').replace('$', '|').strip()}|{video['Name'].strip()}${video['Id']}#"
|
||||
else:
|
||||
url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items"
|
||||
params = {
|
||||
"ParentId": did[0],
|
||||
"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,CommunityRating,CriticRating",
|
||||
"ImageTypeLimit": "1",
|
||||
"StartIndex": "0",
|
||||
"EnableUserData": "true",
|
||||
"X-Emby-Client": embyInfos['SessionInfo']['Client'],
|
||||
"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
|
||||
"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
|
||||
"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
|
||||
"X-Emby-Token": embyInfos['AccessToken']
|
||||
}
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
videoList = r.json()['Items']
|
||||
for video in videoList:
|
||||
playUrl += f"{video['Name'].replace('#', '-').replace('$', '|').strip()}${video['Id']}#"
|
||||
vod['vod_play_url'] = playUrl.strip('#')
|
||||
result = {'list': [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
return self.searchContentPage(key, quick, '1')
|
||||
|
||||
def searchContentPage(self, keywords, quick, page):
|
||||
try:
|
||||
embyInfos = self.getAccessToken()
|
||||
except:
|
||||
return {'list': [], 'msg': '获取Emby服务器信息出错'}
|
||||
page = int(page)
|
||||
header = self.header.copy()
|
||||
header['Content-Type'] = "application/json; charset=UTF-8"
|
||||
url = f"{self.baseUrl}/emby/Users/{embyInfos['User']['Id']}/Items"
|
||||
params = {
|
||||
"X-Emby-Client": embyInfos['SessionInfo']['Client'],
|
||||
"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
|
||||
"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
|
||||
"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
|
||||
"X-Emby-Token": embyInfos['AccessToken'],
|
||||
"SortBy": "SortName",
|
||||
"SortOrder": "Ascending",
|
||||
"Fields": "BasicSyncInfo,CanDelete,Container,PrimaryImageAspectRatio,ProductionYear,Status,EndDate",
|
||||
"StartIndex": str(((page-1)*50)),
|
||||
"EnableImageTypes": "Primary,Backdrop,Thumb",
|
||||
"ImageTypeLimit": "1",
|
||||
"Recursive": "true",
|
||||
"SearchTerm": keywords,
|
||||
"IncludeItemTypes": "Movie,Series,BoxSet",
|
||||
"GroupProgramsBySeries": "true",
|
||||
"Limit": "50",
|
||||
"EnableTotalRecordCount": "true"
|
||||
}
|
||||
r = requests.get(url, params=params, headers=header, timeout=30)
|
||||
|
||||
videos = []
|
||||
vodList = r.json()['Items']
|
||||
for vod in vodList:
|
||||
sid = vod['Id']
|
||||
name = self.cleanText(vod['Name'])
|
||||
pic = f'{self.baseUrl}/emby/Items/{sid}/Images/Primary?maxWidth=400&tag={vod["ImageTags"]["Primary"]}&quality=90' if 'Primary' in vod["ImageTags"] else ''
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": name,
|
||||
"vod_pic": pic,
|
||||
"vod_remarks": vod['ProductionYear'] if 'ProductionYear' in vod else ''
|
||||
})
|
||||
result = {'list': videos}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, pid, vipFlags):
|
||||
try:
|
||||
embyInfos = self.getAccessToken()
|
||||
except:
|
||||
return {'list': [], 'msg': '获取Emby服务器信息出错'}
|
||||
|
||||
header = self.header.copy()
|
||||
header['Content-Type'] = "application/json; charset=UTF-8"
|
||||
url = f"{self.baseUrl}/emby/Items/{pid}/PlaybackInfo"
|
||||
params = {
|
||||
"UserId": embyInfos['User']['Id'],
|
||||
"IsPlayback": "false",
|
||||
"AutoOpenLiveStream": "false",
|
||||
"StartTimeTicks": 0,
|
||||
"MaxStreamingBitrate": "2147483647",
|
||||
"X-Emby-Client": embyInfos['SessionInfo']['Client'],
|
||||
"X-Emby-Device-Name": embyInfos['SessionInfo']['DeviceName'],
|
||||
"X-Emby-Device-Id": embyInfos['SessionInfo']['DeviceId'],
|
||||
"X-Emby-Client-Version": embyInfos['SessionInfo']['ApplicationVersion'],
|
||||
"X-Emby-Token": embyInfos['AccessToken']
|
||||
}
|
||||
data = "{\"DeviceProfile\":{\"SubtitleProfiles\":[{\"Method\":\"Embed\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"Embed\"},{\"Format\":\"subrip\",\"Method\":\"Embed\"},{\"Format\":\"sub\",\"Method\":\"Embed\"},{\"Method\":\"Embed\",\"Format\":\"pgssub\"},{\"Format\":\"subrip\",\"Method\":\"External\"},{\"Method\":\"External\",\"Format\":\"sub\"},{\"Method\":\"External\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"External\"},{\"Method\":\"External\",\"Format\":\"vtt\"},{\"Method\":\"External\",\"Format\":\"ass\"},{\"Format\":\"ssa\",\"Method\":\"External\"}],\"CodecProfiles\":[{\"Codec\":\"h264\",\"Type\":\"Video\",\"ApplyConditions\":[{\"Property\":\"IsAnamorphic\",\"Value\":\"true\",\"Condition\":\"NotEquals\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"high|main|baseline|constrained baseline\",\"Condition\":\"EqualsAny\",\"Property\":\"VideoProfile\"},{\"IsRequired\":false,\"Value\":\"80\",\"Condition\":\"LessThanEqual\",\"Property\":\"VideoLevel\"},{\"IsRequired\":false,\"Value\":\"true\",\"Condition\":\"NotEquals\",\"Property\":\"IsInterlaced\"}]},{\"Codec\":\"hevc\",\"ApplyConditions\":[{\"Property\":\"IsAnamorphic\",\"Value\":\"true\",\"Condition\":\"NotEquals\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"high|main|main 10\",\"Condition\":\"EqualsAny\",\"Property\":\"VideoProfile\"},{\"Property\":\"VideoLevel\",\"Value\":\"175\",\"Condition\":\"LessThanEqual\",\"IsRequired\":false},{\"IsRequired\":false,\"Value\":\"true\",\"Condition\":\"NotEquals\",\"Property\":\"IsInterlaced\"}],\"Type\":\"Video\"}],\"MaxStreamingBitrate\":40000000,\"TranscodingProfiles\":[{\"Container\":\"ts\",\"AudioCodec\":\"aac,mp3,wav,ac3,eac3,flac,opus\",\"VideoCodec\":\"hevc,h264,mpeg4\",\"BreakOnNonKeyFrames\":true,\"Type\":\"Video\",\"MaxAudioChannels\":\"6\",\"Protocol\":\"hls\",\"Context\":\"Streaming\",\"MinSegments\":2}],\"DirectPlayProfiles\":[{\"Container\":\"mov,mp4,mkv,hls,webm\",\"Type\":\"Video\",\"VideoCodec\":\"h264,hevc,dvhe,dvh1,h264,hevc,hev1,mpeg4,vp9\",\"AudioCodec\":\"aac,mp3,wav,ac3,eac3,flac,truehd,dts,dca,opus,pcm,pcm_s24le\"}],\"ResponseProfiles\":[{\"MimeType\":\"video/mp4\",\"Type\":\"Video\",\"Container\":\"m4v\"}],\"ContainerProfiles\":[],\"MusicStreamingTranscodingBitrate\":40000000,\"MaxStaticBitrate\":40000000}}"
|
||||
r = requests.post(url, params=params, data=data, headers=header, timeout=30)
|
||||
url = self.baseUrl + r.json()['MediaSources'][0]['DirectStreamUrl']
|
||||
if int(self.thread) > 0:
|
||||
try:
|
||||
self.fetch('http://127.0.0.1:7777', timeout=1)
|
||||
except:
|
||||
self.fetch('http://127.0.0.1:9978/go')
|
||||
url = f'http://127.0.0.1:7777/?url={quote(url)}&thread={self.thread}'
|
||||
result = {
|
||||
"url": url,
|
||||
"header": self.header,
|
||||
"parse": 0
|
||||
}
|
||||
return result
|
||||
|
||||
def localProxy(self, params):
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
return '正常进入'
|
||||
|
||||
def getAccessToken(self):
|
||||
key = f"emby_{self.baseUrl}_{self.username}_{self.password }"
|
||||
embyInfos = self.getCache(key)
|
||||
if embyInfos:
|
||||
return embyInfos
|
||||
|
||||
header = self.header.copy()
|
||||
header['Content-Type'] = "application/json; charset=UTF-8"
|
||||
r = requests.post(f"{self.baseUrl}/emby/Users/AuthenticateByName", params={"Username": self.username, "Password": self.password , "Pw": self.password , "X-Emby-Client": "Yamby", "X-Emby-Device-Name": "Yamby", "X-Emby-Device-Id": str(uuid4()), "X-Emby-Client-Version": "1.0.2"}, headers=header, timeout=30)
|
||||
embyInfos = r.json()
|
||||
self.setCache(key, embyInfos)
|
||||
return embyInfos
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
header = {"User-Agent": "Yamby/1.0.2(Android"}
|
||||
@@ -0,0 +1,133 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import json
|
||||
from difflib import SequenceMatcher
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "急救指南"
|
||||
|
||||
def init(self, extend):
|
||||
pass
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeVideoContent(self):
|
||||
return self.categoryContent('FIRSTAID', 1, False, {})
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"急救指南": "FIRSTAID"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
return result
|
||||
|
||||
def categoryContent(self, cid, page, filter, ext):
|
||||
result = {}
|
||||
header = self.header.copy()
|
||||
r = self.fetch('https://m.youlai.cn/jijiu', headers=header)
|
||||
html = self.html(r.text)
|
||||
vodList = html.xpath("//ul[contains(@class,'list-flex-br')]/li")
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
title = vod.xpath(".//div/text()")[0].strip()
|
||||
cid = vod.xpath("./a/@href")[0]
|
||||
videos.append({
|
||||
"vod_id": cid,
|
||||
"vod_name": title,
|
||||
"vod_pic": 'https://api-lmteam.koyeb.app/files/firstaid.png',
|
||||
"vod_remarks": ''
|
||||
})
|
||||
lenvideos = len(videos)
|
||||
result['list'] = videos
|
||||
result['page'] = page
|
||||
result['pagecount'] = page
|
||||
result['limit'] = lenvideos
|
||||
result['total'] = lenvideos
|
||||
return result
|
||||
|
||||
def detailContent(self, did):
|
||||
did = did[0]
|
||||
header = self.header.copy()
|
||||
url = f'https://m.youlai.cn{did}'
|
||||
r = self.fetch(url, headers=header)
|
||||
if '/video/article' in did:
|
||||
data = json.loads(self.regStr(reg='_DATA__ =(.*?});', src=r.text))
|
||||
title = data['videoDetailData']['title']
|
||||
director = f"{data['videoDetailData']['doctor']['name']}|{data['videoDetailData']['doctor']['medical_title']}|{data['videoDetailData']['doctor']['hospital_name']}"
|
||||
content = data['videoDetailData']['description'].strip()
|
||||
playUrl = data['videoDetailData']['media_url']
|
||||
else:
|
||||
html = self.html(r.text)
|
||||
title = html.xpath("//h2[contains(@class,'video-title')]/text()")[0].strip()
|
||||
director = '|'.join(html.xpath("//div[contains(@class,'list-flex')]/span /text()")).strip()
|
||||
content = '\n'.join(html.xpath("//div[@class='img-text-con']//text()[not(parent::span[@class='breakpoint-item'])]")).strip()
|
||||
playUrl = html.xpath("//video[contains(@id,'video')]/source/@src")[0]
|
||||
vod = {
|
||||
"vod_id": did,
|
||||
"vod_name": title,
|
||||
"vod_pic": 'https://img1.imgtp.com/2023/09/19/bydPPaLp.png',
|
||||
"vod_content": content.strip(),
|
||||
"vod_director": director,
|
||||
"vod_play_from": '急救指南',
|
||||
"vod_play_url": title + '$' + playUrl
|
||||
}
|
||||
result = {'list': [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
return self.searchContentPage(key, quick, '1')
|
||||
|
||||
def searchContentPage(self, key, quick, page):
|
||||
header = self.header.copy()
|
||||
url = f'https://m.youlai.cn/kp/videobydise?q={key}&page={page}&keyword={key}'
|
||||
r = self.fetch(url, headers=header, timeout=5)
|
||||
html = self.html(r.text)
|
||||
vodList = html.xpath("//div[contains(@class,'re-li li-video')]")
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
sid = vod.xpath("./a/@href")[0]
|
||||
title = vod.xpath(".//h5/text()")[0].strip()
|
||||
if SequenceMatcher(None, title, key).ratio() < 0.6 and not key in title:
|
||||
continue
|
||||
img = vod.xpath(".//img/@src")[0]
|
||||
if not img.startswith('http'):
|
||||
img = 'https:' + img
|
||||
videos.append({
|
||||
"vod_id": sid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": ''
|
||||
})
|
||||
result = {'list': videos}
|
||||
return result
|
||||
|
||||
def playerContent(self, flag, pid, vipFlags):
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = pid
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
def localProxy(self, param):
|
||||
return [200, "video/MP2T", {}, ""]
|
||||
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36 Edg/116.0.1938.76"
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "剧迷"
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
# https://gimytv.co/
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电影": "movies",
|
||||
"电视剧": "tvseries",
|
||||
"综艺": "tv_show",
|
||||
"动漫": "anime"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name':k,
|
||||
'type_id':cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
rsp = self.fetch("https://gimys.tv/",headers=self.header)
|
||||
root = self.html(rsp.text)
|
||||
aList = root.xpath("//ul[@class='myui-vodlist clearfix']/li/div/a")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = a.xpath("./@title")[0]
|
||||
pic = a.xpath("./@data-original")[0]
|
||||
mark = a.xpath("./span[contains(@class, 'pic-text')]/text()")[0]
|
||||
sid = a.xpath("./@href")[0]
|
||||
sid = self.regStr(sid,"/(\\S+).html")
|
||||
videos.append({
|
||||
"vod_id":sid,
|
||||
"vod_name":name,
|
||||
"vod_pic":pic,
|
||||
"vod_remarks":mark
|
||||
})
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
urlParams = ["", "", "", ""]
|
||||
urlParams[0] = tid
|
||||
urlParams[3] = pg
|
||||
suffix = ''
|
||||
for key in extend:
|
||||
if key == 4:
|
||||
suffix = '/by/'+extend[key]
|
||||
else:
|
||||
urlParams[int(key)] = extend[key]
|
||||
params = '-'.join(urlParams)+suffix
|
||||
# https://gimys.tv/genre/tvseries--2022-/by/hits_month.html
|
||||
url = 'https://gimytv.com/genre/{0}.html'.format(params)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
root = self.html(rsp.text)
|
||||
aList = root.xpath("//ul[@class='myui-vodlist clearfix']/li/div/a")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = a.xpath("./@title")[0]
|
||||
pic = a.xpath("./@data-original")[0]
|
||||
mark = a.xpath("./span[contains(@class, 'pic-text')]/text()")[0]
|
||||
sid = a.xpath("./@href")[0]
|
||||
sid = self.regStr(sid,"/(\\S+).html")
|
||||
videos.append({
|
||||
"vod_id":sid,
|
||||
"vod_name":name,
|
||||
"vod_pic":pic,
|
||||
"vod_remarks":mark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
def detailContent(self,array):
|
||||
tid = array[0]
|
||||
url = 'https://gimys.tv/{0}.html'.format(tid)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
root = self.html(rsp.text)
|
||||
node = root.xpath("//div[@class='container']")[0]
|
||||
title = node.xpath(".//div[@class='myui-content__thumb']/a/@title")[0]
|
||||
pic = node.xpath(".//div[@class='myui-content__thumb']/a/img/@data-original")[0]
|
||||
vod = {
|
||||
"vod_id":tid,
|
||||
"vod_name":title,
|
||||
"vod_pic":pic,
|
||||
"type_name":"",
|
||||
"vod_year":"",
|
||||
"vod_area":"",
|
||||
"vod_remarks":"",
|
||||
"vod_actor":"",
|
||||
"vod_director":"",
|
||||
"vod_content":""
|
||||
}
|
||||
infoArray = node.xpath(".//div[@class='myui-content__detail']/p")
|
||||
for info in infoArray:
|
||||
content = info.xpath('string(.)')
|
||||
if content.startswith('分類'):
|
||||
vod['type_name'] = content
|
||||
# if content.startswith('年份'):
|
||||
# vod['vod_year'] = content
|
||||
# if content.startswith('地区'):
|
||||
# vod['vod_area'] = content
|
||||
if content.startswith('狀態'):
|
||||
vod['vod_remarks'] = content
|
||||
if content.startswith('主演'):
|
||||
vod['vod_actor'] = content
|
||||
if content.startswith('導演'):
|
||||
vod['vod_director'] = content
|
||||
# if content.startswith('剧情'):
|
||||
# vod['vod_content'] = content
|
||||
vod['vod_content'] = node.xpath(".//div[contains(@class,'col-pd')]/p/text()")[0]
|
||||
|
||||
vod_play_from = '$$$'
|
||||
playFrom = []
|
||||
vodHeader = root.xpath(".//div[@class='myui-panel_hd']/div/h3/text()[2]")
|
||||
for v in vodHeader:
|
||||
playFrom.append(v.strip())
|
||||
vod_play_from = vod_play_from.join(playFrom)
|
||||
|
||||
vod_play_url = '$$$'
|
||||
playList = []
|
||||
vodList = root.xpath(".//ul[contains(@class,'myui-content__list')]")
|
||||
for vl in vodList:
|
||||
vodItems = []
|
||||
aList = vl.xpath('./li/a')
|
||||
for tA in aList:
|
||||
href = tA.xpath('./@href')[0]
|
||||
name = tA.xpath('./text()')[0]
|
||||
tId = self.regStr(href,'/(\\S+).html')
|
||||
vodItems.append(name + "$" + tId)
|
||||
joinStr = '#'
|
||||
joinStr = joinStr.join(vodItems)
|
||||
playList.append(joinStr)
|
||||
vod_play_url = vod_play_url.join(playList)
|
||||
|
||||
vod['vod_play_from'] = vod_play_from
|
||||
vod['vod_play_url'] = vod_play_url
|
||||
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def searchContent(self,key,quick):
|
||||
url = "https://gimys.tv/search/-------------.html?wd={0}".format(key)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
root = self.html(rsp.text)
|
||||
aList = root.xpath("//ul[contains(@class,'myui-vodlist__media')]/li")
|
||||
videos = []
|
||||
for a in aList:
|
||||
name = a.xpath(".//a/@title")[0]
|
||||
pic = a.xpath(".//a/@data-original")[0]
|
||||
mark = a.xpath(".//span[contains(@class, 'pic-text')]/text()")[0]
|
||||
sid = a.xpath(".//a/@href")[0]
|
||||
sid = self.regStr(sid,"/(\\S+).html")
|
||||
videos.append({
|
||||
"vod_id":sid,
|
||||
"vod_name":name,
|
||||
"vod_pic":pic,
|
||||
"vod_remarks":mark
|
||||
})
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
url = 'https://gimys.tv/{0}.html'.format(id)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
root = self.html(rsp.text)
|
||||
scripts = root.xpath("//script/text()")
|
||||
jo = {}
|
||||
for script in scripts:
|
||||
if(script.startswith("var player_")):
|
||||
target = script[script.index('{'):]
|
||||
jo = json.loads(target)
|
||||
break;
|
||||
url = jo['url']
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = url
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
cookie = {}
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {"movies":[{"key":0,"name":"分类","value":[{"n":"全部","v":""},{"n":"劇情片","v":"drama"},{"n":"動作片","v":"action"},{"n":"科幻片","v":"scifi"},{"n":"喜劇片","v":"comedymovie"},{"n":"愛情片","v":"romance"},{"n":"戰爭片","v":"war"},{"n":"恐怖片","v":"horror"},{"n":"動畫電影","v":"animation"}]},{"key":1,"name":"地区","value":[{"n":"全部","v":""},{"n":"美國","v":"美國"},{"n":"歐美","v":"歐美"},{"n":"大陸","v":"大陸"},{"n":"中國大陸","v":"中國大陸"},{"n":"韓國","v":"韓國"},{"n":"香港","v":"香港"},{"n":"日本","v":"日本"},{"n":"英國","v":"英國"}]},{"key":2,"name":"年份","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"}]},{"key":4,"name":"排序","value":[{"n":"按更新","v":"time"},{"n":"周人气","v":"hits_week"},{"n":"月人气","v":"hits_month"}]}],"tvseries":[{"key":0,"name":"分类","value":[{"n":"全部","v":""},{"n":"陸劇","v":"cn"},{"n":"韓劇","v":"kr"},{"n":"美劇","v":"us"},{"n":"日劇","v":"jp"},{"n":"台劇","v":"tw"},{"n":"港劇","v":"hks"},{"n":"海外劇","v":"ot"},{"n":"紀錄片","v":"documentary"}]},{"key":2,"name":"年份","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"}]},{"key":4,"name":"排序","value":[{"n":"按更新","v":"time"},{"n":"周人气","v":"hits_week"},{"n":"月人气","v":"hits_month"}]}],"anime":[{"key":1,"name":"地区","value":[{"n":"全部","v":""},{"n":"日本","v":"日本"},{"n":"美國","v":"美國"},{"n":"歐美","v":"歐美"},{"n":"大陸","v":"大陸"},{"n":"臺灣","v":"臺灣"},{"n":"香港","v":"香港"}]},{"key":2,"name":"年份","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"}]},{"key":4,"name":"排序","value":[{"n":"按更新","v":"time"},{"n":"周人气","v":"hits_week"},{"n":"月人气","v":"hits_month"}]}],"tv_show":[{"key":0,"name":"分类","value":[{"n":"全部","v":""},{"n":"纪录片","v":"28"}]},{"key":1,"name":"地区","value":[{"n":"全部","v":""},{"n":"大陸","v":"大陸"},{"n":"中國大陸","v":"中國大陸"},{"n":"韓國","v":"韓國"},{"n":"臺灣","v":"臺灣"},{"n":"美國","v":"美國"},{"n":"歐美","v":"歐美"},{"n":"日本","v":"日本"},{"n":"香港","v":"香港"}]},{"key":2,"name":"年份","value":[{"n":"全部","v":""},{"n":"2022","v":"2022"},{"n":"2021","v":"2021"},{"n":"2020","v":"2020"},{"n":"2019","v":"2019"},{"n":"2018","v":"2018"},{"n":"2017","v":"2017"},{"n":"2016","v":"2016"},{"n":"2015","v":"2015"},{"n":"2014","v":"2014"},{"n":"2013","v":"2013"},{"n":"2012","v":"2012"}]},{"key":4,"name":"排序","value":[{"n":"按更新","v":"time"},{"n":"周人气","v":"hits_week"},{"n":"月人气","v":"hits_month"}]}]}
|
||||
}
|
||||
header = {
|
||||
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36 Edg/104.0.1293.47'
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,166 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
import html
|
||||
import base64
|
||||
import hashlib
|
||||
import urllib.parse
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "虎牙"
|
||||
def init(self,extend=""):
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"音乐": "音乐",
|
||||
"一起看": "一起看",
|
||||
"三国杀": "三国杀",
|
||||
"网游竞技": "网游竞技"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
|
||||
result['class'] = classes
|
||||
if (filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
url = 'http://live.yj1211.work/api/live/getRecommendByPlatformArea?platform=huya&size=20&area={0}&page={1}'.format(tid, pg)
|
||||
rsp = self.fetch(url)
|
||||
content = rsp.text
|
||||
jo = json.loads(content)
|
||||
videos = []
|
||||
vodList = jo['data']
|
||||
for vod in vodList:
|
||||
aid = (vod['roomId']).strip()
|
||||
title = vod['roomName'].strip()
|
||||
img = vod['roomPic'].strip()
|
||||
remark = (vod['ownerName']).strip()
|
||||
videos.append({
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self,array):
|
||||
aid = array[0]
|
||||
url = 'https://www.huya.com/' + aid
|
||||
header = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36'
|
||||
}
|
||||
rsp = self.fetch(url, headers=header)
|
||||
streamInfo = re.findall(r'stream: ([\s\S]*?)\n', rsp.text)
|
||||
if (len(streamInfo) > 0):
|
||||
liveData = json.loads(streamInfo[0])
|
||||
else:
|
||||
streamInfo = re.findall(r'"stream": "([\s\S]*?)"', rsp.text)
|
||||
if (len(streamInfo) > 0):
|
||||
liveDataBase64 = streamInfo[0]
|
||||
liveData = json.loads(str(base64.b64decode(liveDataBase64), 'utf-8'))
|
||||
streamInfoList = liveData['data'][0]['gameStreamInfoList']
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": liveData['data'][0]['gameLiveInfo']['roomName'],
|
||||
"vod_pic": liveData['data'][0]['gameLiveInfo']['screenshot'],
|
||||
"type_name": liveData['data'][0]['gameLiveInfo']['gameFullName'],
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": "",
|
||||
"vod_actor": "",
|
||||
"vod_director": "",
|
||||
"vod_content": ""
|
||||
}
|
||||
playUrl = ''
|
||||
playFrom = ''
|
||||
for streamInfo in streamInfoList:
|
||||
hls_url = streamInfo['sHlsUrl'] + '/' + streamInfo['sStreamName'] + '.' + streamInfo['sHlsUrlSuffix']
|
||||
srcAntiCode = html.unescape(streamInfo['sHlsAntiCode'])
|
||||
c = srcAntiCode.split('&')
|
||||
c = [i for i in c if i != '']
|
||||
n = {i.split('=')[0]: i.split('=')[1] for i in c}
|
||||
fm = urllib.parse.unquote(n['fm'])
|
||||
u = base64.b64decode(fm).decode('utf-8')
|
||||
hash_prefix = u.split('_')[0]
|
||||
ctype = n.get('ctype', '')
|
||||
txyp = n.get('txyp', '')
|
||||
fs = n.get('fs', '')
|
||||
t = n.get('t', '')
|
||||
seqid = str(int(time.time() * 1e3 + 1463993859134))
|
||||
wsTime = hex(int(time.time()) + 3600).replace('0x', '')
|
||||
hash = hashlib.md5('_'.join([hash_prefix, '1463993859134', streamInfo['sStreamName'], hashlib.md5((seqid + '|' + ctype + '|' + t).encode('utf-8')).hexdigest(), wsTime]).encode('utf-8')).hexdigest()
|
||||
ratio = ''
|
||||
purl = "{}?wsSecret={}&wsTime={}&seqid={}&ctype={}&ver=1&txyp={}&fs={}&ratio={}&u={}&t={}&sv=2107230339".format(hls_url, hash, wsTime, seqid, ctype, txyp, fs, ratio, '1463993859134', t)
|
||||
playUrl = playUrl + '{}${}#'.format(streamInfo['sCdnType'], purl)
|
||||
vod['vod_play_from'] = '虎牙直播'
|
||||
vod['vod_play_url'] = playUrl
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def searchContent(self,key,quick):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
url = id
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = url
|
||||
result["header"] = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
result["contentType"] = ''
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
def localProxy(self,param):
|
||||
action = {
|
||||
'url':'',
|
||||
'header':'',
|
||||
'param':'',
|
||||
'type':'string',
|
||||
'after':''
|
||||
}
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,179 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import math
|
||||
import json
|
||||
import base64
|
||||
import requests
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "爱看影视"
|
||||
def init(self,extend=""):
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电影": "1",
|
||||
"剧集": "2",
|
||||
"综艺": "3",
|
||||
"动漫": "4",
|
||||
"美剧": "16",
|
||||
"日韩剧": "15",
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
|
||||
result['class'] = classes
|
||||
if (filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def detailContent(self,array):
|
||||
aid = array[0]
|
||||
url = 'https://ikanys.tv/voddetail/{0}/'.format(aid)
|
||||
rsp = self.fetch(url)
|
||||
html = self.html(rsp.text)
|
||||
node = html.xpath("//div[@class='box-width flex between rel']")[0]
|
||||
title = html.xpath("//h3[@class='slide-info-title hide']/text()")[0]
|
||||
pic = html.xpath("//a[@class='detail-pic lazy mask-1']/@data-original")[0]
|
||||
vod = {
|
||||
"vod_id": aid,
|
||||
"vod_name": title,
|
||||
"vod_pic": pic,
|
||||
"type_name": '',
|
||||
"vod_year": '',
|
||||
"vod_area": '',
|
||||
"vod_remarks": '',
|
||||
"vod_actor": '',
|
||||
"vod_director": '',
|
||||
"vod_content": ''
|
||||
}
|
||||
playFrom = ''
|
||||
playfromList = html.xpath("//div[@class='swiper-wrapper']/a")
|
||||
for pL in playfromList:
|
||||
pL = pL.xpath("./text()")[0].strip()
|
||||
playFrom = playFrom + '$$$' + pL
|
||||
urlList = html.xpath("//div[contains(@class,'anthology-list-box none')]")
|
||||
playUrl = ''
|
||||
for uL in urlList:
|
||||
for playurl in uL.xpath(".//li"):
|
||||
purl = self.regStr(reg=r'/vodplay/(.*?)/', src=playurl.xpath("./a/@href")[0])
|
||||
name = playurl.xpath("./a/text()")[0]
|
||||
playUrl = playUrl + '{}${}#'.format(name, purl)
|
||||
playUrl = playUrl + '$$$'
|
||||
vod['vod_play_from'] = playFrom.strip('$$$')
|
||||
vod['vod_play_url'] = playUrl.strip('$$$')
|
||||
|
||||
result = {
|
||||
'list': [
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def verifyCode(self,tag):
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
try:
|
||||
session = requests.session()
|
||||
r = session.post('https://ddddocr.lm317379829.repl.co', json={'url': 'https://ikanys.tv/index.php/verify/index.html', 'comp': 'digit'})
|
||||
jo = r.json()
|
||||
if jo['code'] == 1:
|
||||
code = jo['result']
|
||||
session.cookies.update(jo['cookies'])
|
||||
else:
|
||||
return False, None
|
||||
res = session.post(url="https://ikanys.tv/index.php/ajax/verify_check?type={}&verify={}".format(tag, code), headers=header, timeout=5).json()
|
||||
if res["msg"] == "ok":
|
||||
return True, session
|
||||
except:
|
||||
pass
|
||||
return False, None
|
||||
|
||||
def searchContent(self,key,quick):
|
||||
result = {}
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
|
||||
}
|
||||
url = 'https://ikanys.tv/vodsearch/-------------/?wd={0}'.format(key)
|
||||
_, session = self.verifyCode('search')
|
||||
rsp = session.get(url, headers=header)
|
||||
root = self.html(rsp.text)
|
||||
vodList = root.xpath("//div[@class='search-box flex rel']")
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
name = vod.xpath(".//div[@class='thumb-txt cor4 hide']/text()")[0]
|
||||
pic = vod.xpath(".//div[@class='lazy gen-movie-img mask-1']/@data-original")[0]
|
||||
mark = vod.xpath(".//span[@class='public-list-prb hide ft2']/text()")[0]
|
||||
sid = vod.xpath(".//a[@class='public-list-exp']/@href")[0]
|
||||
sid = self.regStr(sid,"/voddetail/(\\S+)/")
|
||||
videos.append({
|
||||
"vod_id":sid,
|
||||
"vod_name":name,
|
||||
"vod_pic":pic,
|
||||
"vod_remarks":mark
|
||||
})
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
|
||||
"Referer": "https://ikanys.tv/"
|
||||
}
|
||||
result = {}
|
||||
url = 'https://ikanys.tv/vodplay/{0}/'.format(id)
|
||||
rsp = self.fetch(url, headers=header)
|
||||
info = json.loads(self.regStr(reg=r'var player_data=(.*?)</script>', src=self.cleanText(rsp.text)))
|
||||
parse = 0
|
||||
purl = base64.b64decode(info['url'].encode())[14:-8].decode()
|
||||
if purl.startswith('http'):
|
||||
purl = purl
|
||||
else:
|
||||
parse = 1
|
||||
purl = url
|
||||
result["parse"] = parse
|
||||
result["playUrl"] = ''
|
||||
result["url"] = purl
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
def localProxy(self,param):
|
||||
action = {
|
||||
'url':'',
|
||||
'header':'',
|
||||
'param':'',
|
||||
'type':'string',
|
||||
'after':''
|
||||
}
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,236 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import hashlib
|
||||
import requests
|
||||
from urllib.parse import urlparse
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "77"
|
||||
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
url = 'http://api.tyun77.cn/api.php/provide/filter'
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
jo = json.loads(rsp.text)
|
||||
classes = []
|
||||
jData = jo['data']
|
||||
for cKey in jData.keys():
|
||||
classes.append({
|
||||
'type_name':jData[cKey][0]['cat'].replace('电视剧', '剧集'),
|
||||
'type_id':cKey
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
url = 'http://api.tyun77.cn/api.php/provide/homeBlock?type_id=0'
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
jo = json.loads(rsp.text)
|
||||
blockList = jo['data']['blocks']
|
||||
videos = []
|
||||
for block in blockList:
|
||||
vodList = block['contents']
|
||||
for vod in vodList:
|
||||
videos.append({
|
||||
"vod_id":vod['id'],
|
||||
"vod_name":vod['title'],
|
||||
"vod_pic":vod['videoCover'],
|
||||
"vod_remarks":vod['msg']
|
||||
})
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
ts = int(time.time())
|
||||
if 'type_id' not in extend.keys():
|
||||
extend['type_id'] = tid
|
||||
extend['pagenum'] = pg
|
||||
extend = {
|
||||
'pcode': '010110002',
|
||||
'version': '2.1.6',
|
||||
'devid': hashlib.md5(str(time.time()).encode()).hexdigest(),
|
||||
'package': 'com.sevenVideo.app.android',
|
||||
'sys': 'android',
|
||||
'sysver': 13,
|
||||
'brand': 'Redmi',
|
||||
'model': 'M2104K10AC',
|
||||
'pagesize': 24
|
||||
}
|
||||
url = 'https://api.tyun77.cn/api.php/provide/searchFilter'
|
||||
header = self.header.copy()
|
||||
header['t'] = str(ts)
|
||||
header['TK'] = self.get_tk(url, extend, ts)
|
||||
rsp = requests.get(url, params=extend, headers=header, timeout=5)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] == 1004:
|
||||
rsp = requests.get('http://api.tyun77.cn/api.php/provide/getDomain', params=extend, headers=header, timeout=5)
|
||||
if rsp.json()['code'] != 1:
|
||||
rsp = requests.get(url, params=extend, headers=header, timeout=5)
|
||||
jo = json.loads(rsp.text)
|
||||
else:
|
||||
return {}
|
||||
vodList = jo['data']['result']
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
videos.append({
|
||||
"vod_id":vod['id'],
|
||||
"vod_name":vod['title'],
|
||||
"vod_pic":vod['videoCover'],
|
||||
"vod_remarks":vod['msg']
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self,array):
|
||||
tid = array[0]
|
||||
ts = int(time.time())
|
||||
params = {
|
||||
'pcode': '010110002',
|
||||
'version': '2.1.6',
|
||||
'devid': hashlib.md5(str(time.time()).encode()).hexdigest(),
|
||||
'package': 'com.sevenVideo.app.android',
|
||||
'sys': 'android',
|
||||
'sysver': 13,
|
||||
'brand': 'Redmi',
|
||||
'model': 'M2104K10AC'
|
||||
}
|
||||
params['ids'] = tid
|
||||
url = 'http://api.tyun77.cn/api.php/provide/videoDetail'
|
||||
header = self.header.copy()
|
||||
header['t'] = str(ts)
|
||||
header['TK'] = self.get_tk(url, params, ts)
|
||||
rsp = requests.get(url, headers=header, params=params, timeout=5)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['code'] != 1:
|
||||
rsp = requests.get('http://api.tyun77.cn/api.php/provide/getDomain', params=params, headers=header, timeout=5)
|
||||
if rsp.json()['code'] == 1:
|
||||
rsp = requests.get(url, params=params, headers=header, timeout=5)
|
||||
jo = json.loads(rsp.text)
|
||||
else:
|
||||
return {}
|
||||
node = jo['data']
|
||||
vod = {
|
||||
"vod_id":node['id'],
|
||||
"vod_name":node['videoName'],
|
||||
"vod_pic":node['videoCover'],
|
||||
"type_name":node['subCategory'],
|
||||
"vod_year":node['year'],
|
||||
"vod_area":node['area'],
|
||||
"vod_remarks":node['msg'],
|
||||
"vod_actor":node['actor'],
|
||||
"vod_director":node['director'],
|
||||
"vod_content":node['brief'].strip()
|
||||
}
|
||||
listUrl = 'http://api.tyun77.cn/api.php/provide/videoPlaylist'
|
||||
header['TK'] = self.get_tk(listUrl, params, ts)
|
||||
listRsp = requests.get(listUrl, headers=header, params=params, timeout=5)
|
||||
listJo = json.loads(listRsp.text)
|
||||
playMap = {}
|
||||
episodes = listJo['data']['episodes']
|
||||
for ep in episodes:
|
||||
playurls = ep['playurls']
|
||||
for playurl in playurls:
|
||||
source = playurl['playfrom']
|
||||
if source not in playMap.keys():
|
||||
playMap[source] = []
|
||||
playMap[source].append(playurl['title'].strip() + '$' + playurl['playurl'])
|
||||
|
||||
playFrom = []
|
||||
playList = []
|
||||
for key in playMap.keys():
|
||||
playFrom.append(key)
|
||||
playList.append('#'.join(playMap[key]))
|
||||
|
||||
vod_play_from = '$$$'
|
||||
vod_play_from = vod_play_from.join(playFrom)
|
||||
vod_play_url = '$$$'
|
||||
vod_play_url = vod_play_url.join(playList)
|
||||
vod['vod_play_from'] = vod_play_from
|
||||
vod['vod_play_url'] = vod_play_url
|
||||
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self,key,quick):
|
||||
url = 'http://api.tyun77.cn/api.php/provide/searchVideo?searchName={0}'.format(key)
|
||||
rsp = self.fetch(url,headers=self.header)
|
||||
jo = json.loads(rsp.text)
|
||||
vodList = jo['data']
|
||||
videos = []
|
||||
for vod in vodList:
|
||||
videos.append({
|
||||
"vod_id":vod['id'],
|
||||
"vod_name":vod['videoName'],
|
||||
"vod_pic":vod['videoCover'],
|
||||
"vod_remarks":vod['msg']
|
||||
})
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {
|
||||
'User-Agent': 'okhttp/3.12.0'
|
||||
}
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
result = {
|
||||
'parse':0,
|
||||
'jx':0,
|
||||
'playUrl':'',
|
||||
'url':id,
|
||||
'header':''
|
||||
}
|
||||
if flag != 'ppayun':
|
||||
result['parse'] = 1
|
||||
result['jx'] = 1
|
||||
return result
|
||||
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def get_tk(self, url, params, ts):
|
||||
keys = []
|
||||
for key in params:
|
||||
keys.append(key)
|
||||
keys.sort()
|
||||
src = urlparse(url).path
|
||||
for key in keys:
|
||||
src += str(params[key])
|
||||
src += str(ts)
|
||||
src += 'XSpeUFjJ'
|
||||
return hashlib.md5(src.encode()).hexdigest()
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,356 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import hashlib
|
||||
from base64 import b64decode
|
||||
from difflib import SequenceMatcher
|
||||
from urllib.parse import quote, unquote
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "直播"
|
||||
|
||||
def init(self, extend):
|
||||
try:
|
||||
self.extendDict = json.loads(extend)
|
||||
except:
|
||||
self.extendDict = {}
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
pass
|
||||
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {'list': []}
|
||||
return result
|
||||
|
||||
def homeContent(self, filter):
|
||||
result = {}
|
||||
try:
|
||||
url = self.extendDict['url']
|
||||
data = self.fetch(url, headers=self.header, timeout=5).json()
|
||||
result['class'] = data['classes']
|
||||
if filter:
|
||||
result['filters'] = data['filter']
|
||||
except:
|
||||
result['class'] = [{"type_id": 'douyu', "type_name": "斗鱼"}]
|
||||
result['filters'] = {'douyu': {'key': '斗鱼', 'name': '斗鱼', "value": [{"n": "一起看", "v": "208"}]}}
|
||||
return result
|
||||
|
||||
def categoryContent(self, cid, page, filter, ext):
|
||||
result = {}
|
||||
videos = []
|
||||
header = self.header.copy()
|
||||
if cid == 'bilibili':
|
||||
if 'B站' in ext:
|
||||
tid = ext['B站']
|
||||
else:
|
||||
try:
|
||||
r = self.fetch(json.loads(self.extendDict)['url'], headers=header, timeout=5)
|
||||
tid = r.json()['filter'][cid][0]['value'][0]['v']
|
||||
except:
|
||||
tid = '1'
|
||||
url = f'https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id={tid}&page={page}'
|
||||
data = self.fetch(url, headers=header, timeout=5).json()
|
||||
vodList = data['data']['list']
|
||||
append = 'bilibili'
|
||||
imgnm = 'cover'
|
||||
vidnm = 'roomid'
|
||||
titlenm = 'title'
|
||||
remarknm = 'uname'
|
||||
if data['data']['has_more'] == 1:
|
||||
pagecount = page + 1
|
||||
else:
|
||||
pagecount = page
|
||||
elif cid == 'douyu':
|
||||
if '斗鱼' in ext:
|
||||
tid = ext['斗鱼']
|
||||
else:
|
||||
try:
|
||||
r = self.fetch(json.loads(self.extend)['url'], headers=header)
|
||||
tid = r.json()['filter'][cid][0]['value'][0]['v']
|
||||
except:
|
||||
tid = '208'
|
||||
url = f'https://www.douyu.com/gapi/rkc/directory/mixList/2_{tid}/{page}'
|
||||
r = self.fetch(url, headers=header, timeout=5)
|
||||
data = r.json()
|
||||
vodList = data['data']['rl']
|
||||
pagecount = data['data']['pgcnt']
|
||||
append = 'douyu'
|
||||
imgnm = 'rs1'
|
||||
vidnm = 'rid'
|
||||
titlenm = 'rn'
|
||||
remarknm = 'nn'
|
||||
elif cid == 'huya':
|
||||
if '虎牙' in ext:
|
||||
tid = ext['虎牙']
|
||||
else:
|
||||
try:
|
||||
r = self.fetch(json.loads(self.extend)['url'], headers=header)
|
||||
tid = r.json()['filter'][cid][0]['value'][0]['v']
|
||||
except:
|
||||
tid = '2135'
|
||||
header['Referer'] = 'https://www.huya.com/'
|
||||
url = f'https://www.huya.com/cache.php?m=LiveList&do=getLiveListByPage&gameId={tid}&tagAll=0&callback=getLiveListJsonpCallback&page={page}'
|
||||
r = self.fetch(url, headers=header, timeout=5)
|
||||
data = json.loads(self.regStr(reg="getLiveListJsonpCallback\((.*)\)", src=r.text))
|
||||
vodList = data['data']['datas']
|
||||
pagecount = data['data']['totalPage']
|
||||
append = 'huya'
|
||||
imgnm = 'screenshot'
|
||||
vidnm = 'profileRoom'
|
||||
titlenm = 'introduction'
|
||||
remarknm = 'nick'
|
||||
else:
|
||||
vodList = []
|
||||
pagecount = page
|
||||
append = ''
|
||||
imgnm = ''
|
||||
vidnm = ''
|
||||
titlenm = ''
|
||||
remarknm = ''
|
||||
for vod in vodList:
|
||||
img = vod[imgnm]
|
||||
vid = vod[vidnm]
|
||||
title = vod[titlenm]
|
||||
remark = vod[remarknm]
|
||||
videos.append({
|
||||
"vod_id": title + '###' + append + '###' + str(vid),
|
||||
"vod_name": title,
|
||||
"vod_pic": img,
|
||||
"vod_remarks": remark
|
||||
})
|
||||
lenvodList = len(vodList)
|
||||
result['list'] = videos
|
||||
result['page'] = page
|
||||
result['pagecount'] = pagecount
|
||||
result['limit'] = lenvodList
|
||||
result['total'] = lenvodList
|
||||
return result
|
||||
|
||||
def detailContent(self, did):
|
||||
did = did[0]
|
||||
header = self.header.copy()
|
||||
didList = did.split('###')
|
||||
title = didList[0]
|
||||
if didList[1] == 'bilibili':
|
||||
url = f'https://api.live.bilibili.com/room/v1/Room/playUrl?cid={didList[2]}&qn=20000&platform=h5'
|
||||
data = self.fetch(url, headers=header).json()
|
||||
platformList = ['B站直播']
|
||||
playurlList = [data['data']['quality_description'][0]['desc'] + '$' + data['data']['durl'][0]['url']]
|
||||
elif didList[1] == 'douyu':
|
||||
params = quote(json.dumps({"rid": didList[2]}))
|
||||
url = f'https://api-lmteam.koyeb.app/live/douyu?params={params}'
|
||||
platformList = ['斗鱼直播']
|
||||
playurlList = [f'斗鱼直播${url}']
|
||||
elif didList[1] == 'huya':
|
||||
import html
|
||||
header['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
url = 'https://www.huya.com/' + didList[2]
|
||||
r = self.fetch(url, headers=header, timeout=5)
|
||||
try:
|
||||
data = json.loads(self.regStr(reg='stream: ([\s\S]*?)\n', src=r.text))
|
||||
except:
|
||||
data = json.loads(b64decode(self.regStr(reg='"stream": "([\s\S]*?)"', src=r.text)).decode())
|
||||
platformList = []
|
||||
playurlList = []
|
||||
i = 1
|
||||
for pL in data['data'][0]['gameStreamInfoList']:
|
||||
platformList.append('线路{}'.format(str(i)))
|
||||
baseurl = pL['sHlsUrl'] + '/' + pL['sStreamName'] + '.' + pL['sHlsUrlSuffix']
|
||||
srcAntiCode = html.unescape(pL['sHlsAntiCode'])
|
||||
c = srcAntiCode.split('&')
|
||||
c = [i for i in c if i != '']
|
||||
n = {i.split('=')[0]: i.split('=')[1] for i in c}
|
||||
fm = unquote(n['fm'])
|
||||
u = b64decode(fm).decode('utf-8')
|
||||
hash_prefix = u.split('_')[0]
|
||||
ctype = n.get('ctype', '')
|
||||
txyp = n.get('txyp', '')
|
||||
fs = n.get('fs', '')
|
||||
t = n.get('t', '')
|
||||
seqid = str(int(time.time() * 1e3 + 1463993859134))
|
||||
wsTime = hex(int(time.time()) + 3600).replace('0x', '')
|
||||
hash = hashlib.md5('_'.join([hash_prefix, '1463993859134', pL['sStreamName'], hashlib.md5((seqid + '|' + ctype + '|' + t).encode('utf-8')).hexdigest(), wsTime]).encode('utf-8')).hexdigest()
|
||||
ratio = ''
|
||||
purl = "{}?wsSecret={}&wsTime={}&seqid={}&ctype={}&ver=1&txyp={}&fs={}&ratio={}&u={}&t={}&sv=2107230339".format(baseurl, hash, wsTime, seqid, ctype, txyp, fs, ratio, '1463993859134', t)
|
||||
playurlList.append('直播$' + purl)
|
||||
i += 1
|
||||
else:
|
||||
playurlList = []
|
||||
platformList = []
|
||||
vod = {
|
||||
"vod_id": didList[2],
|
||||
"vod_name": title,
|
||||
}
|
||||
vod['vod_play_from'] = '$$$'.join(platformList)
|
||||
vod['vod_play_url'] = '$$$'.join(playurlList)
|
||||
result = {'list': [vod]}
|
||||
return result
|
||||
|
||||
def searchContent(self, key, quick):
|
||||
return self.searchContentPage(key, False, '1')
|
||||
|
||||
def searchContentPage(self, key, quick, page):
|
||||
items = []
|
||||
page = int(page)
|
||||
keyword = key
|
||||
if page == 1:
|
||||
siteList = ['bb', 'dy', 'hy']
|
||||
else:
|
||||
siteList = self.getCache('livesiteList_{}_{}'.format(keyword, page))
|
||||
self.delCache('livesiteList_{}_{}'.format(keyword, page))
|
||||
if not siteList:
|
||||
return {'list': items}
|
||||
contents = []
|
||||
with ThreadPoolExecutor(max_workers=3) as executor:
|
||||
searchList = []
|
||||
try:
|
||||
for site in siteList:
|
||||
tag = site
|
||||
api = ''
|
||||
future = executor.submit(self.runSearch, keyword, tag, page, api)
|
||||
searchList.append(future)
|
||||
for future in as_completed(searchList, timeout=30):
|
||||
contents.append(future.result())
|
||||
except:
|
||||
executor.shutdown(wait=False)
|
||||
nextpageList = []
|
||||
for content in contents:
|
||||
if content is None:
|
||||
continue
|
||||
key = list(content.keys())[0]
|
||||
infos = content[key]
|
||||
items = items + content[key][0]
|
||||
nextpageList.append(infos[1])
|
||||
if not infos[1]:
|
||||
siteList.remove(key)
|
||||
self.setCache('livesiteList_{}_{}'.format(keyword, page+1), siteList)
|
||||
result = {
|
||||
'list': items
|
||||
}
|
||||
return result
|
||||
|
||||
def runSearch(self, key, tag, page, api):
|
||||
try:
|
||||
defname = 'self.search' + tag
|
||||
result = eval(defname)(key, tag, page, api)
|
||||
return result
|
||||
except:
|
||||
pass
|
||||
|
||||
def searchbb(self, key, tag, pg, api):
|
||||
items = []
|
||||
header = self.header.copy()
|
||||
header['Cookie'] = 'buvid3=0'
|
||||
url = f'https://api.bilibili.com/x/web-interface/search/type?page={pg}&page_size=10&order=online&search_type=live_user&keyword={key}'
|
||||
data = self.fetch(url, headers=header).json()
|
||||
vList = data['data']['result']
|
||||
for video in vList:
|
||||
if video['live_status'] == 0:
|
||||
continue
|
||||
title = self.removeHtmlTags(video['uname'])
|
||||
if SequenceMatcher(None, title, key).ratio() < 0.6 and key not in title:
|
||||
continue
|
||||
items.append({
|
||||
'vod_id': '{}###bilibili###{}'.format(title, video['roomid']),
|
||||
'vod_name': title,
|
||||
'vod_pic': 'https:' + video['uface'],
|
||||
"vod_remarks": 'B站直播'
|
||||
})
|
||||
return {tag: [items, pg * 10 < len(items)]}
|
||||
|
||||
def searchdy(self, key, tag, pg, api):
|
||||
items = []
|
||||
header = self.header.copy()
|
||||
url = f'https://www.douyu.com/japi/search/api/searchUser?kw={key}&page={pg}&pageSize=10&filterType=1'
|
||||
data = self.fetch(url, headers=header, timeout=5).json()
|
||||
vList = data['data']['relateUser']
|
||||
for video in vList:
|
||||
if video['anchorInfo']['isLive'] != 1:
|
||||
continue
|
||||
title = video['anchorInfo']['nickName']
|
||||
if SequenceMatcher(None, title, key).ratio() < 0.6 and key not in title:
|
||||
continue
|
||||
items.append({
|
||||
'vod_id': '{}###douyin###{}'.format(title, video['anchorInfo']['rid']),
|
||||
'vod_name': title,
|
||||
'vod_pic': video['anchorInfo']['roomSrc'],
|
||||
"vod_remarks": '斗鱼直播'
|
||||
})
|
||||
return {tag: [items, pg * 10 < len(items)]}
|
||||
|
||||
def searchhy(self, key, tag, pg, api):
|
||||
items = []
|
||||
header = self.header.copy()
|
||||
header['Cookie'] = 'buvid3=0'
|
||||
start = str((pg-1)*40)
|
||||
url = f'https://search.cdn.huya.com/?m=Search&do=getSearchContent&typ=-5&livestate=1&q={key}&start={start}&rows=40'
|
||||
r = self.fetch(url, headers=header)
|
||||
data = r.json()
|
||||
vList = data['response']['1']['docs']
|
||||
for video in vList:
|
||||
title = video['game_nick']
|
||||
if SequenceMatcher(None, title, key).ratio() < 0.6 and key not in title:
|
||||
continue
|
||||
items.append({
|
||||
'vod_id': '{}###huya###{}'.format(title, video['room_id']),
|
||||
'vod_name': title,
|
||||
'vod_pic': video['game_avatarUrl180'],
|
||||
"vod_remarks": '虎牙直播'
|
||||
})
|
||||
return {tag: [items, pg * 40 < len(items)]}
|
||||
|
||||
def playerContent(self, flag, pid, vipFlags):
|
||||
result = {}
|
||||
header = self.header.copy()
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = pid
|
||||
result["header"] = header
|
||||
return result, 14400
|
||||
|
||||
def localProxy(self, param):
|
||||
return [200, "video/MP2T", {}, ""]
|
||||
|
||||
def removeHtmlTags(self, src):
|
||||
from re import sub, compile
|
||||
clean = compile('<.*?>')
|
||||
return sub(clean, '', src)
|
||||
|
||||
def getCache(self, key):
|
||||
value = self.fetch(f'http://127.0.0.1:9978/cache?do=get&key={key}', timeout=5).text
|
||||
if len(value) > 0:
|
||||
if value.startswith('{') and value.endswith('}') or value.startswith('[') and value.endswith(']'):
|
||||
value = json.loads(value)
|
||||
if type(value) == dict:
|
||||
if not 'expiresAt' in value or value['expiresAt'] >= int(time.time()):
|
||||
return value
|
||||
else:
|
||||
self.delCache(key)
|
||||
return None
|
||||
return value
|
||||
else:
|
||||
return None
|
||||
|
||||
def setCache(self, key, value):
|
||||
if len(value) > 0:
|
||||
if type(value) == dict or type(value) == list:
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
self.post(f'http://127.0.0.1:9978/cache?do=set&key={key}', data={"value": value}, timeout=5)
|
||||
|
||||
def delCache(self, key):
|
||||
self.fetch(f'http://127.0.0.1:9978/cache?do=del&key={key}', timeout=5)
|
||||
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36"
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
import base64
|
||||
import random
|
||||
import requests
|
||||
import urllib.parse
|
||||
|
||||
class Spider(Spider): # 元类 默认的元类 type
|
||||
def getName(self):
|
||||
return "体育直播"
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"体育直播": "全部"
|
||||
}
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name':k,
|
||||
'type_id':cateManual[k]
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def categoryContent(self,tid,pg, filter,extend):
|
||||
result = {}
|
||||
if int(pg) > 1:
|
||||
return result
|
||||
rsp = self.fetch('http://itiyu5.tv/spweb/schedule', headers=self.header)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
dataList = root.xpath("//div[@class='fixtures']/div[@class='box']")
|
||||
dateList = root.xpath("//div[contains(@class,'subhead')]")
|
||||
videos = []
|
||||
utc_offset = self.fetch('http://worldtimeapi.org/api/timezone/Australia/Sydney', headers=self.header).json()['utc_offset']
|
||||
hour_offset = int(utc_offset.split(':')[0][1:]) - 8
|
||||
for data in dataList:
|
||||
pos = dataList.index(data)
|
||||
for video in data.xpath(".//div[@class='list']/ul/li"):
|
||||
infosList = video.xpath(".//div[@class='team']/div")
|
||||
stime = video.xpath(".//p[@class='name']/span/text()")[0].strip()
|
||||
sdate = dateList[pos].xpath('.//text()')[0].split()[0].strip()
|
||||
hour = stime.split(':')[0]
|
||||
if int(hour) < hour_offset:
|
||||
sdate = sdate.replace(sdate[3:-1], str(int(sdate[3:-1]) - 1))
|
||||
stime = str(24 - hour_offset + int(hour)) + ':' + stime.split(':')[1]
|
||||
else:
|
||||
hour = str(int(hour) - hour_offset)
|
||||
if len(hour) == 1:
|
||||
hour = '0' + hour
|
||||
stime = hour + ':' + stime.split(':')[1]
|
||||
rid = video.xpath(".//p[contains(@class,'btn')]/a/@href")[0]
|
||||
state = video.xpath(".//p[contains(@class,'btn')]/a/text()")[0].strip()
|
||||
if len(infosList) != 2:
|
||||
home = infosList[0].xpath('.//span/text()')[0].strip()
|
||||
away = infosList[2].xpath('.//span/text()')[0].strip()
|
||||
cover = infosList[0].xpath('.//img/@src')[0]
|
||||
name = home + 'VS' + away
|
||||
else:
|
||||
cover = 'https://s1.ax1x.com/2022/10/07/x3NPUO.png'
|
||||
name = infosList[1].xpath('.//text()')[0].strip()
|
||||
if state != '已结束':
|
||||
videos.append({
|
||||
"vod_id": rid,
|
||||
"vod_name": name,
|
||||
"vod_pic": cover,
|
||||
"vod_remarks": '[{}]|{}'.format(sdate, stime)
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
|
||||
def detailContent(self, array):
|
||||
for i in range(1, 5):
|
||||
rsp = self.fetch('http://itiyu5.tv{}/vid/{}'.format(array[0], i), headers=self.header)
|
||||
if 'vid/{}'.format(i) not in rsp.text or not '\'url\': ' in rsp.text:
|
||||
title = '比赛尚未开始'
|
||||
purl = 'http://0.0.0.0'
|
||||
else:
|
||||
purl = self.regStr(reg=r"\'url\': \"(.*?)\"", src=rsp.text)
|
||||
title = self.regStr(reg=r"\"title\": \"(.*?)\"", src=rsp.text)
|
||||
if purl == '':
|
||||
rid = self.regStr(reg=r'config\.iurl = \"(.*?)\"', src=rsp.text)
|
||||
if '.m3u' in rid:
|
||||
if rid.count('http') != 1:
|
||||
replstr = self.regStr(reg=r'(http.*?)http', src=rid)
|
||||
purl = rid.replace(replstr, '')
|
||||
else:
|
||||
rid = self.regStr(reg=r'id=(.*)', src=rid)
|
||||
rsp = self.fetch('https://info.zb.video.qq.com/?cmd=4', headers=self.header)
|
||||
country = json.loads(rsp.text)['country']
|
||||
province = json.loads(rsp.text)['province']
|
||||
city = json.loads(rsp.text)['city']
|
||||
ip = json.loads(rsp.text)['ip']
|
||||
rsp = self.fetch('https://geo.yolll.com/geo', headers=self.header)
|
||||
cf_ua = json.loads(rsp.text)['ua']
|
||||
cf_cc = json.loads(rsp.text)['ip']
|
||||
cf_ip = json.loads(rsp.text)['cc']
|
||||
rnd = round(random.random() * 100000)
|
||||
param = {
|
||||
'type': 'stream',
|
||||
'id': rid,
|
||||
'rnd': rnd,
|
||||
'ip': ip,
|
||||
'country': country,
|
||||
'province': province,
|
||||
'city': city,
|
||||
'tx_ip': ip,
|
||||
'tx_country': country,
|
||||
'tx_province': province,
|
||||
'tx_city': city,
|
||||
'cf_ip': cf_ip,
|
||||
'cf_cc': cf_cc,
|
||||
'cf_ua': cf_ua,
|
||||
'ref': 'direct',
|
||||
'ua': 'web',
|
||||
}
|
||||
self.header['Referer'] = 'https://v.stnye.cc/'
|
||||
self.header['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
rsp = self.post('https://cdn.dianshunxinxi.com/data/live.php', data=param, headers=self.header)
|
||||
jo = json.loads(rsp.text)
|
||||
if jo['status'] != 'success':
|
||||
return ''
|
||||
else:
|
||||
purl = base64.b64decode(urllib.parse.unquote(jo['playurl'])).decode('utf-8')
|
||||
purl = base64.b64decode(purl).decode('utf-8')
|
||||
if '.m3u' in purl or purl == 'http://0.0.0.0':
|
||||
break
|
||||
vod = {
|
||||
"vod_id":array[0],
|
||||
"vod_name":title,
|
||||
"vod_pic":'https://s1.ax1x.com/2022/10/07/x3NPUO.png',
|
||||
"type_name":'',
|
||||
"vod_year":'',
|
||||
"vod_area":"",
|
||||
"vod_remarks":'',
|
||||
"vod_actor":"",
|
||||
"vod_director":'',
|
||||
"vod_content":""
|
||||
}
|
||||
findurl = False
|
||||
if purl != '' and purl != 'http://0.0.0.0':
|
||||
rsp = self.fetch(purl, headers=self.header)
|
||||
if '.m3u8' in rsp.text and title != '比赛尚未开始':
|
||||
findurl = True
|
||||
while findurl:
|
||||
purl = rsp.text.strip('\n').split('\n')[-1]
|
||||
rsp = requests.get(purl, headers=self.header, verify=False)
|
||||
if '.m3u8' not in rsp.text:
|
||||
findurl = False
|
||||
vod['vod_play_from'] = '体育直播'
|
||||
vod['vod_play_url'] = '{}${}'.format(title.replace(' ', ''), purl)
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def searchContent(self,key,quick):
|
||||
result = {
|
||||
'list':[]
|
||||
}
|
||||
return result
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = id
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36"
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,411 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import base64
|
||||
import math
|
||||
import json
|
||||
import requests
|
||||
import urllib
|
||||
from urllib import request, parse
|
||||
import urllib.request
|
||||
import re
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "西瓜视频(个人中心)"
|
||||
def init(self,extend=""):
|
||||
self.userid=self.get_userid()
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
cateManual = {
|
||||
"电视剧":"dianshiju",
|
||||
"电影":"dianying",
|
||||
"动漫":"dongman",
|
||||
"纪录片":"jilupian",
|
||||
"少儿":"shaoer",
|
||||
"综艺":"zongyi",
|
||||
"关注":"follow"
|
||||
|
||||
}
|
||||
if self.userid=='':
|
||||
del cateManual['关注']
|
||||
classes = []
|
||||
for k in cateManual:
|
||||
classes.append({
|
||||
'type_name': k,
|
||||
'type_id': cateManual[k]
|
||||
})
|
||||
|
||||
result['class'] = classes
|
||||
if (filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
result = {
|
||||
'list': []
|
||||
}
|
||||
return result
|
||||
userid=''
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
idTxt='电视剧'
|
||||
maximum=17
|
||||
url = 'https://www.ixigua.com/api/cinema/filterv2/albums'
|
||||
if tid=='dianying':
|
||||
idTxt='电影'
|
||||
elif tid=='zongyi':
|
||||
idTxt='综艺'
|
||||
elif tid=='dianshiju':
|
||||
idTxt='电视剧'
|
||||
elif tid=='dongman':
|
||||
idTxt='动漫'
|
||||
elif tid=='jilupian':
|
||||
idTxt='纪录片'
|
||||
elif tid=='shaoer':
|
||||
idTxt='少儿'
|
||||
elif tid=='follow':
|
||||
offset=0 if int(pg)<2 else 20*int(pg)
|
||||
url='https://www.ixigua.com/api/userv2/follow/list?authorId={0}&sortType=desc&sortType=desc&cursor={1}'.format(self.userid,offset)
|
||||
maximum=12
|
||||
videos=[]
|
||||
if tid!='follow':
|
||||
offset=0 if int(pg)<2 else 18*int(pg)
|
||||
self.header['Referer']='https://www.ixigua.com/cinema/filter/'.format(tid)
|
||||
data=r'{"pinyin":"'+tid+'","filters":{"type":"'+idTxt+'","area":"全部地区","tag":"全部类型","sort":"综合排序","paid":"全部资费"},"offset":'+str(offset)+',"limit":18}'
|
||||
req = request.Request(url=url, data=bytes(data, encoding='utf8'),headers=self.header, method='POST')
|
||||
response = request.urlopen(req)
|
||||
urlTxt=response.read().decode('utf-8')
|
||||
videos= self.get_list_videoGroup_json(jsonTxt=urlTxt)
|
||||
else:
|
||||
rsp=self.fetch(url,headers=self.header)
|
||||
urlTxt=rsp.text
|
||||
videos= self.get_list_videoGroup_follow_json(jsonTxt=urlTxt)
|
||||
numvL = len(videos)
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = pg if int(numvL)<maximum else int(pg)+1
|
||||
result['limit'] = numvL
|
||||
result['total'] = numvL
|
||||
return result
|
||||
def get_userid(self):
|
||||
Url='https://www.ixigua.com/'
|
||||
rsp=self.fetch(Url,headers=self.header)
|
||||
htmlTxt = rsp.text
|
||||
userid= self.get_RegexGetText(Text=htmlTxt,RegexText=r'"identity":{"id":"(\d+?)",',Index=1)
|
||||
return userid
|
||||
def detailContent(self,array):
|
||||
result = {}
|
||||
aid = array[0].split('###')
|
||||
key = aid[1]
|
||||
title = aid[0]
|
||||
act=aid[2]
|
||||
logo = aid[3]
|
||||
Url='https://www.ixigua.com/api/albumv2/details?albumId={0}'.format(key)
|
||||
if len(aid)==5:
|
||||
Url='https://www.ixigua.com/api/videov2/author/new_video_list?to_user_id={0}'.format(key)
|
||||
rsp = self.fetch(Url,headers=self.header)
|
||||
htmlTxt = rsp.text
|
||||
typeName=''
|
||||
area=''
|
||||
dir=''
|
||||
cont=''
|
||||
vip='true'
|
||||
videoList=[]
|
||||
if len(aid)==5:
|
||||
jRoot = json.loads(htmlTxt)
|
||||
if jRoot['code']!=200:
|
||||
return result
|
||||
jo = jRoot['data']
|
||||
jsonList=jo['videoList']
|
||||
for value in jsonList:
|
||||
id="{0}${1}_false".format(value['title'],value.get('group_id'))
|
||||
videoList.append(id)
|
||||
dir=title
|
||||
elif htmlTxt.find('playlist')>2:
|
||||
jRoot = json.loads(htmlTxt)
|
||||
if jRoot['code']!=200:
|
||||
return result
|
||||
jo = jRoot['data']
|
||||
jsonList=jo['playlist']
|
||||
if jsonList is not None:
|
||||
for value in jsonList:
|
||||
id="{0}${1}?id={2}_{3}".format(value['title'],value['albumId'],value['episodeId'],vip)
|
||||
videoList.append(id)
|
||||
playFrom=[v for v in jo['albumInfo']['tagList']]
|
||||
typeName='/'.join(playFrom)
|
||||
playFrom=[v for v in jo['albumInfo']['areaList']]
|
||||
area='/'.join(playFrom)
|
||||
playFrom=[v['name'] for v in jo['albumInfo']['directorList']]
|
||||
dir='/'.join(playFrom)
|
||||
cont=jo['albumInfo']['intro']
|
||||
if len(videoList)<1:
|
||||
return result
|
||||
vod = {
|
||||
"vod_id":array[0],
|
||||
"vod_name":title,
|
||||
"vod_pic":logo,
|
||||
"type_name":typeName,
|
||||
"vod_year":'',
|
||||
"vod_area":area,
|
||||
"vod_remarks":"",
|
||||
"vod_actor":'',
|
||||
"vod_director":dir,
|
||||
"vod_content":cont
|
||||
}
|
||||
vod['vod_play_from'] = '西瓜'
|
||||
vod['vod_play_url'] = "#".join(videoList)
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
|
||||
def verifyCode(self):
|
||||
pass
|
||||
|
||||
def searchContent(self,key,quick):
|
||||
Url='https://www.ixigua.com/api/searchv2/lvideo/{0}/0'.format(urllib.parse.quote(key))
|
||||
rsp = self.fetch(Url,headers=self.header)
|
||||
htmlTxt = rsp.text
|
||||
videos=self.get_list(html=htmlTxt)
|
||||
'''
|
||||
Url='https://www.ixigua.com/api/searchv2/user/{0}/10'.format(urllib.parse.quote(key))
|
||||
rsp = self.fetch(Url,headers=self.header)
|
||||
htmlTxt1 = rsp.text
|
||||
videos=self.get_list_user(html=htmlTxt1)
|
||||
'''
|
||||
result = {
|
||||
'list': videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result={}
|
||||
UrlId=id.split('_')
|
||||
Url='https://www.ixigua.com/{0}'.format(UrlId[0])
|
||||
headers = {
|
||||
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Mobile Safari/537.36'
|
||||
}
|
||||
jx=1 if UrlId[1]=='true' else 0
|
||||
result["parse"] = 1#0=直接播放,1=解析
|
||||
result["playUrl"] = ''
|
||||
result["url"] = Url
|
||||
result['jx'] = jx#VIP解析
|
||||
result["header"] =headers
|
||||
return result
|
||||
def get_RegexGetText(self,Text,RegexText,Index):
|
||||
returnTxt=""
|
||||
Regex=re.search(RegexText, Text, re.M|re.I)
|
||||
if Regex is None:
|
||||
returnTxt=""
|
||||
else:
|
||||
returnTxt=Regex.group(Index)
|
||||
return returnTxt
|
||||
def get_RegexGetTextLine(self,Text,RegexText,Index):
|
||||
returnTxt=[]
|
||||
pattern = re.compile(RegexText)
|
||||
ListRe=pattern.findall(Text)
|
||||
if len(ListRe)<1:
|
||||
return returnTxt
|
||||
for value in ListRe:
|
||||
returnTxt.append(value)
|
||||
return returnTxt
|
||||
def get_playlist(self,Text,headStr,endStr):
|
||||
circuit=""
|
||||
origin=Text.find(headStr)
|
||||
if origin>8:
|
||||
end=Text.find(endStr,origin)
|
||||
circuit=Text[origin:end]
|
||||
return circuit
|
||||
def removeHtml(self,txt):
|
||||
soup = re.compile(r'<[^>]+>',re.S)
|
||||
txt =soup.sub('', txt)
|
||||
return txt.replace(" "," ")
|
||||
def get_webReadFile(self,urlStr):
|
||||
headers = {
|
||||
'Referer':urlStr,
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36',
|
||||
'Host': 'www.ikmjw.com'
|
||||
}
|
||||
req = urllib.request.Request(url=urlStr, headers=headers)
|
||||
html = urllib.request.urlopen(req).read().decode('utf-8')
|
||||
return html
|
||||
def get_list(self,html):
|
||||
result={}
|
||||
jRoot = json.loads(html)
|
||||
if jRoot['code']!=0:
|
||||
return result
|
||||
jo = jRoot['data']
|
||||
if len(jo)<1:
|
||||
return result
|
||||
vodList = jo['data']
|
||||
if len(vodList)<1:
|
||||
return result
|
||||
videos=[]
|
||||
img='_'
|
||||
artist='_'
|
||||
for vod in vodList:
|
||||
if vod['type']!='lvideo':
|
||||
continue
|
||||
data=vod['data']
|
||||
display=data['display']
|
||||
title =display['name']
|
||||
if len(title)==0:
|
||||
continue
|
||||
episode_link=display.get('episode_link')
|
||||
asc_link=episode_link.get('asc_link')
|
||||
KeyName='album_id'
|
||||
if asc_link is None:
|
||||
asc_link=episode_link.get('desc_link')
|
||||
KeyName='album_id'
|
||||
id=asc_link[0].get('album_id')
|
||||
sslocal=asc_link[0]['scheme_url']
|
||||
if sslocal!=None and sslocal.find('sslocal:')<0:
|
||||
continue
|
||||
video_cover_info=display.get('video_cover_info')
|
||||
img=video_cover_info['url'] if video_cover_info is not None else '_'
|
||||
try:
|
||||
artist=display['actor']
|
||||
except Exception:
|
||||
artist=''
|
||||
remarks=display['rating']
|
||||
vod_id="{0}###{1}###{2}###{3}".format(title,id,artist,img)
|
||||
videos.append({
|
||||
"vod_id":vod_id,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remarks
|
||||
})
|
||||
return videos
|
||||
def get_list_user(self,html):
|
||||
result={}
|
||||
jRoot = json.loads(html)
|
||||
if jRoot['code']!=0:
|
||||
return result
|
||||
jo = jRoot['data']
|
||||
if len(jo)<1:
|
||||
return result
|
||||
vodList = jo['data']
|
||||
if len(vodList)<1:
|
||||
return result
|
||||
videos=[]
|
||||
img='_'
|
||||
artist='_'
|
||||
for vod in vodList:
|
||||
if vod['type']!='user':
|
||||
continue
|
||||
data=vod['data']
|
||||
img=data['avatar']
|
||||
title =data['name']
|
||||
log_pb=json.loads(data.get('log_pb'))
|
||||
user_auth_info=json.loads(data.get('user_auth_info'))
|
||||
remarks=user_auth_info['auth_info']
|
||||
id=log_pb.get('search_result_id')
|
||||
vod_id="{0}###{1}###{2}###{3}###{4}".format(title,id,artist,img,'user')
|
||||
videos.append({
|
||||
"vod_id":vod_id,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remarks
|
||||
})
|
||||
return videos
|
||||
def get_list_videoGroup_json(self,jsonTxt):
|
||||
result={}
|
||||
jRoot = json.loads(jsonTxt)
|
||||
if jRoot['code']!=200:
|
||||
return result
|
||||
jo = jRoot['data']
|
||||
vodList = jo['albumList']
|
||||
if len(vodList)<1:
|
||||
return result
|
||||
videos=[]
|
||||
img='_'
|
||||
artist='_'
|
||||
for vod in vodList:
|
||||
url =vod['albumId']
|
||||
title =vod['title']
|
||||
imgList =vod.get('coverList')
|
||||
if len(imgList)>0:
|
||||
img=imgList[0]['url']
|
||||
remarks=vod['subTitle']
|
||||
artistList=vod.get('actorList')
|
||||
if artistList is not None:
|
||||
artistList=artistList if len(artistList)<5 else artistList[0:4]
|
||||
artist='/'.join(artistList)
|
||||
if len(title)==0:
|
||||
continue
|
||||
#标题###地址###演员###封面
|
||||
vod_id="{0}###{1}###{2}###{3}".format(title,url,artist,img)
|
||||
videos.append({
|
||||
"vod_id":vod_id,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remarks
|
||||
})
|
||||
return videos
|
||||
def get_list_videoGroup_follow_json(self,jsonTxt):
|
||||
videos=[]
|
||||
jRoot = json.loads(jsonTxt)
|
||||
if jRoot['code']!=0:
|
||||
return videos
|
||||
jo = jRoot['data']
|
||||
vodList=jo['data']
|
||||
if len(vodList)<1:
|
||||
return videos
|
||||
img='_'
|
||||
artist=''
|
||||
for vod in vodList:
|
||||
url =vod.get('user_id')
|
||||
title =vod['name']
|
||||
img =vod.get('avatar_url')
|
||||
remarks=vod['description']
|
||||
artistList=vod.get('actorList')
|
||||
artist=title
|
||||
if len(title)==0:
|
||||
continue
|
||||
#标题###地址###演员###封面
|
||||
vod_id="{0}###{1}###{2}###{3}###{4}".format(title,url,artist,img,'user')
|
||||
videos.append({
|
||||
"vod_id":vod_id,
|
||||
"vod_name":title,
|
||||
"vod_pic":img,
|
||||
"vod_remarks":remarks
|
||||
})
|
||||
return videos
|
||||
def get_lineList(self,Txt,mark,after):
|
||||
circuit=[]
|
||||
origin=Txt.find(mark)
|
||||
while origin>8:
|
||||
end=Txt.find(after,origin)
|
||||
circuit.append(Txt[origin:end])
|
||||
origin=Txt.find(mark,end)
|
||||
return circuit
|
||||
def get_EpisodesList(self,jsonList):
|
||||
vodItems=[]
|
||||
for value in jsonList:
|
||||
vodItems.append(value['title']+"$"+'https://www.ixigua.com/{0}?logTag=55abe18cfb733871bb04'.format(value['episodeId']))
|
||||
return vodItems
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {
|
||||
"Cookie":"s_v_web_id=verify_lev3h43l_rrTPrFDG_ztWQ_4ugg_8WBA_yGVYsXlVyoBh; passport_csrf_token=80e0efe90bc8bd6681a896dd90cd08cc; passport_csrf_token_default=80e0efe90bc8bd6681a896dd90cd08cc; __ac_nonce=0643361890096533c765; __ac_signature=_02B4Z6wo00f01JPVVrAAAIDBcisHPfWA66CT91IAAEDK9840CE-PheNOCgA4VtrFG0-K.KkLmAR5KsI-Xx-6dBXxz.ABWU2OpEd22kF7biwGaVmGR7an4S1heLEU9xpv0ObRSHFHDslR7uL8fb; support_webp=true; support_avif=false; MONITOR_WEB_ID=45c3b6ab-7ad4-4805-b971-5962d1d6909a; ttwid=1%7CCueNR-HU9tGVF30WaiFCjXDxh0FUXoXsZr-cIb9Dogg%7C1681089268%7Cf0eeaa2016a602a277055494954f083e9f7fa8121c5dd1162db9195932fa167b; odin_tt=386a42a5740f9859d4670373fc8c70cf320ea5b227aed04bcc53fde26c233e8c952a8b0ba5f80fd3d46f9663fa595d8c; sid_guard=842b56710f55021912487890e7d5bef3%7C1681089337%7C3024001%7CMon%2C+15-May-2023+01%3A15%3A38+GMT; uid_tt=b7eb5b73cd72bed6d3c2e1e1e8aaa9f3; uid_tt_ss=b7eb5b73cd72bed6d3c2e1e1e8aaa9f3; sid_tt=842b56710f55021912487890e7d5bef3; sessionid=842b56710f55021912487890e7d5bef3; sessionid_ss=842b56710f55021912487890e7d5bef3; sid_ucp_v1=1.0.0-KGQ2YzBlMDFiMzIyMjY0YTIwMDg2MjZmZGQzMTE5MmFlYTYzY2EwMTMKFQjL2cnx9AIQucbNoQYYGCAMOAhABRoCaGwiIDg0MmI1NjcxMGY1NTAyMTkxMjQ4Nzg5MGU3ZDViZWYz; ssid_ucp_v1=1.0.0-KGQ2YzBlMDFiMzIyMjY0YTIwMDg2MjZmZGQzMTE5MmFlYTYzY2EwMTMKFQjL2cnx9AIQucbNoQYYGCAMOAhABRoCaGwiIDg0MmI1NjcxMGY1NTAyMTkxMjQ4Nzg5MGU3ZDViZWYz; csrf_session_id=c58adecac1d20d91d8c61e72ce0c6fdb; ixigua-a-s=3; msToken=St3ptsHkwBjPgGvRWhZfVdhHO_K16vTizxxna17draCvt4ekz6DQXO6c2Ctrp6gOnn9_Abm83-a9URQp5rKb-JIPs4mQPn2fpKlQRY6jLDBWUdLYTePIAACU6cY2fk40; tt_scid=nN3WPItw72gnB5PDiGcHveirXDZ8oDl5n.ihKN583mmZhoe.uLhFpy3JOL8wrsQO0ed1",
|
||||
"Referer": 'https://www.ixigua.com/cinema/filter/dianshiju/',
|
||||
'User-Agent':'User-Agent: Mozilla%2F5.0+(Windows+NT+10.0%3B+WOW64)+AppleWebKit%2F537.36+(KHTML%2C+like+Gecko)+Chrome%2F63.0.3239.132+Safari%2F537.36',
|
||||
'Host': 'www.ixigua.com',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'x-secsdk-csrf-token': '0001000000017b593ba6251b18bd7bce2753042917bb36e534867b9606317584c00b0ae836c61754314b7365128e',
|
||||
'tt-anti-token': 'oDr7A3PDDFq4pWzk-707faf92a9e3040f5c6ed4284d53b05b7091221852c0e9d32bca9fcfe5035225',
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,181 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import requests
|
||||
from base64 import b64encode
|
||||
from collections import OrderedDict
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "Yiso"
|
||||
def init(self,extend):
|
||||
self.ali = extend[0]
|
||||
print("============{0}============")
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
return result
|
||||
|
||||
def detailContent(self,array):
|
||||
hashMap = {}
|
||||
dirname = ''
|
||||
ids = array[0].split('@@@')
|
||||
self.listFiles(hashMap, dirname, [ids[1]])
|
||||
if not hashMap:
|
||||
return {}
|
||||
sortedMap = sorted(hashMap.items(), key=lambda x: x[0])
|
||||
vod = {
|
||||
"vod_id": array[0],
|
||||
"vod_name": ids[0],
|
||||
"vod_pic": 'https://p2.itc.cn/q_70/images03/20211009/59c75745d3524163b9277c4006020ac0.jpeg',
|
||||
"type_name": "",
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": "",
|
||||
"vod_actor": "",
|
||||
"vod_director": "",
|
||||
"vod_content": ""
|
||||
}
|
||||
vod['vod_play_from'] = '原画$$$超清'
|
||||
vod_play_url = ''
|
||||
YHplayurl = ''
|
||||
CQplayurl = ''
|
||||
subDict = {}
|
||||
nameList = []
|
||||
for sm in sortedMap:
|
||||
if 'subtitles' in sm:
|
||||
for subList in sm[1]:
|
||||
subDict.update({os.path.splitext(subList['name'])[0]: sm[1].index(subList)})
|
||||
else:
|
||||
name = sm[0]
|
||||
sm[1][0]['params']['downloader_switch'] = 'True'
|
||||
YHurl = 'Docker域名或IP:端口/ali_resolve?item=' + b64encode(
|
||||
json.dumps(sm[1][0]['params']).encode("utf-8")).decode("utf-8")
|
||||
CQurl = 'Docker域名或IP:端口/ali_resolve?item=' + b64encode(
|
||||
json.dumps(sm[1][1]['params']).encode("utf-8")).decode("utf-8")
|
||||
YHplayurl = '{}#{}${}'.format(YHplayurl, name, YHurl)
|
||||
CQplayurl = '{}#{}${}'.format(CQplayurl, name, CQurl)
|
||||
name = name.split('/')[0]
|
||||
if ']|' in name:
|
||||
name = name.split('|')[1]
|
||||
nameList.append(name)
|
||||
for nL in nameList:
|
||||
for sbkey in subDict:
|
||||
if os.path.splitext(nL)[0] in sbkey:
|
||||
value = json.dumps(sm[1][subDict[sbkey]]['params'])
|
||||
requests.post('Docker域名或IP:端口/cache', params={'key': 'alisub', }, data=value, headers={'Content-Length': str(len(value))})
|
||||
vod['vod_play_url'] = YHplayurl.strip('#') + '$$$' + CQplayurl.strip('#')
|
||||
result = {
|
||||
'list': [vod]
|
||||
}
|
||||
return result
|
||||
|
||||
def listFiles(self, map, dirname, list):
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 12; V2049A Build/SP1A.210812.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36"
|
||||
}
|
||||
parent_item = {
|
||||
'id': list[0],
|
||||
'params': {}
|
||||
}
|
||||
url = 'Docker域名或IP:端口/ali_list?item=' + b64encode(json.dumps(parent_item).encode("utf-8")).decode("utf-8") + '&display_file_size=True'
|
||||
rsp = self.fetch(url, headers=header)
|
||||
while rsp.status_code != 200:
|
||||
time.sleep(1)
|
||||
rsp = self.fetch(url, headers=header)
|
||||
if rsp.text in ['Erro', 'Token', 'Session', 'Lapse', 'None']:
|
||||
return {}
|
||||
jo = json.loads(rsp.text)
|
||||
folderList = []
|
||||
dirnameList = []
|
||||
subtitlesList = []
|
||||
for info in jo:
|
||||
if dirname != '' and not dirname.startswith('['):
|
||||
dirname = '[' + dirname + ']|'
|
||||
if info['params']['file_type'] == 'folder':
|
||||
folderList.append(info['id'])
|
||||
dirnameList.append(info['name'])
|
||||
else:
|
||||
size = '/[{}]'.format(info['description'].split('\n')[0].split(':')[1])
|
||||
map[dirname + info['name'] + size] = info['sources']
|
||||
if info['subtitles'] != [] and info['subtitles'][0] not in subtitlesList:
|
||||
subtitlesList = subtitlesList + info['subtitles']
|
||||
if len(subtitlesList) > 0:
|
||||
map.update({'subtitles': subtitlesList})
|
||||
for folder in folderList:
|
||||
dirname = dirnameList[folderList.index(folder)]
|
||||
self.listFiles(map, dirname, [folder])
|
||||
|
||||
def searchContent(self,key,quick):
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 12; V2049A Build/SP1A.210812.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36"
|
||||
}
|
||||
url = "https://www.yunpanfenxiang.cn/api/bbs/api/getdata2?key={}".format(key)
|
||||
rsp = self.fetch(url=url, headers=header)
|
||||
vodList = json.loads(self.cleanText(rsp.text))["data"][0]['result']['items']
|
||||
videos = []
|
||||
linkList = []
|
||||
for vod in vodList:
|
||||
sid = vod["page_url"]
|
||||
if not 'www.aliyundrive.com' in sid:
|
||||
continue
|
||||
if not sid.endswith('/'):
|
||||
sid = sid + '/'
|
||||
linkid = self.regStr(sid, r'/s/(\w+)/')
|
||||
if linkid in linkList:
|
||||
continue
|
||||
linkList.append(linkid)
|
||||
name = vod['title']
|
||||
if len(name) > 15:
|
||||
name = ''.join(OrderedDict.fromkeys(name))
|
||||
videos.append({
|
||||
"vod_id": name + '@@@' + sid,
|
||||
"vod_name":name,
|
||||
"vod_pic": "https://inews.gtimg.com/newsapp_bt/0/13263837859/1000",
|
||||
"vod_remarks": vod['insert_time'].split(' ')[0]
|
||||
})
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
token = requests.get('Token外链地址').text.replace('\n', '').replace(' ', '')
|
||||
url = id
|
||||
rsp = self.fetch(url=url)
|
||||
purl = '{}&token={}&connection={}' .format(rsp.text, token, '20')
|
||||
alisub = requests.get('Docker域名或IP:端口/cache',params={'key': 'alisub'}).text
|
||||
if alisub != '':
|
||||
requests.delete('Docker域名或IP:端口/cache', params={'key': 'alisub'})
|
||||
suburl = 'Docker域名或IP:端口/proxy_download_file?params={}&token={}&connection=1'.format(b64encode(alisub).encode("utf-8").decode("utf-8"), token)
|
||||
result['subt'] = suburl
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = purl
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,128 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
|
||||
class Spider(Spider):
|
||||
def getName(self):
|
||||
return "一席"
|
||||
def init(self,extend=""):
|
||||
print("============{0}============".format(extend))
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
url = 'https://yixi.tv/api/site/category/?_=1'
|
||||
jo = self.fetch(url,headers=self.header).json()
|
||||
category = jo['data']['items']
|
||||
classes = []
|
||||
classes.append({
|
||||
'type_name':'全部',
|
||||
'type_id':''
|
||||
})
|
||||
for cat in category:
|
||||
classes.append({
|
||||
'type_name':cat['title'],
|
||||
'type_id':cat['id']
|
||||
})
|
||||
result['class'] = classes
|
||||
if(filter):
|
||||
result['filters'] = self.config['filter']
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
# url = 'https://yixi.tv/api/site/album/?page=1&page_size=4&_=1'
|
||||
url = 'https://yixi.tv/api/site/album/22/detail/?page=1&page_size=24&_=1'
|
||||
jo = self.fetch(url,headers=self.header).json()
|
||||
videos = []
|
||||
vodList = jo['data']['items']
|
||||
for vod in vodList:
|
||||
videos.append({
|
||||
"vod_id":vod['id'],
|
||||
"vod_name":vod['title'],
|
||||
"vod_pic":vod['cover'],
|
||||
"vod_remarks":vod['time']
|
||||
})
|
||||
result = {
|
||||
'list':videos
|
||||
}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
url = 'https://yixi.tv/api/site/speech/?page={1}&page_size=12&category_id={0}&order_by=0&_=1'.format(tid,pg)
|
||||
jo = self.fetch(url,headers=self.header).json()
|
||||
videos = []
|
||||
vodList = jo['data']['items']
|
||||
for vod in vodList:
|
||||
videos.append({
|
||||
"vod_id":vod['id'],
|
||||
"vod_name":vod['title'],
|
||||
"vod_pic":vod['cover'],
|
||||
"vod_remarks":vod['time']
|
||||
})
|
||||
result['list'] = videos
|
||||
result['page'] = pg
|
||||
result['pagecount'] = 9999
|
||||
result['limit'] = 90
|
||||
result['total'] = 999999
|
||||
return result
|
||||
def detailContent(self,array):
|
||||
tid = array[0]
|
||||
url = "https://yixi.tv/api/site/speech/{0}/detail/?_=1".format(tid)
|
||||
jo = self.fetch(url,headers=self.header).json()
|
||||
|
||||
vod = {
|
||||
"vod_id":jo['data']['speech']['id'],
|
||||
"vod_name":jo['data']['speech']['title'],
|
||||
"vod_pic":jo['data']['speech']['cover'],
|
||||
"type_name":jo['data']['speech']['first_category'],
|
||||
"vod_year":"",
|
||||
"vod_area":"",
|
||||
"vod_remarks":jo['data']['speech']['date'],
|
||||
"vod_actor":"",
|
||||
"vod_director":"",
|
||||
"vod_content":jo['data']['speech']['titlelanguage']
|
||||
}
|
||||
|
||||
vod['vod_play_from'] = '一席'
|
||||
pList = []
|
||||
for vUrl in sorted(jo['data']['speech']['video_url'], key=lambda x: x['type'], reverse=True):
|
||||
if vUrl['video_url'] == '':
|
||||
continue
|
||||
pList.append(vUrl['type_name']+"$"+vUrl['video_url'])
|
||||
vod['vod_play_url'] = '#'.join(pList)
|
||||
result = {
|
||||
'list':[
|
||||
vod
|
||||
]
|
||||
}
|
||||
return result
|
||||
def searchContent(self,key,quick):
|
||||
result = {
|
||||
'list':[]
|
||||
}
|
||||
return result
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = id
|
||||
result["header"] = ''
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36"
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
@@ -0,0 +1,218 @@
|
||||
#coding=utf-8
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import requests
|
||||
from base64 import b64encode
|
||||
from collections import OrderedDict
|
||||
|
||||
sys.path.append('..')
|
||||
from base.spider import Spider
|
||||
|
||||
class Spider(Spider):
|
||||
def getDependence(self):
|
||||
return ['py_ali']
|
||||
def getName(self):
|
||||
return "py_zhaozy"
|
||||
def init(self,extend):
|
||||
self.ali = extend[0]
|
||||
print("============py_zhaozy============")
|
||||
pass
|
||||
def isVideoFormat(self,url):
|
||||
pass
|
||||
def manualVideoCheck(self):
|
||||
pass
|
||||
def homeContent(self,filter):
|
||||
result = {}
|
||||
return result
|
||||
def homeVideoContent(self):
|
||||
result = {}
|
||||
return result
|
||||
def categoryContent(self,tid,pg,filter,extend):
|
||||
result = {}
|
||||
return result
|
||||
header = {
|
||||
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36",
|
||||
"Referer": "https://zhaoziyuan.la/"
|
||||
}
|
||||
def detailContent(self,array):
|
||||
hashMap = {}
|
||||
dirname = ''
|
||||
ids = array[0].split('@@@')
|
||||
pattern = '(https://www.aliyundrive.com/s/[^\"]+)'
|
||||
url = self.regStr(ids[1], pattern)
|
||||
if len(url) > 0:
|
||||
self.listFiles(hashMap, dirname, [ids[1]])
|
||||
else:
|
||||
rsp = self.fetch('https://zhaoziyuan.la/' + ids[1])
|
||||
url = self.regStr(rsp.text, pattern)
|
||||
if len(url) == 0:
|
||||
return {}
|
||||
self.listFiles(hashMap, dirname, [url])
|
||||
if not hashMap:
|
||||
return {}
|
||||
sortedMap = sorted(hashMap.items(), key=lambda x: x[0])
|
||||
vod = {
|
||||
"vod_id": array[0],
|
||||
"vod_name": ids[0],
|
||||
"vod_pic": 'https://p2.itc.cn/q_70/images03/20211009/59c75745d3524163b9277c4006020ac0.jpeg',
|
||||
"type_name": "",
|
||||
"vod_year": "",
|
||||
"vod_area": "",
|
||||
"vod_remarks": "",
|
||||
"vod_actor": "",
|
||||
"vod_director": "",
|
||||
"vod_content": ""
|
||||
}
|
||||
vod['vod_play_from'] = '原画$$$超清'
|
||||
vod_play_url = ''
|
||||
YHplayurl = ''
|
||||
CQplayurl = ''
|
||||
subDict = {}
|
||||
nameList = []
|
||||
for sm in sortedMap:
|
||||
if 'subtitles' in sm:
|
||||
for subList in sm[1]:
|
||||
subDict.update({os.path.splitext(subList['name'])[0]: sm[1].index(subList)})
|
||||
else:
|
||||
name = sm[0]
|
||||
sm[1][0]['params']['downloader_switch'] = 'True'
|
||||
YHurl = 'Docker域名或IP:端口/ali_resolve?item=' + b64encode(
|
||||
json.dumps(sm[1][0]['params']).encode("utf-8")).decode("utf-8")
|
||||
CQurl = 'Docker域名或IP:端口/ali_resolve?item=' + b64encode(
|
||||
json.dumps(sm[1][1]['params']).encode("utf-8")).decode("utf-8")
|
||||
YHplayurl = '{}#{}${}'.format(YHplayurl, name, YHurl)
|
||||
CQplayurl = '{}#{}${}'.format(CQplayurl, name, CQurl)
|
||||
name = name.split('/')[0]
|
||||
if ']|' in name:
|
||||
name = name.split('|')[1]
|
||||
nameList.append(name)
|
||||
for nL in nameList:
|
||||
for sbkey in subDict:
|
||||
if os.path.splitext(nL)[0] in sbkey:
|
||||
value = json.dumps(sm[1][subDict[sbkey]]['params'])
|
||||
requests.post('Docker域名或IP:端口/cache', params={'key': 'alisub', }, data=value, headers={'Content-Length': str(len(value))})
|
||||
vod['vod_play_url'] = YHplayurl.strip('#') + '$$$' + CQplayurl.strip('#')
|
||||
result = {
|
||||
'list': [vod]
|
||||
}
|
||||
return result
|
||||
|
||||
def listFiles(self, map, dirname, list):
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 12; V2049A Build/SP1A.210812.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36"
|
||||
}
|
||||
parent_item = {
|
||||
'id': list[0],
|
||||
'params': {}
|
||||
}
|
||||
url = 'Docker域名或IP:端口/ali_list?item=' + b64encode(json.dumps(parent_item).encode("utf-8")).decode("utf-8") + '&display_file_size=True'
|
||||
rsp = self.fetch(url, headers=header)
|
||||
while rsp.status_code != 200:
|
||||
time.sleep(1)
|
||||
rsp = self.fetch(url, headers=header)
|
||||
if rsp.text in ['Erro', 'Token', 'Session', 'Lapse', 'None']:
|
||||
return {}
|
||||
jo = json.loads(rsp.text)
|
||||
folderList = []
|
||||
dirnameList = []
|
||||
subtitlesList = []
|
||||
for info in jo:
|
||||
if dirname != '' and not dirname.startswith('['):
|
||||
dirname = '[' + dirname + ']|'
|
||||
if info['params']['file_type'] == 'folder':
|
||||
folderList.append(info['id'])
|
||||
dirnameList.append(info['name'])
|
||||
else:
|
||||
size = '/[{}]'.format(info['description'].split('\n')[0].split(':')[1])
|
||||
map[dirname + info['name'] + size] = info['sources']
|
||||
if info['subtitles'] != [] and info['subtitles'][0] not in subtitlesList:
|
||||
subtitlesList = subtitlesList + info['subtitles']
|
||||
if len(subtitlesList) > 0:
|
||||
map.update({'subtitles': subtitlesList})
|
||||
for folder in folderList:
|
||||
dirname = dirnameList[folderList.index(folder)]
|
||||
self.listFiles(map, dirname, [folder])
|
||||
|
||||
def searchContent(self,key,quick):
|
||||
map = {
|
||||
'7':'文件夹',
|
||||
'1':'视频'
|
||||
}
|
||||
ja = []
|
||||
cookies_str = requests.get('https://getplayurl.lm317379829.repl.co/cache?key=cookies')
|
||||
if cookies_str.text == '':
|
||||
cookies = self.getCookie()
|
||||
else:
|
||||
cookies_dict = cookies_str.json()
|
||||
if cookies_dict['expires'] <= int(time.time()):
|
||||
cookies = self.getCookie()
|
||||
else:
|
||||
cookies = requests.cookies.RequestsCookieJar()
|
||||
for ckey, value in cookies_dict.items():
|
||||
if ckey == 'domain' or ckey == 'expires':
|
||||
continue
|
||||
c = requests.cookies.create_cookie(ckey, value)
|
||||
c.domain = cookies_dict['domain']
|
||||
c.expires = cookies_dict['expires']
|
||||
cookies.set_cookie(c)
|
||||
for tKey in map.keys():
|
||||
url = "https://zhaoziyuan.la/so?filename={0}&t={1}".format(key,tKey)
|
||||
rsp = self.fetch(url, headers=self.header, cookies=cookies)
|
||||
root = self.html(self.cleanText(rsp.text))
|
||||
aList = root.xpath("//li[@class='clear']/div/div[@class='news_text']/a")
|
||||
for a in aList:
|
||||
name = self.xpText(a,'./h3/text()')
|
||||
if len(name) > 15:
|
||||
name = ''.join(OrderedDict.fromkeys(name))
|
||||
remark = self.xpText(a,'./p/text()').split('|')[1].strip()
|
||||
jo = {
|
||||
'vod_id': name + '@@@' + self.xpText(a,'@href'),
|
||||
'vod_name': name,
|
||||
'vod_pic': "https://inews.gtimg.com/newsapp_bt/0/13263837859/1000",
|
||||
"vod_remarks": remark
|
||||
}
|
||||
ja.append(jo)
|
||||
result = {
|
||||
'list':ja
|
||||
}
|
||||
return result
|
||||
|
||||
def getCookie(self):
|
||||
header = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36",
|
||||
"Referer": "https://zhaoziyuan.la/login.html",
|
||||
"Origin": "https://zhaoziyuan.la/"
|
||||
}
|
||||
logininfo = {'username': 'Unbaked4136', 'password': '4hzxQkB9yxX5EP'}
|
||||
r = requests.post('https://zhaoziyuan.la/logiu.html', data=logininfo, headers=header, timeout=5)
|
||||
cookies = r.cookies.get_dict()
|
||||
cookies.update({'expires': int(time.time()) + 604200})
|
||||
cookies.update({'domain': 'zhaoziyuan.la'})
|
||||
requests.post('https://getplayurl.lm317379829.repl.co/cache?key=cookies', data=json.dumps(cookies))
|
||||
return r.cookies
|
||||
|
||||
def playerContent(self,flag,id,vipFlags):
|
||||
result = {}
|
||||
token = requests.get('Token外链地址').text.replace('\n', '').replace(' ', '')
|
||||
url = id
|
||||
rsp = self.fetch(url=url)
|
||||
purl = '{}&token={}&connection={}' .format(rsp.text, token, '20')
|
||||
alisub = requests.get('Docker域名或IP:端口/cache',params={'key': 'alisub'}).text
|
||||
if alisub != '':
|
||||
requests.delete('Docker域名或IP:端口/cache', params={'key': 'alisub'})
|
||||
suburl = 'Docker域名或IP:端口/proxy_download_file?params={}&token={}&connection=1'.format(b64encode(alisub).encode("utf-8").decode("utf-8"), token)
|
||||
result['subt'] = suburl
|
||||
result["parse"] = 0
|
||||
result["playUrl"] = ''
|
||||
result["url"] = purl
|
||||
return result
|
||||
|
||||
config = {
|
||||
"player": {},
|
||||
"filter": {}
|
||||
}
|
||||
|
||||
def localProxy(self,param):
|
||||
return [200, "video/MP2T", action, ""]
|
||||
Reference in New Issue
Block a user