Files
2026-06-29 03:41:14 +00:00

322 lines
9.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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