Add files via upload

This commit is contained in:
xmbjm
2025-01-08 10:09:04 +08:00
committed by GitHub
parent b469afda1d
commit c0773b5084
17 changed files with 6806 additions and 0 deletions
+1056
View File
@@ -0,0 +1,1056 @@
# coding=utf-8
# !/usr/bin/python
import os.path
import random
import sys
sys.path.append('..')
try:
# from base.spider import Spider as BaseSpider
from base.spider import BaseSpider
except ImportError:
from t4.base.spider import BaseSpider
import json
import time
import base64
import datetime
import re
from urllib import request, parse
from pathlib import Path
import urllib
import urllib.request
"""
配置示例:
t4的配置里ext节点会自动变成api对应query参数extend,但t4的ext字符串不支持路径格式,比如./开头或者.json结尾
api里会自动含有ext参数是base64编码后的选中的筛选条件
错误示例,ext含有json:
{
"key":"hipy_cntv央视",
"name":"cntv央视(hipy_t4)",
"type":4,
"api":"http://192.168.31.49:5707/api/v1/vod/cntv央视?api_ext={{host}}/txt/hipy/cntv央视.json",
"searchable":1,
"quickSearch":1,
"filterable":0,
"ext":"cntv央视.json"
}
正确示例。同时存在ext和api_ext会优先取ext作为extend加载init
{
"key":"hipy_t4_cntv央视",
"name":"cntv央视(hipy_t4)",
"type":4,
"api":"http://192.168.31.49:5707/api/v1/vod/cntv央视?api_ext={{host}}/txt/hipy/cntv央视.json",
"searchable":1,
"quickSearch":0,
"filterable":1,
"ext":"{{host}}/files/hipy/cntv央视.json"
},
{
"key": "hipy_t3_cntv央视",
"name": "cntv央视(hipy_t3)",
"type": 3,
"api": "{{host}}/txt/hipy/cntv央视.py",
"searchable": 1,
"quickSearch": 0,
"filterable": 1,
"ext": "{{host}}/files/hipy/cntv央视.json"
},
"""
class Spider(BaseSpider): # 元类 默认的元类 type
module = None
def getDependence(self):
return ['base_spider']
def getName(self):
return "中央电视台" # 可搜索
def init_api_ext_file(self):
ext_file = __file__.replace('.py', '.json')
print(f'ext_file:{ext_file}')
# 特别节目网页: https://tv.cctv.com/yxg/index.shtml?spm=C28340.PlFTqGe6Zk8M.E2PQtIunpEaz.65
# 特别节目分类筛选获取页面: https://tv.cctv.com/yxg/tbjm/index.shtml
# 纪录片网页: https://tv.cctv.com/yxg/index.shtml?spm=C28340.PlFTqGe6Zk8M.E2PQtIunpEaz.65
# 纪录片分类筛选获取页面:https://tv.cctv.com/yxg/jlp/index.shtml
# ==================== 获取特别节目的筛选条件 ======================
r = self.fetch('https://tv.cctv.com/yxg/tbjm/index.shtml')
html = r.text
html = self.html(html)
filter_tbjm = []
lis = html.xpath('//*[@id="pindao"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datacd')),
})
# print(li_value)
filter_tbjm.append({
"key": "datapd-channel",
"name": "频道",
"value": li_value
})
lis = html.xpath('//*[@id="fenlei"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datalx')),
})
# print(li_value)
filter_tbjm.append({
"key": "datafl-sc",
"name": "类型",
"value": li_value
})
lis = html.xpath('//*[@id="zimu"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datazm')),
})
# print(li_value)
filter_tbjm.append({
"key": "dataszm-letter",
"name": "首字母",
"value": li_value
})
print(filter_tbjm)
# ==================== 纪录片筛选获取 ======================
r = self.fetch('https://tv.cctv.com/yxg/jlp/index.shtml')
html = r.text
html = self.html(html)
filter_jlp = []
lis = html.xpath('//*[@id="pindao"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datacd')),
})
# print(li_value)
filter_jlp.append({
"key": "datapd-channel",
"name": "频道",
"value": li_value
})
lis = html.xpath('//*[@id="fenlei"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datalx')),
})
# print(li_value)
filter_jlp.append({
"key": "datafl-sc",
"name": "类型",
"value": li_value
})
lis = html.xpath('//*[@id="nianfen"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datanf')),
})
# print(li_value)
filter_jlp.append({
"key": "datanf-year",
"name": "年份",
"value": li_value
})
lis = html.xpath('//*[@id="zimu"]/li')
li_value = []
for li in lis:
li_value.append({
'n': ''.join(li.xpath('./span//text()')),
'v': ''.join(li.xpath('@datazm')),
})
# print(li_value)
filter_jlp.append({
"key": "dataszm-letter",
"name": "首字母",
"value": li_value
})
print(filter_jlp)
ext_file_dict = {
"特别节目": filter_tbjm,
"纪录片": filter_jlp,
}
# print(json.dumps(ext_file_dict,ensure_ascii=False,indent=4))
with open(ext_file, mode='w+', encoding='utf-8') as f:
# f.write(json.dumps(ext_file_dict,ensure_ascii=False,indent=4))
f.write(json.dumps(ext_file_dict, ensure_ascii=False))
def init(self, extend=""):
def init_file(ext_file):
ext_file = Path(ext_file).as_posix()
# print(f'ext_file:{ext_file}')
if os.path.exists(ext_file):
# print('存在扩展文件')
with open(ext_file, mode='r', encoding='utf-8') as f:
try:
ext_dict = json.loads(f.read())
# print(ext_dict)
self.config['filter'].update(ext_dict)
except Exception as e:
print(f'更新扩展筛选条件发生错误:{e}')
print("============依赖列表:{0}============".format(extend))
ext = self.extend
print("============ext:{0}============".format(ext))
if isinstance(ext, str) and ext:
if ext.startswith('./'):
ext_file = os.path.join(os.path.dirname(__file__), ext)
init_file(ext_file)
elif ext.startswith('http'):
try:
r = self.fetch(ext)
self.config['filter'].update(r.json())
except Exception as e:
print(f'更新扩展筛选条件发生错误:{e}')
elif not ext.startswith('./') and not ext.startswith('http'):
ext_file = os.path.join(os.path.dirname(__file__), './' + ext + '.json')
init_file(ext_file)
# ==================== 栏目大全加载年月筛选 ======================
lanmu_list = self.config['filter']['栏目大全']
lanmu_keys_list = [lanmu['key'] for lanmu in lanmu_list]
if 'year' not in lanmu_keys_list:
currentYear = datetime.date.today().year
yearList = [{"n": "全部", "v": ""}]
for year in range(currentYear, currentYear - 10, -1):
yearList.append({"n": year, "v": year})
yearDict = {"key": "year", "name": "年份", "value": yearList}
lanmu_list.append(yearDict)
if 'month' not in lanmu_keys_list:
monthList = [{"n": "全部", "v": ""}]
for month in range(1, 13):
text = str(month).rjust(2, '0')
monthList.append({"n": text, "v": text})
monthDict = {"key": "month", "name": "月份", "value": monthList}
lanmu_list.append(monthDict)
# 装载模块,这里只要一个就够了
if isinstance(extend, list):
for lib in extend:
if '.Spider' in str(type(lib)):
self.module = lib
break
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
result = {}
cateManual = {
"4K专区": "4K专区",
"栏目大全": "栏目大全",
"特别节目": "特别节目",
"纪录片": "纪录片",
"电视剧": "电视剧",
"动画片": "动画片",
"频道直播": "频道直播",
}
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': []
}
if self.module:
result = self.module.homeVideoContent()
return result
def categoryContent(self, tid, pg, filter, extend):
result = {}
month = "" # 月
year = "" # 年
area = '' # 地区
channel = '' # 频道
datafl = '' # 类型
letter = '' # 字母
year_prefix = '' # 栏目大全的年月筛选过滤
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']
year = extend.get('year') or ''
month = extend.get('month') or ''
if year:
year_prefix = year + month
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
elif tid == '4K专区':
cid = 'CHAL1558416868484111'
url = 'https://api.cntv.cn/NewVideo/getLastVideoList4K?serviceId=cctv4k&cid={0}&p={1}&n={2}&t=json&cb=ko'.format(
cid, pg, pagecount
)
elif tid == '频道直播':
url = 'https://tv.cctv.com/epg/index.shtml'
else:
url = 'https://tv.cctv.com/epg/index.shtml'
videos = []
htmlText = self.fetch(url).text
if tid == '栏目大全':
index = htmlText.rfind(');')
if index > -1:
htmlText = htmlText[3:index]
videos = self.get_list1(html=htmlText, tid=tid, year_prefix=year_prefix)
elif tid == '4K专区':
index = htmlText.rfind(');')
if index > -1:
htmlText = htmlText[3:index]
videos = self.get_list_4k(html=htmlText, tid=tid)
elif tid == '频道直播':
html = self.html(htmlText)
lis = html.xpath('//*[@id="jiemudan01"]//div[contains(@class,"channel_con")]//ul/li')
for li in lis:
vid = ''.join(li.xpath('./img/@title'))
pic = ''.join(li.xpath('./img/@src'))
pic = self.urljoin('https://tv.cctv.com/epg/index.shtml', pic)
videos.append({
'vod_id': '||'.join([tid, vid, f'https://tv.cctv.com/live/{vid}/', pic]),
'vod_name': vid,
'vod_pic': pic,
'vod_mark': '',
})
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 = {}
year_prefix = ''
did = array[0]
if '$$$' in did:
year_prefix = did.split('$$$')[0]
did = did.split('$$$')[1]
aid = did.split('||')
tid = aid[0]
title = aid[1]
lastVideo = aid[2]
logo = aid[3]
if tid == '频道直播':
vod = {
"vod_id": did,
"vod_name": title.replace(' ', ''),
"vod_pic": logo,
"vod_content": f'频道{title}正在直播中',
"vod_play_from": '道长在线直播',
"vod_play_url": f'在线观看${title}||{lastVideo}',
}
result = {'list': [vod]}
return result
id = aid[4]
vod_year = aid[5]
actors = aid[6] if len(aid) > 6 else ''
brief = aid[7] if len(aid) > 7 else '' # get请求最长255,这个描述会有可能直接被干没了。
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)
htmlTxt = self.fetch(lastUrl).text
topicId = json.loads(htmlTxt)['ctid']
url = 'https://api.cntv.cn/NewVideo/getVideoListByColumn'
# params = {
# 'p': '1',
# 'n': '100',
# 't': 'json',
# 'mode': '0',
# 'sort': 'desc',
# 'serviceId': 'tvcctv',
# 'd': year_prefix,
# 'id': topicId
# }
# htmlTxt = self.fetch(url,data=params).text
Url = "{0}?id={1}&d=&p=1&n=100&sort=desc&mode=0&serviceId=tvcctv&t=json&d={2}".format(
url, topicId, year_prefix)
elif tid == "4K专区":
Url = 'https://api.cntv.cn/NewVideo/getVideoListByAlbumIdNew?id={0}&serviceId=cctv4k&p=1&n=100&mode=0&pub=1'.format(
id)
print(Url)
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)
htmlTxt = self.fetch(Url).text
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)
htmlTxt = self.fetch(lastVideo).text
if tid == "电视剧" or tid == "纪录片" or tid == "4K专区":
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": did,
"vod_name": title.replace(' ', ''),
"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, pg=1):
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)
htmlTxt = self.fetch(Url).text
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)
elif flag == '道长在线直播':
# _url = id
title = id.split('||')[0] # 获取标题
_url = f'https://vdn.live.cntv.cn/api2/liveHtml5.do?channel=pc://cctv_p2p_hd{title}&channel_id={title}'
htmlTxt = self.fetch(_url).text
# print(htmlTxt)
vdata = self.regStr(htmlTxt, "var .*?=.*?'(.*?)';")
vdata = self.str2json(vdata)
print(vdata)
url = vdata['hls_url']['hls1']
print(url)
url = self.fixm3u8_url(url)
else:
try:
# htmlTxt = self.webReadFile(urlStr=id, header=self.header)
htmlTxt = self.fetch(id).text
guid = self.get_RegexGetText(Text=htmlTxt, 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
# 分类抓取地址:
# 栏目大全:https://tv.cctv.com/lm/index.shtml?spm=C28340.Pu9TN9YUsfNZ.E2PQtIunpEaz.24
# 电视剧:https://tv.cctv.com/yxg/index.shtml?spm=C28340.PlFTqGe6Zk8M.E2PQtIunpEaz.65#datacid=dsj&datafl=&datadq=&fc=%E7%94%B5%E8%A7%86%E5%89%A7&datanf=&dataszm=
# 动画片:https://tv.cctv.com/yxg/index.shtml?spm=C28340.PlFTqGe6Zk8M.E2PQtIunpEaz.65#datacid=dhp&datafl=&datadq=&fc=%E5%8A%A8%E7%94%BB%E7%89%87&dataszm=
# 记录片:https://tv.cctv.com/yxg/index.shtml?spm=C28340.PlFTqGe6Zk8M.E2PQtIunpEaz.65#datacid=jlp&datapd=&datafl=&fc=%E7%BA%AA%E5%BD%95%E7%89%87&datanf=&dataszm=
# 特别节目:https://tv.cctv.com/yxg/index.shtml?spm=C28340.PlFTqGe6Zk8M.E2PQtIunpEaz.65#datacid=tbjm&datapd=&datafl=&fc=%E7%89%B9%E5%88%AB%E8%8A%82%E7%9B%AE&datajr=&dataszm=
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": "2024", "v": "2024"}, {"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": "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": "2024", "v": "2024"}, {"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": "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"}]},
]
}
}
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, params):
return [200, "video/MP2T", ""]
# -----------------------------------------------自定义函数-----------------------------------------------
# 访问网页
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("&nbsp;", " ")
def hookM3u8(self, url):
"""
https://www.52pojie.cn/thread-1932358-1-1.html
JavaScript:$.ajaxSettings.async = false; var s = ""; let a = $.get(vodh5player.playerList[0].ads.contentSrc); for (var m = 0; m < a.responseText.match(/asp.*?m3u8/g).length; m++) { s = s + "https://hls.cntv.myalicdn.com//asp" + a.responseText.match(/asp.*?m3u8/g)[m].slice(7) + "\n\n" }; var blob = new Blob([s], { type: "text/plain" }); var url = URL.createObjectURL(blob); window.open(url);
@param url:
@return:
"""
url = url or ''
hook1 = lambda x: x.replace('asp/', 'asp//', 1)
hook2 = lambda x: x.replace('hls/', 'hls//', 1)
hook3 = lambda x: x.replace('https://newcntv.qcloudcdn.com', 'https://hls.cntv.myalicdn.com/', 1)
hooks = [hook1, hook2, hook3]
hook = random.choice(hooks)
return hook(url)
# 取m3u8
def get_m3u8(self, urlTxt):
"""
https://blog.csdn.net/panwang666/article/details/135347859
JavaScript:jQuery.getJSON("https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid="+guid,function(result){document.writeln(result.hls_url.link(result.hls_url));});
https://newcntv.qcloudcdn.com/asp/hls/main/0303000a/3/default/3628bb15af644f588dc91ec68425b9ac/main.m3u8?maxbr=2048
@param urlTxt:
@return:
"""
url = "https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid={0}".format(urlTxt)
# htmlTxt = self.webReadFile(urlStr=url, header=self.header)
htmlTxt = self.fetch(url).text
jo = json.loads(htmlTxt)
link = jo['hls_url'].strip()
# print('hls_url:',link)
# 获取域名前缀
urlPrefix = self.get_RegexGetText(Text=link, RegexText='(http[s]?://[a-zA-z0-9.]+)/', Index=1)
# 域名前缀指定替换,然后可以获取到更高质量的视频列表
# /asp/h5e/hls/2000/0303000a/3/default/3628bb15af644f588dc91ec68425b9ac/2000.m3u8
new_link = link.replace(f'{urlPrefix}/asp/hls/', 'https://dh5.cntv.qcloudcdn.com/asp/h5e/hls/').split('?')[0]
# print('new_link:',new_link)
html = self.webReadFile(urlStr=new_link, header=self.header)
content = html.strip()
arr = content.split('\n')
subUrl = arr[-1].split('/')
# hdUrl = urlPrefix + arr[-1]
# subUrl[3] = '2000'
# subUrl[-1] = '2000.m3u8'
# hdUrl = urlPrefix + '/'.join(subUrl)
maxVideo = subUrl[-1].replace('.m3u8', '')
hdUrl = link.replace('main', maxVideo)
hdUrl = hdUrl.replace(urlPrefix, 'https://newcntv.qcloudcdn.com')
hdRsp = self.TestWebPage(urlStr=hdUrl, header=self.header)
if hdRsp == 200:
url = hdUrl.split('?')[0]
url = self.hookM3u8(url)
self.log(f'视频链接: {url}')
else:
url = ''
return url
def fixm3u8_url(self, url):
# 获取域名前缀
urlPrefix = self.get_RegexGetText(Text=url, RegexText='(http[s]?://[a-zA-z0-9.]+)/', Index=1)
# 域名前缀指定替换,然后可以获取到更高质量的视频列表
new_link = url.split('?')[0]
# print(new_link)
html = self.webReadFile(urlStr=new_link, header=self.header)
content = html.strip()
# print(content)
arr = content.split('\n')
subUrl = arr[3] if 'EXT-X-VERSION' in content else arr[2]
hdUrl = self.urljoin(new_link, subUrl).split('?')[0]
# hdUrl = hdUrl.replace(urlPrefix, 'https://newcntv.qcloudcdn.com')
hdRsp = self.TestWebPage(urlStr=hdUrl, header=self.header)
if hdRsp == 200:
url = hdUrl
self.log(f'视频链接: {url}')
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
guids = [tid, title, url, img, id, year, '', brief]
guid = "||".join(guids)
videos.append({
"vod_id": guid,
"vod_name": title,
"vod_pic": img,
"vod_remarks": year
})
return videos
def get_list1(self, html, tid, year_prefix=None):
jRoot = json.loads(html)
videos = []
data = jRoot['response']
if data is None:
return []
jsonList = data['docs']
for vod in jsonList:
id = vod['lastVIDE']['videoSharedCode']
desc = vod['lastVIDE']['videoTitle']
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
guids = [tid, title, url, img, id, year, actors, brief]
guid = "||".join(guids)
# print(vod_id)
videos.append({
"vod_id": year_prefix + '$$$' + guid if year_prefix else guid,
"vod_name": title,
"vod_pic": img,
"vod_remarks": desc.split('')[1].strip() if '' in desc else desc.strip()
})
# 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
guids = [tid, title, url, img, id, year, actors, brief]
guid = "||".join(guids)
# print(vod_id)
videos.append({
"vod_id": guid,
"vod_name": title,
"vod_pic": img,
"vod_remarks": ''
})
return videos
# 4k分类取结果
def get_list_4k(self, html, tid):
jRoot = json.loads(html)
videos = []
data = jRoot['data']
if data is None:
return []
jsonList = data['list']
for vod in jsonList:
vod_remarks = vod['title']
id = vod['id']
vod = vod['last_video']
img = vod['image']
url = vod['url']
title = vod['title']
brief = vod.get('brief') or ''
year = vod.get('year') or ''
actors = vod.get('actors') or ''
if len(url) == 0:
continue
guids = [tid, title, url, img, id, year, actors, brief]
guid = "||".join(guids)
# print(vod_id)
videos.append({
"vod_id": guid,
"vod_name": title,
"vod_pic": img,
"vod_remarks": vod_remarks
})
return videos
if __name__ == '__main__':
from t4.core.loader import t4_spider_init
spider = Spider()
t4_spider_init(spider)
# print(spider.homeContent(True))
# print(spider.homeVideoContent())
# spider.init_api_ext_file()
# url = 'https://api.cntv.cn/lanmu/columnSearch?&fl=&fc=%E6%96%B0%E9%97%BB&cid=&p=1&n=20&serviceId=tvcctv&t=jsonp&cb=Callback'
# url = 'https://api.cntv.cn/lanmu/columnSearch?&fl=&fc=&cid=&p=1&n=20&serviceId=tvcctv&t=json&cb=ko'
# r = spider.fetch(url)
# print(r.text)
# home_content = spider.homeContent(None)
# print(home_content)
cate_content = spider.categoryContent('栏目大全', 1, {'cid': 'n'}, {})
# cate_content = spider.categoryContent('频道直播', 1, None, None)
print(cate_content)
vid = cate_content['list'][0]['vod_id']
print(vid)
detail_content = spider.detailContent([vid])
print(detail_content)
# #
vod_play_from = detail_content['list'][0]['vod_play_from']
vod_play_url = detail_content['list'][0]['vod_play_url']
print(vod_play_from, vod_play_url)
_url = vod_play_url.split('#')[0].split('$')[1]
print(_url)
print('vod_play_from:', vod_play_from, ' vod_play_url:', _url)
play = spider.playerContent(vod_play_from, _url, None)
print(play)
# play = spider.playerContent('道长在线直播', 'cctv1||https://tv.cctv.com/live/cctv1/', None)
# print(play)
+1310
View File
@@ -0,0 +1,1310 @@
Cv='Referer'
Cu='application/dash+xml'
Ct='interaction'
Cs='subtitle'
Cr='mimeType'
Cq='192000'
Cp='media_ft'
Co='media_bangumi'
Cn='stream'
Cm='playurl_info'
Cl='vod_actor'
Ck='\u3000👥 '
Cj='setting'
Ci='message'
Ch='totalrank'
Cg='room_id'
Cf='favorite'
Ce='attention'
Cd='videos'
Cc=' 个人主页'
Cb='vod_pc'
Ca='series'
CZ='oldest'
CY='description'
CX='user_cover'
CW='roomid'
CV='text_small'
CU='watched_show'
CT='live_status'
CS='查看直播细化标签'
CR='https:'
CQ='fav_list'
CP='https://api.bilibili.com/x/web-interface/nav'
CO='bangumi_pay_parse'
CN='bangumi_vip_parse'
CM='raw_cookie_vip'
CL='raw_cookie_line'
CJ='contentType'
CI='header'
CH='mpd'
CG='codecid'
CF='playurl'
CE='season_title'
CD='edgeid'
CC='vod_list'
CB='AllPt'
CA='vod_year'
C9='title_type'
C8='bangumi'
C7='bili_user'
C6='seasons'
C5='sort'
C4='season_status'
C3='all'
C2='special'
C1='悄悄关注'
C0='最近关注'
B_='like_num'
Bz='crname'
By='part'
Bx='play'
Bw='%H:%M:%S'
Bv='module_author'
Bu='isVIP'
Bt='isLogin'
Bs='https://'
Br='utf-8'
Bq='排行榜'
Bp='showLiveFilterTag'
Bo='vodDefaultCodec'
Bn='vodDefaultQn'
Bm='favMode'
Bl='maxHomeVideoContent'
Bf='deadline'
Be='durl'
Bd='csrf'
Bc='codec'
Bb='AllPu'
Ba='🆙 '
BZ='vod_director'
BY='fromep'
BX='@thisepisode@'
BW='预告'
BV='000'
BU='最近访问'
BT='最常访问'
BS='coin'
BR='danmaku'
BQ='稍后再看'
BP='vod_count'
BO='episodes'
BN='view'
BM='stat'
BL=''
BK='archive'
BJ='UP主'
BI='modules'
BH='type_name'
BG=None
BF='历史'
BE='关注'
BD='rankingLis'
BC='tuijianLis'
BB='cateManual'
BA='heartbeatInterval'
B9=float
B7='s_title'
B6='graph_version'
B5='ssid'
B4='pages'
B3='ugc_season'
B2='parse'
B1='特别关注'
B0='正在直播'
A_='[/a]'
Az='"}/]'
Ay='pubdate'
Ax='new_ep'
Aw='index_show'
Av='content'
Au='pic'
At='keyword'
As='登录'
Ar='userid'
Aq='搜索'
Ap='vodDefaultAudio'
Ao='@@@'
An='\n'
Am='like'
Al='desc'
Ak='[a=cr:{"id": "'
Aj='fans'
Ai='up'
Ah='owner'
Ag=' 🆙'
Af='mlid'
Ae='收藏'
Ad='直播'
Ac='影视'
Ab=True
Aa=type
AZ='audio'
AY='qn'
AX='format'
AW='vod_content'
AV='redirect_url'
AU='\u3000'
AT='ep'
AS='following'
AR='/'
AQ='4'
AP='User-Agent'
AO='cateLive'
AN='动态'
AM='推荐'
AL='3'
AK=round
AJ=''
AI='this_array'
AH='\\"'
AG='live'
AF='vip'
AE='cookies_dic'
AD='_tmp'
AC='vod_play_url'
AB='vod_play_from'
AA='"'
A9='ss'
A8='season_id'
A7=' '
A6='uname'
A5='face'
A4='cateManualLiveExtra'
A3='热门'
A2=''
A1='tid'
A0='2'
z=list
w='$'
v='cid'
u='result'
t='id'
s='mid'
r='cateManualLive'
q='order'
p='video'
o='epid'
n='duration'
m='av'
l='filter'
k='type'
j='users'
i='$$$'
h='cover'
g='limit'
f='pagecount'
e='master'
d=dict
c='total'
b='url'
a='page'
Z='page_size'
Y='vod_remarks'
W='key'
V='1'
U=len
T='aid'
S='vod_pic'
R='vod_id'
Q='fake'
P='title'
O='vod_name'
N='_'
M='code'
L='0'
K='value'
J=map
I='#'
H='name'
G='list'
F=int
E='data'
D='n'
C='v'
B=''
A=str
import sys,os,json as Bg,threading as x,hashlib,time as X,random as B8
from base.spider import Spider
from requests import session as Bh,utils as Bi,head
from requests.adapters import HTTPAdapter as Cw,Retry
from concurrent.futures import ThreadPoolExecutor as Cx,as_completed as Bj
from functools import reduce
from urllib.parse import quote as CK,urlencode as Bk
sys.path.append('..')
y,Cy=os.path.split(os.path.abspath(__file__))
if y.startswith('/data/'):y=os.path.abspath(os.path.join(y,'..'));y=os.path.abspath(os.path.join(y,'..'));y=f"{y}/files"
sys.path.append(y)
class Spider(Spider):
defaultConfig={'currentVersion':'20240815_1',CL:B,CM:B,Bl:AL,Bm:L,Z:12,BA:'15',Bn:'80',Bo:'7',Ap:'30280',CN:Ab,CO:Ab,Bp:L,BB:[AM,Ac,Ad,AN,Ae,BE,BF,Aq],BC:[A3,Bq,'每周必看','入站必刷','番剧时间表','国创时间表'],BD:['动画','音乐','舞蹈','游戏','鬼畜','知识','科技','运动','生活','美食','动物','汽车','时尚','娱乐',Ac,'原创','新人']};focus_on_up_list=[];focus_on_search_key=[]
def getName(A):return'哔哩哔哩'
def load_config(A):
try:
with open(f"{y}/config.json",encoding=Br)as C:A.userConfig=Bg.load(C)
B=A.userConfig.get(j,{})
if B.get(e)and B[e].get(AE):A.session_master.cookies=Bi.cookiejar_from_dict(B[e][AE]);A.userid=B[e][Ar]
if B.get(Q)and B[Q].get(AE):A.session_fake.cookies=Bi.cookiejar_from_dict(B[Q][AE])
except:A.userConfig={}
A.userConfig={**A.defaultConfig,**A.userConfig}
dump_config_lock=x.Lock()
def dump_config(A):
F=[j,AO,r,A4];C={}
for(B,D)in A.userConfig.items():
E=A.defaultConfig.get(B)
if E!=BG and D!=E or B in F:C[B]=D
A.dump_config_lock.acquire()
with open(f"{y}/config.json",'w',encoding=Br)as G:H=Bg.dumps(C,indent=1,ensure_ascii=False);G.write(H)
A.dump_config_lock.release()
pool=Cx(max_workers=8);task_pool=[]
def homeContent(A,filter):
A.pool.submit(A.add_live_filter);A.pool.submit(A.add_search_key);A.pool.submit(A.add_focus_on_up_filter);A.pool.submit(A.get_tuijian_filter);A.pool.submit(A.add_fav_filter);F=[AN,Ae,BE,BF];B=A.userConfig[BB]
if not A.userid and not As in B:B+=[As]
D=[]
for C in B:
if C in F and not A.userid:continue
D.append({BH:C,'type_id':C})
E={'class':D};A.add_focus_on_up_filter_event.wait();A.add_live_filter_event.wait();A.add_fav_filter_event.wait();A.add_search_key_event.wait()
if filter:E['filters']=A.config[l]
A.pool.submit(A.dump_config);return E
userid=csrf=B;session_master=Bh();session_vip=Bh();session_fake=Bh();con=x.Condition();getCookie_event=x.Event();retries=Retry(total=5,backoff_factor=.1);adapter=Cw(max_retries=retries);session_master.mount(Bs,adapter);session_vip.mount(Bs,adapter);session_fake.mount(Bs,adapter)
def getCookie_dosth(B,co):
A=co.strip().split('=',1)
if not'%'in A[1]:A[1]=CK(A[1])
return A
def getCookie(A,_type=e):
D=_type;G=CL
if D==AF:G=CM
G=A.userConfig.get(G);K=A.userConfig.get(j,{});C=K.get(D,{})
if not G and not C:
if D==e:A.getCookie_event.set()
with A.con:A.con.notifyAll()
return
I=C.get(AE,{})
if G:I=d(J(A.getCookie_dosth,G.split(';')))
L=Bi.cookiejar_from_dict(I);N=CP;O=A.fetch(N,headers=A.header,cookies=L);H=Bg.loads(O.text);C[Bt]=0
if H[M]==0:
C[Bt]=1;C[Ar]=H[E][s];C[A5]=H[E][A5];C[A6]=H[E][A6];C[AE]=I;C[Bu]=F(H[E]['vipStatus'])
if D==e:A.session_master.cookies=L;A.userid=C[Ar];A.csrf=I['bili_jct']
if C[Bu]:A.session_vip.cookies=L
else:A.userid=B
K[D]=C
with A.con:
if U(C)>1:A.userConfig.update({j:K})
if D==e:A.getCookie_event.set()
getFakeCookie_event=x.Event()
def getFakeCookie(A,fromSearch=BG):
if A.session_fake.cookies:A.getFakeCookie_event.set()
C={};C[AP]=A.header[AP];B=A.fetch('https://space.bilibili.com/2/video',headers=C);A.session_fake.cookies=B.cookies;A.getFakeCookie_event.set()
with A.con:D=A.userConfig.get(j,{});D[Q]={AE:d(B.cookies)};A.userConfig.update({j:D})
if not fromSearch:
A.getCookie_event.wait()
if not A.session_master.cookies:A.session_master.cookies=B.cookies
add_fav_filter_event=x.Event()
def add_fav_filter(B):
N=B.userConfig.get(j,{})
if N.get(e)and N[e].get(Ar):F=B.userConfig[j][e][Ar]
else:B.getCookie_event.wait();F=B.userid
I=[]
if F:
Q='https://api.bilibili.com/x/v3/fav/folder/created/list-all?up_mid=%s&jsonp=jsonp'%A(F);L=B._get_sth(Q).json()
if L[M]==0 and L.get(E):R=L[E].get(G);I=z(J(lambda x:{D:B.cleanCharacters(x[P].strip()),C:x[t]},R))
S=[{D:'追番',C:V},{D:'追剧',C:A0}];O=B.config[l].get(Ae)
if O:O.insert(0,{W:Af,H:'分区',K:S+I})
B.add_fav_filter_event.set();B.userConfig[CQ]=I
add_focus_on_up_filter_event=x.Event()
def add_focus_on_up_filter(B):
F=B.focus_on_up_list
if not B.session_master.cookies:B.getCookie_event.wait()
L=z(J(lambda x:x[C],F))
if B.session_master.cookies:
N='https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=video&page=1';G=B._get_sth(N).json()
if G[M]==0 and G.get(E):
O=G[E].get('items',[])
for I in J(lambda x:{D:x[BI][Bv][H],C:A(x[BI][Bv][s])},O):
if not I in F and not I[C]in L:F.append(I)
P=[{D:'登录与设置',C:As}];F+=P;B.config[l][AN]=Q=[B.config[l].get(AN,[])[-1]];Q.insert(0,{W:s,H:BJ,K:F});B.add_focus_on_up_filter_event.set()
def get_live_parent_area_list(O,parent_area):B=parent_area;E=B[H];id=A(B[t]);F=B[G];I=z(J(lambda area:{D:area[H],C:A(area['parent_id'])+N+A(area[t])},F));L={W:A1,H:E,K:I};M={t:id+'_0',K:L};return E,M
def get_live_list(A):
C='https://api.live.bilibili.com/xlive/web-interface/v1/index/getWebAreaList?source_id=2';B=A._get_sth(C,Q).json()
if B[M]==0:D=B[E][E];A.userConfig[AO]=d(J(A.get_live_parent_area_list,D))
return A.userConfig[AO]
def set_default_cateManualLive(A):
B=[{D:AM,C:AM}]
for E in A.userConfig[AO]:F={D:E,C:A.userConfig[AO][E][t]};B.append(F)
A.defaultConfig[r]=B;return B
add_live_filter_event=x.Event()
def add_live_filter(A):
C=A.userConfig.get(AO,{});G=A.pool.submit(A.get_live_list)
if not C:C=G.result()
I=A.pool.submit(A.set_default_cateManualLive);A.config[l][Ad]=D=[];B=A.userConfig.get(r,[])
if not B:B=I.result()
if B:J={W:A1,H:'分区',K:B};D.append(J)
if F(A.userConfig[Bp]):
for E in C.values():
if U(E[K][K])>1:D.append(E[K])
A.add_live_filter_event.set()
add_search_key_event=x.Event()
def add_search_key(A):
B=A.focus_on_search_key;L='https://api.bilibili.com/x/web-interface/search/square?limit=10&platform=web';F=A._get_sth(L,Q).json();P={}
if F[M]==0:N=F[E]['trending'].get(G,[]);B+=z(J(lambda x:x[At],N))
I={W:At,H:'搜索词',K:[]};I[K]=z(J(lambda i:{D:i,C:i},B));A.config[l][Aq]=O=A.config[l][Aq][-3:];O.insert(0,I);A.add_search_key_event.set()
def get_tuijian_filter(E):
I={'番剧时间表':'10001','国创时间表':'10004',Bq:L,'动画':V,'音乐':AL,'舞蹈':'129','游戏':AQ,'鬼畜':'119','知识':'36','科技':'188','运动':'234','生活':'160','美食':'211','动物':'217','汽车':'223','时尚':'155','娱乐':'5',Ac:'181','原创':'origin','新人':'rookie'};J=[{D:BC,C:'分区'},{D:BD,C:Bq}];E.config[l][AM]=M=[]
for F in J:
G={W:A1,H:F[C],K:[]};N=E.userConfig.get(F[D],[])
for A in N:
B=I.get(A)
if not B:B=A
O={D:A,C:B};G[K].append(O)
M.append(G)
def __init__(A):A.load_config();A.pool.submit(A.getCookie);A.pool.submit(A.getFakeCookie);A.pool.submit(A.getCookie,AF);B=AK(X.time());C=X.gmtime(B).tm_hour;A.pool.submit(A.get_wbiKey,C)
def init(A,extend=B):print('============{0}============'.format(extend))
def isVideoFormat(A,url):0
def manualVideoCheck(A):0
def destroy(A):0
def format_img(B,img):
A=img;A+='@672w_378h_1c.webp'
if not A.startswith('http'):A=CR+A
return A
def pagination(A,array,pg):B=A.userConfig[Z]*F(pg);C=B-A.userConfig[Z];return array[C:B]
def zh(D,num):
C=num
if F(C)>=100000000:B=AK(B9(C)/B9(100000000),1);B=A(B)+'亿'
elif F(C)>=10000:B=AK(B9(C)/B9(10000),1);B=A(B)+''
else:B=A(C)
return B
def second_to_time(D,a):
a=F(a)
if a<3600:C=X.strftime('%M:%S',X.gmtime(a))
else:C=X.strftime(Bw,X.gmtime(a))
if A(C).startswith(L):C=A(C).replace(L,B,1)
return C
def str2sec(E,x):
x=A(x)
try:D,B,C=x.strip().split(':');return F(D)*3600+F(B)*60+F(C)
except:B,C=x.strip().split(':');return F(B)*60+F(C)
def find_bangumi_id(C,url):
B=A(url).split(AR)[-1]
if not B:B=A(url).split(AR)[-2]
B=B.split('?')[0];return B
def get_Login_qrcode(H,pg):
N='https://www.bilibili.com/favicon.ico';K='setting_login_';A={}
if F(pg)!=1:return A
D=[{R:'setting_tab&filter',O:'标签与筛选',S:N},{R:'setting_liveExtra',O:CS,S:N}];I='https://passport.bilibili.com/x/passport-login/web/qrcode/generate';J=H._get_sth(I,Q).json()
if J[M]==0:
id=J[E]['qrcode_key'];I=J[E][b];P={e:'主账号',AF:'副账号'};T={0:'未登录',1:'已登录'};U={0:B,1:'👑'};V=H.userConfig.get(j,{})
for(W,X)in P.items():
C=V.get(W)
if C:D.append({R:K+id,O:C[A6],S:H.format_img(C[A5]),Y:U[C[Bu]]+X+A7+T[C[Bt]]})
L={E:I,'quietzone':'208','codepage':'UTF8','quietunit':'px','errorcorrection':'M','size':'small'};D.append({R:K+id,S:'http://jm92swf.s1002.xrea.com/?'+Bk(L)});D.append({R:K+id,S:'https://bili.ming1992.xyz/API/QRCode?'+Bk(L)})
A[G]=D;A[a]=1;A[f]=1;A[g]=1;A[c]=1;return A
time_diff1={V:[0,300],A0:[300,900],AL:[900,1800],AQ:[1800,3600],'5':[3600,0x4ee2d6d415b85acef80ffffffff]};time_diff=L;dynamic_offset=B
def get_dynamic(C,pg,mid,order):
if mid==L:
D={}
if F(pg)==1:C.dynamic_offset=B
Q='https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=video&offset=%s&page=%s'%(C.dynamic_offset,pg);J=C._get_sth(Q).json()
if J[M]==0:
C.dynamic_offset=J[E].get('offset');K=[];U=J[E]['items']
for N in U:V=N[BI][Bv][H];I=N[BI]['module_dynamic']['major'][BK];W=A(I[T]).strip();X=C.cleanCharacters(I[P].strip());Z=I[h].strip();b=A(C.second_to_time(C.str2sec(I['duration_text']))).strip()+Ag+A(V).strip();K.append({R:m+W,O:X,S:C.format_img(Z),Y:b})
D[G]=K;D[a]=pg;D[f]=9999;D[g]=99;D[c]=999999
return D
else:return C.get_up_videos(mid=mid,pg=pg,order=order)
def get_found_vod(G,vod):
C=vod;D=C.get(T,B)
if not D:D=C.get(t,B)
E=C.get('goto',B)
if not E or E and E==m:D=m+A(D).strip()
elif E=='ad':return[]
N=C[P].strip();Q=C[Au].strip();U=C.get('is_followed')
if E==AG:
L=C['room_info'];I=B;V=L.get(CT,B)
if V:I='直播中 '
else:return[]
I+='👁'+L[CU][CV]+Ag+C[Ah][H].strip()
else:
K=C.get('rcmd_reason',B)
if K and Aa(K)==d and K.get(Av):
F=' 🔥'+K[Av].strip()
if'人气飙升'in F:F=' 🔥人气飙升'
elif U:F=' 已关注'
else:F=Ag+C[Ah][H].strip()
I=A(G.second_to_time(C[n])).strip()+BL+G.zh(C[BM][BN])+F
M=[{R:D,O:N,S:G.format_img(Q),Y:I}]
for W in J(G.get_found_vod,C.get('others',[])):M.extend(W)
return M
_popSeriesInit=0
def get_found(A,tid,rid,pg):
H=tid;C=pg;D={};K=1
if H==AM:O=A.encrypt_wbi(fresh_type=4,feed_version='V8',brush=1,fresh_idx=C,fresh_idx_1h=C,ps=A.userConfig[Z])[0];B='https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd?'+O;K=99
elif H==A3:B='https://api.bilibili.com/x/web-interface/popular?pn={0}&ps={1}'.format(C,A.userConfig[Z]);K=99
elif H=='入站必刷':B='https://api.bilibili.com/x/web-interface/popular/precious'
elif H=='每周必看':
if F(C)==1:B='https://api.bilibili.com/x/web-interface/popular/series/list';I=A._get_sth(B,Q).json();A._popSeriesInit=F(I[E][G][0]['number'])
P=A._popSeriesInit-F(C)+1;K=A._popSeriesInit;B=f"https://api.bilibili.com/x/web-interface/popular/series/one?number={P}"
else:B='https://api.bilibili.com/x/web-interface/ranking/v2?rid={0}&type={1}'.format(rid,H)
I=A._get_sth(B).json()
if I[M]==0:
N=[];L=I[E].get('item')
if not L:L=I[E][G]
for R in J(A.get_found_vod,L):N.extend(R)
D[G]=N;D[a]=C;D[f]=K;D[g]=99;D[c]=999999
return D
def get_bangumi(D,tid,pg,order,season_status):
X='first_ep';W='first_ep_info';T=order;I=tid;H={}
if T=='追番剧':J='https://api.bilibili.com/x/space/bangumi/follow/list?type={0}&vmid={1}&pn={2}&ps={3}'.format(I,D.userid,pg,D.userConfig[Z]);K=D._get_sth(J).json()
else:
J='https://api.bilibili.com/pgc/season/index/result?type=1&season_type={0}&page={1}&order={2}&season_status={3}&pagesize={4}'.format(I,pg,T,season_status,D.userConfig[Z])
if T==A3:
if I==V:J='https://api.bilibili.com/pgc/web/rank/list?season_type={0}&day=3'.format(I)
else:J='https://api.bilibili.com/pgc/season/rank/web/list?season_type={0}&day=3'.format(I)
K=D._get_sth(J,Q).json()
if K[M]==0:
if E in K:L=K[E][G]
else:L=K[u][G]
if U(L)>D.userConfig[Z]:L=D.pagination(L,pg)
b=[]
for C in L:
e=A(C[A8]).strip();i=C[P];N=C.get('ss_horizontal_cover')
if not N:
if C.get(W)and h in C[W]:N=C[W][h]
elif C.get(X)and h in C[X]:N=C[X][h]
else:N=C[h].strip()
F=C.get(Aw,B)
if not F and C.get(Ax)and C[Ax].get(Aw):F=C[Ax][Aw]
F=F.replace('更新至','🆕');d=C.get(BM)
if d:F=''+D.zh(d.get(BN))+' '+F
b.append({R:A9+e,O:i,S:D.format_img(N),Y:F})
H[G]=b;H[a]=pg;H[f]=9999;H[g]=90;H[c]=999999
return H
def get_timeline(E,tid,pg):
b='pub_index';Z='ep_cover';D={};d='https://api.bilibili.com/pgc/web/timeline/v2?season_type={0}&day_before=2&day_after=4'.format(tid);F=E._get_sth(d,Q).json()
if F[M]==0:
T=[];H=F[u]['latest']
for C in H:I=A(C[A8]).strip();J=C[P].strip();K=C[Z].strip();N='🆕'+C[b]+''+C['follows'].replace('系列',B).replace('追番',B);T.append({R:A9+I,O:J,S:E.format_img(K),Y:N})
V=[];W=F[u]['timeline']
for e in range(U(W)):
H=W[e][BO]
for C in H:
if A(C['published'])==L:I=A(C[A8]).strip();J=A(C[P]).strip();K=A(C[Z]).strip();h=A(X.strftime('%m-%d %H:%M',X.localtime(C['pub_ts'])));N=h+' '+C[b];V.append({R:A9+I,O:J,S:E.format_img(K),Y:N})
D[G]=V+T;D[a]=1;D[f]=1;D[g]=90;D[c]=999999
return D
def get_live(F,pg,parent_area_id,area_id):
N='recommend_room_list';I=parent_area_id;C={}
if I==AM:H='https://api.live.bilibili.com/xlive/web-interface/v1/webMain/getList?platform=web&page=%s'%pg;J=F._get_sth(H).json()
else:
H='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'%(I,area_id,pg)
if I==A3:H='https://api.live.bilibili.com/room/v1/room/get_user_recommend?page=%s&page_size=%s'%(pg,F.userConfig[Z])
J=F._get_sth(H,Q).json()
if J[M]==0:
L=[];B=J[E]
if N in B:B=B[N]
elif G in B:B=B[G]
for D in B:
T=A(D[CW]).strip();U=F.cleanCharacters(D[P]);K=D.get(CX)
if not K:K=D.get(h)
V='👁'+D[CU][CV].strip()+Ag+D[A6].strip();L.append({R:T,O:U,S:F.format_img(K),Y:V})
C[G]=L;C[a]=pg;C[f]=9999;C[g]=99;C[c]=999999
return C
def get_up_series(I,mid,pg):
C={};N='https://api.bilibili.com/x/polymer/web-space/seasons_series_list?mid=%s&page_num=%s&page_size=%s'%(mid,pg,I.userConfig[Z]);D=I._get_sth(N,Q).json()
if D[M]==0:
K=[];D=D[E]['items_lists'];P=D['seasons_list']+D['series_list']
for L in P:
F=L.get('meta');J=A(F.get(A8,B)).strip()
if J:J=m+A(L['recent_aids'][0])
else:J='list_'+A(mid)+'_series_'+A(F.get('series_id',B)).strip()
T=I.cleanCharacters(F[H]);U=F.get(h);V=F.get(CY,B).strip();K.append({R:J,O:T,S:I.format_img(U),Y:V})
C[G]=K;C[a]=pg;C[f]=9999;C[g]=99;C[c]=999999
return C
get_up_videos_result=d()
def get_up_videos(C,mid,pg,order):
L=order;K=pg;D=mid;I={}
if not D in C.up_info or F(K)==1:C.get_up_info_event.clear();C.pool.submit(C.get_up_info,D)
V=W=B
if L==CZ:W=L;L=Ay
elif L=='quicksearch':
V='投稿: ';J=C.get_up_videos_result.get(D,[])
if J:I[G]=J;return I
elif L==Ca:return C.get_up_series(mid=D,pg=K)
X=K
if W:C.get_up_info_event.wait();X=C.up_info[D][Cb]-F(K)+1
h=C.encrypt_wbi(mid=D,pn=X,ps=C.userConfig[Z],order=L)[0];i=f"https://api.bilibili.com/x/space/wbi/arc/search?{h}";b=C._get_sth(i,Q).json();J=[]
if b[M]==0:
j=b[E][G]['vlist']
for N in j:
k=A(N[T]).strip();l=C.cleanCharacters(N[P].strip());n=N[Au].strip();d=C.second_to_time(C.str2sec(A(N['length']).strip()))+BL+C.zh(N[Bx])
if not V:d+=' 💬'+C.zh(N['video_review'])
J.append({R:m+k,O:V+l,S:C.format_img(n),Y:d})
if W:J.reverse()
if F(K)==1:
C.get_up_info_event.wait();U=C.up_info[D];e=U[H]+Cc
if V:e='UP: '+U[H]
o={R:Ai+A(D),O:e,S:C.format_img(U[A5]),Y:U[AS]+' 👥'+U[Aj]+' 🎬'+A(U[BP])};J.insert(0,o)
if V:C.get_up_videos_result[D]=J
I[G]=J;I[a]=K;I[f]=99;I[g]=99;I[c]=999999
return I
history_view_at=0
def get_history(D,type,pg):
W='progress';H={}
if F(pg)==1:D.history_view_at=0
X='https://api.bilibili.com/x/web-interface/history/cursor?ps={0}&view_at={1}&type={2}'.format(D.userConfig[Z],D.history_view_at,type)
if type==BQ:X='https://api.bilibili.com/x/v2/history/toview'
U=D._get_sth(X).json()
if U[M]==0:
b=[];V=U[E].get(G,[])
if type==BQ:V=D.pagination(V,pg)
else:D.history_view_at=U[E]['cursor']['view_at']
for C in V:
I=C.get('history',B)
if I:J=I['business'];K=A(I['oid']).strip();d=C[h].strip();Q=A(I[By]).strip()
else:J=BK;K=A(C[T]).strip();d=C[Au].strip();Q=A(C[a][By]).strip()
if J=='article':continue
elif J=='pgc':K=AT+A(I[o]);e=C[c];Q=C.get('show_title')
elif J==BK:K=m+K;e=C[Cd]
i=D.cleanCharacters(C[P])
if J==AG:j=C.get('badge',B);N=j+Ag+C['author_name'].strip()
else:
if A(C[W])=='-1':N='已看完'
elif A(C[W])==L:N='刚开始看'
else:k=A(D.second_to_time(C[W])).strip();N='看到 '+k
if not e in[0,1]and Q:N+=' ('+A(Q)+')'
b.append({R:K,O:i,S:D.format_img(d),Y:N})
H[G]=b;H[a]=pg;H[f]=9999;H[g]=90;H[c]=999999
return H
def get_fav_detail(C,pg,mlid,order):
I='cnt_info';D={};J='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);F=C._get_sth(J).json()
if F[M]==0:
H=[];K=F[E].get('medias',[])
for B in K:
if B.get(k)in[2]and B.get(P)!='已失效视频':L=A(B[t]).strip();N=C.cleanCharacters(B[P]);Q=B[h].strip();T=A(C.second_to_time(B[n])).strip()+BL+C.zh(B[I][Bx])+'\u3000💬'+C.zh(B[I][BR]);H.append({R:m+L+'_mlid'+A(mlid),O:N,S:C.format_img(Q),Y:T})
D[G]=H;D[a]=pg;D[f]=9999;D[g]=99;D[c]=999999
return D
def get_up_videoNum(B,mid):
C={};I=f"http://api.bilibili.com/x/space/navnum?mid={mid}";D=B._get_sth(I,Q).json()
if D[M]==0:
C[BP]=A(D[E][p]).strip();G=divmod(F(C[BP]),B.userConfig[Z]);H=G[0]
if G[1]!=0:H+=1
C[Cb]=H
B.up_info[mid].update(C);B.get_up_info_event.set()
get_up_info_event=x.Event();up_info={}
def get_up_info(B,mid,data={}):
J='Official';D=data;C=mid;B.up_info[C]=A=B.up_info.get(C,{});B.pool.submit(B.get_up_videoNum,C)
if not D:
K=f"https://api.bilibili.com/x/web-interface/card?mid={C}";G=B._get_sth(K).json()
if G[M]==0:D=G[E]
else:return A
F=D['card'];A[AS]='未关注'
if D[AS]:A[AS]='已关注'
A[H]=I=B.cleanCharacters(F[H]);A[Bz]=Ak+C+'_pubdate_getupvideos","name": "'+I.replace(AA,AH)+Az+I+A_;A[A5]=F[A5];A[Aj]=B.zh(F[Aj]);A[B_]=B.zh(D[B_]);A[Al]=F[J][Al]+AU+F[J][P];return A
def get_vod_relation(F,query):
G=f"https://api.bilibili.com/x/web-interface/archive/relation?{query}";A=F._get_sth(G).json();B=[]
if A[M]==0:
A=A[E]
if A[Ce]:B.append('已关注')
else:B.append('未关注')
C=[]
if A[Cf]:C.append('')
if A[Am]:C.append('👍')
D=A.get(BS)
if D:C.append('💰'*D)
if U(C)==3:B.append('👍💰⭐')
else:B.extend(C)
if A['dislike']:B.append('👎')
if A['season_fav']:B.append('已订阅合集')
return B
def get_follow(I,pg,sort):
J=pg;D=sort;K={}
if D==BT:L='https://api.bilibili.com/x/relation/followings?vmid={0}&pn={1}&ps=10&order=desc&order_type=attention'.format(I.userid,J)
elif D==C0:L='https://api.bilibili.com/x/relation/followings?vmid={0}&pn={1}&ps=10&order=desc&order_type='.format(I.userid,J)
elif D==B0:L='https://api.live.bilibili.com/xlive/web-ucenter/v1/xfetter/GetWebList?page={0}&page_size=10'.format(J)
elif D==BU:L='https://api.bilibili.com/x/v2/history?pn={0}&ps=15'.format(J)
elif D==B1:L='https://api.bilibili.com/x/relation/tag?mid={0}&tagid=-10&pn={1}&ps=10'.format(I.userid,J)
elif D==C1:L='https://api.bilibili.com/x/relation/whispers?pn={0}&ps=10'.format(J)
else:L='https://api.bilibili.com/x/relation/followers?vmid={0}&pn={1}&ps=10&order=desc&order_type=attention'.format(I.userid,J)
Q=I._get_sth(L).json()
if Q[M]!=0:return K
if D==B1 or D==BU:T=Q[E]
elif D==B0:T=Q[E]['rooms']
else:T=Q[E][G]
if F(J)==1:I.recently_up_list=[]
X=[]
for C in T:
U=B
if D==BU:
N=Ai+A(C[Ah][s])
if N in I.recently_up_list:continue
I.recently_up_list.append(N);V=A(C[Ah][H]).strip();W=A(C[Ah][A5]).strip()
elif D==B0:N=A(C[Cg]);V=I.cleanCharacters(C[P]);W=C['cover_from_user'].strip();U=C[A6].strip()
else:N=Ai+A(C[s]);V=A(C[A6]).strip();W=A(C[A5]).strip()
if C2 in C and C[C2]==1:U=B1
X.append({R:N,O:V,S:I.format_img(W),Y:U})
K[G]=X;K[a]=J;K[f]=9999;K[g]=99;K[c]=999999;return K
def homeVideoContent(A):B=A.get_found(rid=L,tid=C3,pg=1)[G][:F(A.userConfig[Bl])];C={G:B};return C
def categoryContent(I,tid,pg,filter,extend):
u='_clicklink';O=pg;H=extend;D=tid;I.pool.submit(I.stop_heartbeat)
if D==AM:
if A1 in H:D=H[A1]
if D.isdigit():
D=F(D)
if D>10000:D-=10000;return I.get_timeline(tid=D,pg=O)
b=D;D=C3;return I.get_found(tid=D,rid=b,pg=O)
b=L;return I.get_found(tid=D,rid=b,pg=O)
elif D==Ac:
D=V;P=A3;d='-1'
if A1 in H:D=H[A1]
if q in H:P=H[q]
if C4 in H:
if P==A3:P=A0
d=H[C4]
return I.get_bangumi(D,O,P,d)
elif D==AN:
R=L;P=Ay
if s in H:R=H[s]
if q in H:P=H[q]
if R==L and not I.userid or R==As:return I.get_Login_qrcode(O)
return I.get_dynamic(pg=O,mid=R,order=P)
elif D==Ad:
D=A3;h=L
if A1 in H:D=H[A1]
if N in D:i=D.split(N);D=i[0];h=i[1]
return I.get_live(pg=O,parent_area_id=D,area_id=h)
elif D==As:return I.get_Login_qrcode(O)
elif D==BE:
j=BT
if C5 in H:j=H[C5]
return I.get_follow(O,j)
elif D==Ae:
S=A(I.userConfig[Bm])
if Af in H:S=H[Af]
m=I.config[l].get(Ae)
if S in[V,A0]:return I.get_bangumi(tid=S,pg=O,order='追番剧',season_status=B)
elif S==L and m:
for Q in m:
if Q[W]==Af:
if U(Q[K])>1:S=Q[K][2][C]
break
P='mtime'
if q in H:P=H[q]
return I.get_fav_detail(pg=O,mlid=S,order=P)
elif D==BF:
type=C3
if k in H:type=H[k]
if type==BJ:return I.get_follow(pg=O,sort=BU)
return I.get_history(type=type,pg=O)
elif D.endswith('_getbangumiseasons'):
if F(O)==1:return{G:I.detailContent_args[D.split(N)[0]][C6]}
elif D.endswith('_getupvideos'):R,P,v=D.split(N);return I.get_up_videos(pg=O,mid=R,order=P)
elif D.endswith('_related'):
w,v=D.split(N);x=f"https://api.bilibili.com/x/web-interface/archive/related?aid={w}";o=I._get_sth(x,e).json();T={}
if o.get(M)==0:
r=[]
for y in J(I.get_found_vod,o[E]):r.extend(y)
T[G]=r;T[a]=1;T[f]=1;T[g]=99;T[c]=40
return T
elif D.endswith(u):
X=D.replace(u,B);Y=L
if n in H:Y=H[n]
return I.get_search_content(key=X,pg=O,duration_diff=Y,order=B,type=p,ps=I.userConfig[Z])
else:
Y=L
if n in H:Y=H[n]
type=p
if k in H:type=H[k]
P=Ch
if q in H:P=H[q]
X=A(I.search_key);t=I.config[l].get(Aq)
if not X and t:
for Q in t:
if Q[W]==At:
if U(Q[K])>0:X=Q[K][0][C]
break
if At in H:X=H[At]
return I.get_search_content(key=X,pg=O,duration_diff=Y,order=P,type=type,ps=I.userConfig[Z])
def get_search_content(D,key,pg,duration_diff,order,type,ps):
I=pg;L=BG
if not A(I).isdigit():L=I;I=1
X=D.encrypt_wbi(keyword=key,page=I,duration=duration_diff,order=order,search_type=type,page_size=ps)[0];Z=f"https://api.bilibili.com/x/web-interface/wbi/search/type?{X}";V=D._get_sth(Z,Q).json();F={}
if V.get(M)==0 and u in V[E]:
W=[];J=V[E].get(u)
if J and type==AG:J=J.get('live_room')
if not J:return F
for C in J:
if type!=C[k]:continue
H=B
if type==C7:N=Ai+A(C[s]).strip();U=C['upic'].strip();K='👥'+D.zh(C[Aj])+' 🎬'+D.zh(C[Cd]);H=C[A6]
elif type==AG:N=A(C[CW]).strip();U=C[h].strip();K='👁'+D.zh(C['online'])+Ag+C[A6]
elif'media'in type:N=A9+A(C[A8]).strip();U=C[h].strip();K=A(C[Aw]).strip().replace('更新至','🆕')
else:
N=m+A(C[T]).strip();U=C[Au].strip();K=A(D.second_to_time(D.str2sec(C[n]))).strip()+BL+D.zh(C[Bx])
if L==BG:K+=' 💬'+D.zh(C[BR])
if not H:H=D.cleanCharacters(C[P])
if L:H=L+H
W.append({R:N,O:H,S:D.format_img(U),Y:K})
F[G]=W;F[a]=I;F[f]=9999;F[g]=99;F[c]=999999
return F
def cleanSpace(C,s):return A(s).replace(An,B).replace('\t',B).replace('\r',B).replace(A7,B)
def cleanCharacters(C,s):return A(s).replace('<em class="keyword">',B).replace('</em>',B).replace('&quot;',AA).replace('&amp;','&')
def get_normal_episodes(L,episode):
D=episode;M=D.get(AI);C=L.detailContent_args
if M:C=C[M]
N=D.get(T,B)
if not N:N=C[T]
S=D.get(v,B);H=D.get(P,B)
if not H:H=D.get(By,B)
J=D.get(n,B)
if not J:
X=D.get(a,B)
if X:J=X[n]
E=G=Y=U=B;O=D.get('ep_id',B)
if AV in D and C8 in D[AV]:O=L.find_bangumi_id(D[AV])
if O:
if J and A(J).endswith(BV):J=F(J/1000)
if H.isdigit():H=''+H+C[C9]
E=D.get('badge',B)
if not L.session_vip.cookies and E=='会员'and L.userConfig[CN]or E=='付费'and L.userConfig[CO]:C[B2]=U=V
if L.session_vip.cookies:E=E.replace('会员',B)
if E==BW:E=E.replace(BW,B);Y=V
if E:E=''+E+''
G=D.get('long_title',B)
if not E and G:G=A7+G
Q=H+E+G;Q=Q.replace(I,A2).replace(w,AJ)
if B3 in C:
if Q in C[B3]:Q+=f"_av{N}"
else:C[B3].append(Q)
K=f"{Q}${N}_{S}_{O}_{J}_"
if M:K+='@'+M
if f"{N}_{S}"in C:W=C[B4];W[0]=K+BX;K=I.join(W);C[B4]=W
Z=C.get(o,B)
if Z==AT+A(O):C[BY]=K
b=C.get(B5,B)
if b:
if Y:return K,B
if U:
if G:G='【解析】'+G
H+=G;R=f"{H}${N}_{S}_{O}_{J}_{U}"
if M:R+='@'+M
if Z==AT+A(O):C[BY]=R+I+C[BY]
else:R=K
return K,R
else:return K
def get_ugc_season(D,section,season_title,sec_len,array):
F=season_title;E=section
if sec_len>1:A=F+A7+E[P]
else:A=F
A=A.replace(I,A2).replace(w,AJ);G=E.get(BO);C=I.join(J(D.get_normal_episodes,J(lambda e:D.add_this_array(e,array),G)))
if BX in C:C=C.replace(BX,B);return A,C,0
return A,C
def get_vodReply(K,oid,pg=B):
W='member';V='rpid';X=K.encrypt_wbi(type=1,ps=30,oid=A(oid))[0];Y=f"https://api.bilibili.com/x/v2/reply/wbi/main?{X}";L=K._get_sth(Y).json();O=B
if L[M]==0:
I=L[E].get('replies');Q=L[E].get('top_replies')
if Q and I:I=Q+I
if I:
Z=L[E]['upper'][s];R=[]
for F in I:
a=F[V];J=F[W]['sex']
if J and J=='':J='👧'
else:J='👦'
S=F[s];H=F[W][A6]
if S==Z:H='🆙'+H
b='👍'+K.zh(F[Am]);H=Ak+f'{S}_pubdate_getupvideos","name": "'+H.replace(AA,AH)+Az+b+J+H+A_+'';G=F[Av][Ci].strip()
if'/note-app/'in G:continue
if U(G)>400 or G.count(D)>24:G=K.cleanSpace(G)
c=F[Av].get('jump_url',{})
for(C,N)in c.items():
d=C
if not N.get('app_url_schema')and not N.get('pc_url'):
if C.startswith('https://www.bilibili.com/')or C.startswith('https://b23.tv/'):
C=A(C).split('?')[0].split(AR)
while C[-1]==B:C.pop(-1)
C=C[-1]
if C.startswith(m)or C.startswith('BV')or C.startswith(AT)or C.startswith(A9):a=A(F[V]);T=N[P].replace(AA,AH);e=Ak+C+'_clicklink","name": "'+T+Az+''+T+A_;G=G.replace(d,e)
f=H+G;R.append(f)
O=An.join(R)
return O
def add_this_array(A,e,array):e[AI]=array;return e
detailContent_args={}
def detailContent(H,array):
A8='tag_name';A3='up_info';A1='relation';A0='vodReply';L=array;H.pool.submit(H.stop_heartbeat);L=L[0]
if L.startswith(Cj):
n=L.split(N)
if n[1]=='tab&filter':return H.setting_tab_filter_detailContent()
elif n[1]=='liveExtra':return H.setting_liveExtra_detailContent()
elif n[1]=='login':return H.setting_login_detailContent(n[2])
if L.startswith(G):return H.series_detailContent(L)
if L.isdigit():return H.live_detailContent(L)
if L.startswith(Ai):return H.up_detailContent(L)
H.detailContent_args[L]=K={AI:L,**H.detailContent_args.get(L,{})};AO=K.get(B6)
if AO:return H.interaction_detailContent(K)
f=id=A4=p=B;V=K.get(T);AD=K.get(o)
if V:
L=f"av{V}"
if AD:L=AD
f=1
K['_notfirst']=f
if L.startswith(A9)or L.startswith(AT):return H.ysContent(K)
for d in L.split(N):
if d.startswith(m):id=d.replace(m,B);p=H.encrypt_wbi(aid=id)[0]
elif d.startswith('BV'):id=d;p=H.encrypt_wbi(bvid=d)[0]
elif d.startswith(Af):A4=d.replace(Af,B)
if not A0 in K:K[A0]=H.pool.submit(H.get_vodReply,id)
if not A1 in K:K[A1]=H.pool.submit(H.get_vod_relation,p)
AP=f"https://api.bilibili.com/x/web-interface/wbi/view/detail?{p}";q=H._get_sth(AP,Q).json()
if q[M]!=0:return{}
W=q[E]['View'];AE=W.get(AV,B)
if C8 in AE:K[o]=id=H.find_bangumi_id(AE);return H.ysContent(K)
L=K[AI];Z=A(W[Ah][s]);K[T]=V=A(W.get(T));r=W.get(v)
if not A3 in K:K[A3]=H.pool.submit(H.get_up_info,mid=Z,data=q[E].get('Card'))
AF=H.cleanCharacters(W[P]);AQ=W[Au];j=W[Al].strip();AR=W['tname'];AS=X.strftime('%Y%m%d',X.localtime(W[Ay]));k=W[BM];t=W['rights'].get('is_stein_gate',0);g=[];g.append(''+H.zh(k[BN]));g.append('💬'+H.zh(k[BR]));g.append('👍'+H.zh(k[Am]));g.append('💰'+H.zh(k[BS]));g.append(''+H.zh(k[Cf]));e={R:m+A(V),O:AF,S:AQ,BH:AR,CA:AS};e[Y]=AU.join(g)
if f"{V}_{r}"in K:K.pop(f"{V}_{r}")
A5=W[B4]
if A5:K[B4]=z(J(H.get_normal_episodes,J(lambda e:H.add_this_array(e,L),A5)))
a=[];c=[];u=[];A6=[];h=W.get(B3)
if h:
K[B3]=[];K[f"{V}_{r}"]=B;AG=h['sections']
for AX in AG:b=H.pool.submit(H.get_ugc_season,AX,h[P],U(AG),L);A6.append(b)
for b in Bj(A6):
if b.result()[-1]==0:
a.insert(0,b.result()[0]);c.insert(0,b.result()[1])
if not I in b.result()[1]:f=1
else:a.append(b.result()[0]);c.append(b.result()[1])
A6.remove(b)
u.append(T)
if not f:u+=[A0,A1,A3,f"{V}_{r}"]
else:
a=['B站']
if t:a[0]='互动视频'
if not h or not f:
if A5:a=[a[0]];AY=I.join(K[B4]).replace(BX,B);c=[AY]
if H.userid:
AZ=f"➕关注${V}_{Z}__1__notplay_follow";Aa=f"➖取关${V}_{Z}__2__notplay_follow";Ab=f"👍点赞${V}_{Z}__1__notplay_like";Ac=f"👍🏻取消点赞${V}_{Z}__2__notplay_like";Ad=f"👍💰投币${V}_{Z}__1__notplay_coin";Ae=f"👍💰💰${V}_{Z}__2__notplay_coin";Ag=f"👍💰⭐三连${V}_{Z}____notplay_triple";A7=[AZ,Ag,Ab,Ad,Ae,Aa,Ac]
if A4:Ao=f"☆取消收藏${V}_{Z}__{A4}_del_notplay_fav";A7.append(Ao)
for x in H.userConfig.get(CQ,[]):Ap=x[D].replace(I,A2).replace(w,AJ);Aq=x[C];x=f"{Ap}${V}_{Z}__{Aq}_add_notplay_fav";A7.append(x)
Ar=I.join(A7);a.insert(1,'做点什么');c.insert(1,Ar)
if t:c[0]='片头$'+c[0].split(w)[1]
e[AB]=i.join(a);e[AC]=i.join(c)
if not h or f:
y=[Ak+A(V)+'_related","name":"'+AF.replace(AA,AH)+'"}/]相关推荐[/a]']
if U(j)<60 and j.count(D)<4:j+=An*F(3-U(j)/29)
y.append(j);As=''.join(sorted(J(lambda x:Ak+x[A8].replace(AA,AH)+'_clicklink","name":"'+x[A8].replace(AA,AH)+Az+A2+x[A8]+A2+A_,q[E].get('Tags',[])),key=U));y.append(As);l=K.get(A3);AK=K.get(A1)
if l and AK:l=l.result();e[BZ]=Ba+l[Bz]+Ck+l[Aj]+AU+AU.join(AK.result())
AL=K.get(A0)
if AL:y.append(AL.result())
e[AW]=An.join(y)
if t:K[CB]=a.copy();K[Bb]=c.copy();K[CC]=e.copy();u+=[T,CB,Bb,CC]
if not h and not t:H.detailContent_args.pop(L)
else:
AM={}
for(AN,At)in K.items():
if AN in u:AM[AN]=At
H.detailContent_args[L]=AM.copy()
Av={G:[e]};return Av
def interaction_detailContent(V,array):
C=array;M=C.get(AI);N=C.get(T);W=C.get(v,0);O=C.get(CD,0);X=C.get(B6);Y=f"https://api.bilibili.com/x/stein/edgeinfo_v2?aid={N}&graph_version={X}&edge_id={O}";F=V._get_sth(Y,Q).json().get(E);R={}
if F:
S=C.get(CB).copy();D=C.get(Bb).copy();H=C.get(CC)
if O:J=A(F[P]).replace(I,A2).replace(w,AJ);D[0]+=f"#{J}${N}_{W}___@{M}"
else:D[0]=D[0].split(I)[0]
C[Bb]=D.copy();Z=F['edges'].get('questions',[]);K=[]
for U in Z:
a=U.get(P,B)
for L in U.get('choices',[]):b=L[t];c=L[v];d=L.get('option',B);J=A7.join([a,d]).replace(I,A2).replace(w,AJ);K.append(f"{J}${b}_{c}_interaction@{M}")
if K:S.insert(1,'选项');D.insert(1,I.join(K))
else:C.pop(CD);C.pop(v)
H[AB]=i.join(S);H[AC]=i.join(D);R[G]=[H]
return R
def series_detailContent(C,array):
U='archives';K=array;L,type,V=K.replace('list_',B).split(N);D=1;M=99;A={R:K,AB:'B站'};S=[]
while Ab:
W='https://api.bilibili.com/x/series/archives?mid=%s&series_id=%s&pn=%s&ps=%s'%(L,V,D,M);X=C._get_sth(W,Q).json();F=X.get(E)
if not A.get(O):A[O]=F[U][0][P]
Y=I.join(J(C.get_normal_episodes,F.get(U)));S.append(Y);Z=F[a][c]
if M*D>=Z:break
D+=1
A[AC]=I.join(S);T=C.up_info[L];A[BZ]=Ba+T[H]+AU+T[AS];b={G:[A]};return b
def up_detailContent(L,array):
F=array.replace(Ai,B);L.get_up_info_event.clear();L.pool.submit(L.get_up_info,F);Q=f"关注$_{F}__1__notplay_follow";R=f"取消关注$_{F}__2__notplay_follow";T=f"特别关注$_{F}__-10_special_notplay_follow";U=f"取消特别关注$_{F}__0_special_notplay_follow";P=[Q,T,R,U];P='做点什么$ $$$'+I.join(P);L.get_up_info_event.wait();E=L.up_info[F];M={O:E[H]+Cc,S:E[A5],BZ:Ba+E[H]+AU+E[AS]+'\u3000UID'+A(F),Y:'👥 '+E[Aj]+'\u3000🎬 '+E[BP]+'\u3000👍 '+E[B_],AW:E[Al]}
if L.userid:M[AB]='做点什么$$$关注TA';M[AC]=P
V=L.config[l].get(AN);M[Cl]=A7.join(J(lambda x:Ak+A(F)+N+x[C]+'_getupvideos","name": "'+E[H].replace(AA,AH)+' '+x[D]+Az+x[D]+A_,V[-1][K]));W={G:[M]};return W
def setting_login_detailContent(J,key):
M=key;E='f';D='d';C='c';W=J.cookie_dic_tmp.get(M,B);K=B
if not W:K=J.get_cookies(M)
if K:K=f"{K}】通过手机客户端扫码确认登录后点击相应按钮设置账号"
else:K='【已扫码并确认登录】请点击相应按钮设置当前获取的账号为:'
Q={O:'登录与设置',AW:'通过手机客户端扫码并确认登录后,点击相应按钮设置cookie,设置后不需要管嗅探结果,直接返回二维码页面刷新,查看是否显示已登录,已登录即可重新打开APP以加载全部标签'};T=['登录$$$退出登录'];P=[];X=K+'$ ';Y='设置为主账号,动态收藏关注等内容源于此$'+A(M)+'_master_login_setting';Z='设置为备用的VIP账号,仅用于播放会员番剧$'+A(M)+'_vip_login_setting';P.append(I.join([X,Y,Z]));a='点击相应按钮退出账号>>>$ ';b='退出主账号$master_logout_setting';c='退出备用的VIP账号$vip_logout_setting';P.append(I.join([a,b,c]));d=[{E:'主页站点推荐栏',C:Bl,D:{AL:'3图',AQ:'4图','6':'6图','8':'8图','9':'9图'}},{E:'视频画质',C:Bn,D:J.vod_qn_id},{E:'视频编码',C:Bo,D:J.vod_codec_id},{E:'音频码率',C:Ap,D:J.vod_audio_id},{E:'收藏默认显示',C:Bm,D:{L:'默认收藏夹',V:'追番',A0:'追剧'}},{E:'上传播放进度',C:BA,D:{L:'','15':''}},{E:'直播筛选细化',C:Bp,D:{L:'',V:''}}]
for H in d:
T.append(H[E]);R=H[D][A(F(J.userConfig[H[C]]))]
if Ap==H[C]:R=A(R).replace(BV,'k')
U=['当前:'+R+'$ ']
for(id,S)in H[D].items():
if Ap==H[C]:S=A(S).replace(BV,'k')
U.append(S+w+A(id)+N+H[C]+'_setting')
P.append(I.join(U))
Q[AB]=i.join(T);Q[AC]=i.join(P);e={G:[Q]};return e
def setting_tab_filter_detailContent(K):
L={O:'标签与筛选',AW:'依次点击各标签,同一标签第一次点击为添加,第二次删除,可以返回到二维码页后重进本页查看预览,最后点击保存,未选择的将追加到末尾,如果未保存就重启app,将丢失未保存的配置'};M=[];P=[];V=[{D:BB,C:'标签'},{D:BC,C:'推荐[分区]'},{D:BD,C:'推荐[排行榜]'},{D:r,C:Ad}]
for Q in V:
F=Q[D];M.append(Q[C]);E=K.userConfig.get(A(F)+AD,[]);R=B
if E:R='【未保存】'
else:E=K.userConfig.get(F,[])
if not E:E=K.defaultConfig.get(F)
if E and Aa(E[0])==d:E=z(J(lambda x:x[D],E))
S=['当前: '+','.join(E)+'$ ',f"{R}点击这里保存$_{F}_save_setting",f"点击这里恢复默认并保存$_{F}_clear_setting"];T=K.defaultConfig[F].copy()
if F==r:W=K.userConfig.get(A4,[]);T.extend(W.copy())
for H in T:
U=A(H)
if Aa(H)==d:U=H[D]+Ao+H[C].replace(N,Ao);H=H[D]
S.append(f"{H}${U}_{F}_setting")
P.append(I.join(S))
L[AB]=i.join(M);L[AC]=i.join(P);X={G:[L]};return X
def setting_liveExtra_detailContent(H):
Q='_liveFilter_setting';F={O:CS,AW:'点击想要添加的标签,同一标签第一次点击为添加,第二次删除,完成后在[标签与筛选]页继续操作,以添加到直播筛选分区列中'};J=['已添加'];R=H.userConfig.get(A4,[]);E=['点击相应标签(只)可以删除$ #清空$clear_liveFilter_setting']
for B in R:S=B[C];B=B[D];E.append(B+w+'del_'+B+N+S+Q)
E=[I.join(E)];T=H.userConfig.get(AO,{})
for(V,W)in T.items():
L=W[K][K]
if U(L)==1:continue
J.append(V);M=[]
for P in L:B=A(P[D]).replace(N,'-').replace(I,A2).replace(w,AJ);id=A(P[C]).replace(N,Ao).replace(I,A2).replace(w,AJ);M.append(B+'$add_'+B+N+id+Q)
E.append(I.join(M))
F[AB]=i.join(J);F[AC]=i.join(E);X={G:[F]};return X
def get_all_season(C,season):
B=season;D=A(B[A8]);E=B[CE];F=C.detailContent_args[B[AI]]
if D==F[B5]:F[B7]=E
G=B[h];H=B[Ax][Aw];I={R:A9+D,O:E,S:C.format_img(G),Y:H};return I
def get_bangumi_section(B,section,array):
A=section;C=A[P].replace(I,A2).replace(w,AJ);D=A[k]
if D in[1,2]and U(A['episode_ids'])==0:E=A[BO];F=z(J(lambda x:B.get_normal_episodes(x)[0],J(lambda e:B.add_this_array(e,array),E)));return C,F
def ysContent(E,this_array):
r='rating';C=this_array;F=C[AI];X=C.get(T);d=C.get(o)
if d:F=d;C.pop(o)
if AT in F:X='ep_id='+F.replace(AT,B);C[o]=F
else:X='season_id='+F.replace(A9,B)
F=C[AI];s='https://api.bilibili.com/pgc/view/web/season?{0}'.format(X);D=E._get_sth(s,Q).json().get(u,{});C[B5]=Z=A(D[A8]);e=D[P];C[B7]=D[CE];C[C9]=''
if D[k]in[1,4]:C[C9]=''
N=D[Ax][Al]
if r in D:N=A(D[r]['score'])+''+N
M=D.get(C6)
if U(M)==1:C[B7]=M[0][CE];M=0
elif U(M)>1:C[C6]=z(J(E.get_all_season,J(lambda e:E.add_this_array(e,F),M)));N+=' [a=cr:{"id": "'+F+'_getbangumiseasons","name": "'+e.replace(AA,AH)+'"}/]更多系列[/a]'
f=D.get(BO);g=[]
for H in D.get('section',[]):
if H:a=E.pool.submit(E.get_bangumi_section,H,F);g.append(a)
t=D[h];v=D['share_sub_title'];w=D['publish']['pub_time'][0:4];x=D['evaluate'];j=D[BM];y=''+E.zh(j['views'])+'\u3000'+E.zh(j['favorites']);V={R:A9+Z,O:e,S:t,BH:v,CA:w,Cl:y,AW:x};V[Y]=N;W=[];K=[];L=[]
if f:
b=[];c=[]
for(l,m)in J(E.get_normal_episodes,J(lambda e:E.add_this_array(e,F),f)):
if m:b.append(l);c.append(m)
else:W.append(l)
if C.get(B2)and c:K.append(A(C[B7])+'【解析】');L.append(I.join(c))
if b:K.append(A(C[B7]));L.append(I.join(b))
n=[];p=[]
for a in Bj(g):
H=a.result()
if H:
if H[0]==BW:W+=H[1]
else:n.append(H[0]);p.append(I.join(H[1]))
if W:K.append(BW);L.append(I.join(W))
K+=n;L+=p;q=C.get(BY)
if q:K.insert(0,'B站');L.insert(0,q)
if E.userid:A0='做点什么';A1=f"❤追番剧$__{Z}_add__notplay_zhui#💔取消追番剧$__{Z}_del__notplay_zhui";K.insert(1,A0);L.insert(1,A1)
V[AB]=i.join(K);V[AC]=i.join(L);A2={G:[V]};return A2
def get_live_api2_playurl(W,room_id):
K=room_id;O=[];P=[];G='https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?room_id={0}&qn=0&platform=web&protocol=0,1&format=0,1,2&codec=0,1&dolby=5&panorama=1'.format(K);Q=W._get_sth(G,AF).json()
if Q[M]==0:
H=Q[E].get(Cm,B)
if H:
X=H[CF][Cn];C={Bc:{'avc':L,'hevc':V},AX:{'flv':L,'ts':V,'fmp4':A0}};C[AY]=d(J(lambda x:(x[AY],x[Al]),H[CF]['g_qn_desc']));R=[]
for Y in X:R.extend(Y[AX])
D={}
for S in R:
format=A(S.get('format_name'))
for T in S[Bc]:
U=A(T.get('codec_name'));Z=T.get('accept_qn')
for F in Z:
G=format+N+U+f"$live_{K}_"+A(F)+N+C[AX][format]+N+C[Bc][U]
if not D.get(C[AY][F]):D[C[AY][F]]=[]
D[C[AY][F]].append(G)
for(a,b)in D.items():O.append(a);P.append(I.join(b))
c=O,P;return c
def live_detailContent(C,room_id):
J=room_id;L=C.pool.submit(C.get_live_api2_playurl,J);W='https://api.live.bilibili.com/room/v1/Room/get_info?room_id='+A(J);N=C._get_sth(W,Q).json();T={}
if N.get(M)==0:
B=N[E];K=A(B['uid']);H=C.pool.submit(C.get_up_info,K);X=C.cleanCharacters(B[P]);Y=B.get(CX);Z=B.get(CY);a=B.get('parent_area_name')+'-'+B.get('area_name');D={R:J,O:X,S:Y,BH:a,AW:Z}
if F(B.get(CT)):D[CA]=B.get('live_time').replace('-','.')
U=L.result()[0];V=L.result()[1]
if C.userid:b='关注TA';c='是否关注$ ';d=f"➕关注$_{K}__1__notplay_follow";e=f"➖取关$_{K}__2__notplay_follow";f=[c,d,e];g=I.join(f);U.insert(1,b);V.insert(1,g)
D[AB]=i.join(U);D[AC]=i.join(V);H=H.result();D[BZ]=Ba+H[Bz]+Ck+C.zh(B.get(Ce))+AU+H[AS];T[G]=[D]
return T
search_key=B
def searchContent(A,key,quick,pg=V):
E=key
if not A.session_fake.cookies:A.pool.submit(A.getFakeCookie,Ab)
for C in A.task_pool:C.cancel()
if F(pg)>1:return A.get_search_content(key=E,pg=pg,duration_diff=0,order=B,type=p,ps=A.userConfig[Z])
A.task_pool=[];A.search_key=E;I={p:B,Co:'番剧: ',Cp:'影视: ',C7:'用户: ',AG:'直播: '}
for(type,J)in I.items():C=A.pool.submit(A.get_search_content,key=E,pg=J,duration_diff=0,order=B,type=type,ps=A.userConfig[Z]);A.task_pool.append(C)
D={};H=[]
for C in Bj(A.task_pool):K=C.result().get(G,[]);H.extend(K);A.task_pool.remove(C)
if U(H):D[G]=H;D[a]=pg;D[f]=9999;D[g]=99;D[c]=999999
return D
stop_heartbeat_event=x.Event()
def stop_heartbeat(A):
try:
for B in A.task_pool:B.cancel()
finally:A.stop_heartbeat_event.set()
def start_heartbeat(B,aid,cid,ssid,epid,duration,played_time):
E=played_time;G=F(B.userConfig[BA])
if not B.userid or not G:return
H=F((duration-E)/G)+1;I='https://api.bilibili.com/x/click-interface/web/heartbeat';C={T:A(aid),v:A(cid),Bd:A(B.csrf)}
if ssid:C['sid']=A(ssid);C[o]=A(epid);C[k]=AQ
D=0;B.stop_heartbeat_event.clear()
while Ab:
if D==G or B.stop_heartbeat_event.is_set():E+=D;D=0
if not D:
H-=1
if not H:E=-1;B.stop_heartbeat_event.set()
C['played_time']=A(E);C=B.encrypt_wbi(**C)[1];B.pool.submit(B._post_sth,url=I,data=C)
if B.stop_heartbeat_event.is_set():break
X.sleep(1);D+=1
wbi_key={}
def get_wbiKey(A,hour):D='wbi_img';C=A.fetch(CP,headers=A.header);F=C.json()[E][D]['img_url'];G=C.json()[E][D]['sub_url'];H=[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];I=F.split(AR)[-1].split('.')[0]+G.split(AR)[-1].split('.')[0];J=reduce(lambda s,i:s+I[i],H,B)[:32];A.wbi_key={W:J,'hour':hour}
def encrypt_wbi(D,**C):
E=AK(X.time());F=X.gmtime(E).tm_hour
if not D.wbi_key or F!=D.wbi_key['hour']:D.get_wbiKey(F)
C['wts']=E;G='ABCDEFGHIJK';C['dm_img_list']='[]';C['dm_img_str']=B.join(B8.sample(G,2));C['dm_cover_img_str']=B.join(B8.sample(G,2));C['dm_img_inter']='{"ds":[],"wh":[0,0,0],"of":[0,0,0]}';C=d(sorted(C.items()));C={C:B.join(filter(lambda chr:chr not in"!'()*",A(D)))for(C,D)in C.items()};H=Bk(C);I=hashlib.md5((H+D.wbi_key[W]).encode(encoding=Br)).hexdigest();C['w_rid']=I;return[H+'&w_rid='+I,C]
def _get_sth(A,url,_type=e,**C):
E=_type;B=url
if E==AF and A.session_vip.cookies:D=A.session_vip.get(B,headers=A.header,**C)
elif E==Q:
if not A.session_fake.cookies:A.getFakeCookie_event.wait()
D=A.session_fake.get(B,headers=A.header,**C)
else:D=A.session_master.get(B,headers=A.header,**C)
return D
def _post_sth(A,url,data):return A.session_master.post(url,headers=A.header,data=data)
def post_live_history(B,room_id):C={Cg:A(room_id),'platform':'pc',Bd:A(B.csrf)};D='https://api.live.bilibili.com/xlive/web-room/v1/index/roomEntryAction';B._post_sth(url=D,data=C)
def do_notplay(E,ids):
L='triple';K='fav';H,I,M,G,J,N,F=ids;C={Bd:A(E.csrf)};O=D=B
if F=='follow':
if J==C2:C.update({'fids':A(I),'tagids':A(G)});D='https://api.bilibili.com/x/relation/tags/addUsers'
else:C.update({'fid':A(I),'act':A(G)});D='https://api.bilibili.com/x/relation/modify'
elif F=='zhui':C.update({A8:A(M)});D='https://api.bilibili.com/pgc/web/follow/'+A(G)
elif F==Am:C.update({T:A(H),Am:A(G)});D='https://api.bilibili.com/x/web-interface/archive/like'
elif F==BS:C.update({T:A(H),'multiply':A(G),'select_like':V});D='https://api.bilibili.com/x/web-interface/coin/add'
elif F==K:C.update({'rid':A(H),k:A0});C[J+'_media_ids']=A(G);D='https://api.bilibili.com/x/v3/fav/resource/deal'
elif F==L:C.update({T:A(H)});D='https://api.bilibili.com/x/web-interface/archive/like/triple'
E._post_sth(url=D,data=C)
if F in[Am,BS,K,L]:C={T:A(H),Bd:A(E.csrf),'csrf_token':A(E.csrf)};D='https://api.bilibili.com/x/web-interface/share/add';E.pool.submit(E._post_sth,url=D,data=C)
E._refreshDetail()
def get_cid(D,aid,cid):
C=cid;G=f"https://api.bilibili.com/x/web-interface/view?aid={aid}&cid={C}";A=D._get_sth(G).json().get(E,{})
if not C:C=A[v]
H=A[n];F=B
if AV in A and C8 in A[AV]:F=D.find_bangumi_id(A[AV])
return C,H,F
cookie_dic_tmp={}
def get_cookies(A,key):
D='https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key='+key;B=A._get_sth(D,Q).json()
if B[M]==0:
C=B[E][Ci]
if not C:A.cookie_dic_tmp[key]=d(A.session_fake.cookies);A.pool.submit(A.getFakeCookie)
return C
return'网络错误'
def set_cookie(A,key,_type):
D=_type;C=key;F=A.cookie_dic_tmp.get(C,B)
if not F:
G=A.get_cookies(C)
if G:return
E=A.userConfig.get(j,{});E[D]={AE:A.cookie_dic_tmp.get(C,{})};A.userConfig.update({j:E});A.getCookie(D);A.dump_config()
def unset_cookie(A,_type):
C=_type
if C==AF:A.session_vip.cookies.clear()
else:A.session_master.cookies=A.session_fake.cookies;A.userid=A.csrf=B
if C in A.userConfig.get(j,{}):A.userConfig[j].pop(C);A.dump_config()
def set_normal_default(B,id,type):B.userConfig[type]=A(id);B.dump_config()
def set_normal_cateManual(B,name,_List,action):
H=action;F=name;E=_List;G=B.userConfig.get(A(E)+AD)
if not G:G=B.userConfig[A(E)+AD]=[]
if H=='save':
for I in B.defaultConfig[E]:
if not I in G.copy():B.userConfig[A(E)+AD].append(I)
B.userConfig[E]=B.userConfig[A(E)+AD].copy();B.userConfig.pop(E+AD);B.dump_config()
elif H=='clear':B.userConfig[E]=B.defaultConfig[E].copy();B.userConfig.pop(A(E)+AD);B.dump_config()
else:
if E==r:
F=F.split(Ao)
if U(F)==3:F[1]+=N+A(F[2])
F={D:F[0],C:A(F[1])}
if F in G:B.userConfig[A(E)+AD].remove(F)
else:B.userConfig[A(E)+AD].append(F)
def add_cateManualLiveExtra(A,action,name,id):
F='cateManualLive_tmp';G=A.userConfig.get(A4,[])
if not G:G=A.userConfig[A4]=[]
if action=='clear':
for E in G:
E[C]=E[C].replace(Ao,N)
if E in A.userConfig.get(r,[]):A.userConfig[r].remove(E)
if E in A.userConfig.get(F,[]):A.userConfig[F].remove(E)
A.userConfig.pop(A4)
elif id in z(J(lambda x:x[C],A.userConfig.get(A4,[]))):
B={D:name,C:id};A.userConfig[A4].remove(B);B[C]=id.replace(Ao,N)
if B in A.userConfig.get(r,[]):A.userConfig[r].remove(B)
if B in A.userConfig.get(F,[]):A.userConfig[F].remove(B)
else:B={D:name,C:id};A.userConfig[A4].append(B)
A.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={'30251':'Hi-Res无损','30250':'杜比全景声','30280':Cq,'30232':'132000','30216':'64000'}
def get_dash_media(E,media,aid,cid,qn):
I='SegmentBase';C=media;F=A(C.get(t));J=C.get(CG,B);K=C.get('codecs');L=C.get('bandwidth');M=C.get('startWithSap');H=C.get(Cr);O=C[I].get('indexRange');P=C[I].get('Initialization');D=H.split(AR)[0];G=B
if D==p:Q=C.get('frameRate');R=C.get('sar');S=C.get('width');T=C.get('height');G=f"height='{T}' width='{S}' frameRate='{Q}' sar='{R}'"
elif D==AZ:U=E.vod_audio_id.get(F,Cq);G=f"numChannels='2' sampleRate='{U}'"
V=f"{E.localProxyUrl}{D}&aid={aid}&cid={cid}&qn={qn}".replace('&','&amp;');F+=N+A(J);W=f'''
<Representation id="{F}" bandwidth="{L}" codecs="{K}" mimeType="{H}" {G} startWithSAP="{M}">
<BaseURL>{V}</BaseURL>
<SegmentBase indexRange="{O}">
<Initialization range="{P}"/>
</SegmentBase>
</Representation>''';E.pC_urlDic[f"{aid}_{cid}"][D]=C;return W
def get_dash_media_list(E,media_lis,aid,cid,qn):
F=media_lis
if not F:return B
G=F[0][Cr].split(AR)[0]
if G==p:I=A(qn);H=A(E.userConfig[Bo])
else:I=A(E.userConfig[Ap]);H=L
C={}
for D in F:
if G==AZ and not C:C=D
if A(D[t])==I:
if not C or A(D[CG])==H:
C=D
if A(D[CG])==H:break
J=f'\n <AdaptationSet>\n <ContentComponent contentType="{G}"/>{E.get_dash_media(C,aid,cid,qn)}\n </AdaptationSet>';return J
def get_dash(B,ja,aid,cid,qn):
A=ja;D=A.get(n);G=A.get('minBufferTime');H=B.pool.submit(B.get_dash_media_list,A.get(p),aid,cid,qn);C=A.get(AZ,[]);E=A.get('dolby',{}).get(AZ)
if E:C=E+C
F=A.get('flac')
if Aa(F)==d:C.insert(0,F.get(AZ))
I=B.pool.submit(B.get_dash_media_list,C,aid,cid,qn);J=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{D}S" minBufferTime="PT{G}S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">\n <Period duration="PT{D}S" start="PT0S">{H.result()}{I.result()}\n </Period>\n</MPD>';return J
def miao(B,m):
m=A(m).partition('.')[2]
if U(m)==0:m=BV
if U(m)==1:m=m+'00'
if U(m)==2:m=m+L
return m
def down_sub(C,url):
I=C._get_sth(url,Q).json()['body'];E=B;F=1
for D in I:G=AK(D['from'],3);H=AK(D['to'],3);J=D[Av];K=X.strftime(Bw,X.gmtime(G))+','+C.miao(G);L=X.strftime(Bw,X.gmtime(H))+','+C.miao(H);E+=A(F)+An+K+A7+'-->'+A7+L+An+J+'\n\n';F+=1
return E
localProxyUrl='http://127.0.0.1:9978/proxy?do=py&siteType=3&siteKey=py_bilibili&type='
def get_subs(J,aid,cid):
L='application/x-subrip';I=[];M=J.encrypt_wbi(aid=aid,cid=cid)[0];N=f"https://api.bilibili.com/x/player/wbi/v2?{M}";D=J._get_sth(N,e).json().get(E)
if D:
for K in D[Cs].get('subtitles',[]):
O=A(K.get('lan_doc',B));C=K.get('subtitle_url')
if C.startswith('//'):C=CR+C
C=CK(C);I.append({b:f"{J.localProxyUrl}subtitle&url={C}",H:O,AX:L})
if I:I.insert(0,{b:B,H:A7,AX:L})
G=0
if F(D.get('last_play_cid',0))==F(cid):
G=F(D.get('last_play_time'))
if G>0:G=F(G/1000)
P=D.get(Ct,{}).get(B6,B);return I,G,P
pC_urlDic={}
def _get_playerContent(G,result,aid,cid,epid):
e='durls';c='video_info';W='quality';P=epid;N=cid;L=aid;C=result;G.pC_urlDic[f"{L}_{N}"]=I={**G.pC_urlDic.get(f"{L}_{N}",{}),T:L,v:N,o:P};R=G.userConfig[Bn]
if P:H='https://api.bilibili.com/pgc/player/web/v2/playurl?aid={}&cid={}&qn={}&fnval=4048&fnver=0&fourk=1&from_client=BROWSER'.format(L,N,R)
else:
X={'avid':L,v:N,AY:R,'fnval':4048,'fnver':0,'fourk':1,'from_client':'BROWSER'}
if not G.session_vip.cookies:X['try_look']=1
f=G.encrypt_wbi(**X)[0];H=f"https://api.bilibili.com/x/player/wbi/playurl?{f}"
Q=G._get_sth(H,AF).json();S=B
if Q[M]==0:
if E in Q:D=Q[E]
elif u in Q:
D=Q[u]
if c in D:Y=D['view_info']['report'];S=Y[A8];P=Y['ep_id'];D=D[c]
else:return C
else:return C
I[B5]=S;I[o]=P;Z=d(J(lambda x:(x[W],x['new_description']),D['support_formats']));C[b]=[];U=D.get('dash');V=f"&aid={L}&cid={N}&qn="
if U:
I[CH]=U;C[AX]=Cu
for g in U[p]:
id=g[t];O=Z[id]
if not O in C[b]:
H=f"{G.localProxyUrl}dash{V}{id}"
if id==F(R):C[b]=[O,H]+C[b]
else:C[b].extend([O,H])
elif e in D:
for a in D[e]:
K=a[W];O=Z[K];H=f"{G.localProxyUrl}durl{V}{K}"
if K==F(R):C[b]=[O,H]+C[b]
else:C[b].extend([O,H])
I[A(K)]=a[Be][0]
else:K=D[W];I[A(K)]=D[Be][0];C[b]=f"{G.localProxyUrl}durl{V}{K}"
I[u]={**I.get(u,{}),**C};return C,S,P
def _refreshDetail(A,t=0):X.sleep(F(t));A.fetch('http://127.0.0.1:9978/action?do=refresh&type=detail')
def playerContent(C,flag,id,vipFlags):
C.pool.submit(C.stop_heartbeat);D={};P=B
if'@'in id:id,P=id.split('@')
I=C.detailContent_args.get(P,C.detailContent_args);H=id.split(N)
if U(H)<2:return D
if AG==H[0]:return C.live_playerContent(id)
G=H[0];E=H[1]
if Cj in H:
if'liveFilter'in H:id=H[2];C.add_cateManualLiveExtra(G,E,id)
elif E in[BB,r,BC,BD]:S=H[2];C.set_normal_cateManual(G,E,S)
elif'login'in H:C.set_cookie(G,E)
elif'logout'in H:C.unset_cookie(G)
else:C.set_normal_default(G,E)
return D
elif'notplay'in H:C.pool.submit(C.do_notplay,H);return D
elif Ct in H:I[CD]=G;I[v]=E;C.pool.submit(C._refreshDetail);return D
G,E,J,M,W=id.split(N)
if not E or not M:E,M,J=C.get_cid(G,E)
D[BR]='https://api.bilibili.com/x/v1/dm/list.so?oid='+A(E)
if W:X='https://www.bilibili.com/bangumi/play/ep'+A(J);D[b]=X;D['flag']='bilibili';D[B2]=V;D['jx']=V;D[CI]={AP:C.header[AP]};return D
Y=C.pool.submit(C.get_subs,G,E);K=C.pC_urlDic.get(f"{G}_{E}")
if K:D,Q,J=K[u],K[B5],K[o]
else:D[B2]=L;D[CJ]=B;D[CI]=C.header;D,Q,J=C._get_playerContent(D,G,E,J)
D['subs'],Z,O=Y.result();a=I.get(B6,B);R=I.get(T)
if R and G!=R or f"{G}_{E}"in I:I[T]=G;C.pool.submit(C._refreshDetail,2)
elif O and a!=O:I[B6]=O;C.pool.submit(C._refreshDetail)
else:c=C.pool.submit(C.start_heartbeat,G,E,Q,J,F(M),Z);C.task_pool.append(c)
return D
def live_playerContent(D,id):
K='url_info';T,I,O,format,G=id.split(N)
if D.userid and F(D.userConfig[BA])>0:D.pool.submit(D.post_live_history,I)
P='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'.format(I,format,G,O);J=D._get_sth(P,AF).json();C={}
if J[M]==0:
try:H=J[E][Cm].get(CF);G=H[Cn][0][AX][0][Bc][0]
except:return C
Q=A(G['base_url']);R=A(G[K][0]['host']);S=A(G[K][0]['extra']);H=R+Q+S;C[b]=H;C[CJ]=B
if'.flv'in H:C[CJ]='video/x-flv'
else:return C
C[B2]=L;C[CI]={Cv:'https://live.bilibili.com',AP:D.header[AP]};return C
def _testUrl(A,url,id,mediaType):
B=head(url,headers=A.header,timeout=5).status_code
if B!=200:A.pC_urlDic[id][mediaType].pop(url)
def get_fastesUrl(C,ja,id,mediaType):
E=mediaType;A=ja;D=A
if Aa(A)==d:C.pC_urlDic[id][E]=D=[A.get('baseUrl',A.get(b,B))];D.extend(A.get('backup_url',[]));C.pC_urlDic[id][Bf]=F(d(J(lambda x:x.split('=')[:2],D[0].split('?')[1].split('&'))).get(Bf,0))
for G in D:C.pool.submit(C._testUrl,G,id,E)
def localProxy(D,param):
N='range';M='application/octet-stream';E=param;A=E.get(k)
if A==Cs:O=D.down_sub(E[b]);return[200,M,O]
F=E.get(T);G=E.get(v);H=E.get(AY);C=D.pC_urlDic[f"{F}_{G}"]
if A=='dash':P=D.get_dash(C[CH],F,G,H);return[200,Cu,P]
if A in[Be,p,AZ]:
if A==Be:A=H
K=AK(X.time());I=C.get(Bf)
if Aa(C[A])==d or(I-K)%10==0:D.get_fastesUrl(C[A],f"{F}_{G}",A);I=C.get(Bf)
J=B8.choice(C[A])
if not J or A!=AZ and I-K<1800:
D._get_playerContent({},F,G,C[o]);C=D.pC_urlDic[f"{F}_{G}"]
if A==p:D.get_dash(C[CH],F,G,H)
D.get_fastesUrl(C[A],f"{F}_{G}",A);J=B8.choice(C[A])
L=D.header.copy()
if N in E:L['Range']=E[N]
Q=D.fetch(J,headers=L,stream=Ab);return[206,M,Q.content]
return[404,'text/plain',B]
config={'player':{},l:{BE:[{W:C5,H:'分类',K:[{D:B0,C:B0},{D:BT,C:BT},{D:C0,C:C0},{D:B1,C:B1},{D:C1,C:C1},{D:'我的粉丝',C:'我的粉丝'}]}],AN:[{W:q,H:'别人投稿排序',K:[{D:'最新发布',C:Ay},{D:'最多播放',C:'click'},{D:'最多收藏',C:'stow'},{D:'最早发布',C:CZ},{D:'合集和列表',C:Ca}]}],Ac:[{W:A1,H:'分类',K:[{D:'番剧',C:V},{D:'国创',C:AQ},{D:'电影',C:A0},{D:'电视剧',C:'5'},{D:'纪录片',C:AL},{D:'综艺',C:'7'}]},{W:q,H:'排序',K:[{D:A3,C:A3},{D:'播放数量',C:A0},{D:'更新时间',C:L},{D:'最高评分',C:AQ},{D:'弹幕数量',C:V},{D:'追看人数',C:AL},{D:'开播时间',C:'5'},{D:'上映时间',C:'6'}]},{W:C4,H:'付费',K:[{D:'全部',C:'-1'},{D:'免费',C:V},{D:'付费',C:'2%2C6'},{D:'大会员',C:'4%2C6'}]}],Ae:[{W:q,H:'排序',K:[{D:'收藏时间',C:'mtime'},{D:'播放量',C:BN},{D:'投稿时间',C:'pubtime'}]}],BF:[{W:k,H:'分类',K:[{D:'视频',C:BK},{D:Ad,C:AG},{D:BJ,C:BJ},{D:BQ,C:BQ}]}],Aq:[{W:k,H:'类型',K:[{D:'视频',C:p},{D:'番剧',C:Co},{D:Ac,C:Cp},{D:Ad,C:AG},{D:'用户',C:C7}]},{W:q,H:'视频排序',K:[{D:'综合排序',C:Ch},{D:'最多点击',C:'click'},{D:'最新发布',C:Ay},{D:'最多收藏',C:'stow'},{D:'最多弹幕',C:'dm'}]},{W:n,H:'视频时长',K:[{D:'全部',C:L},{D:'60分钟以上',C:AQ},{D:'30~60分钟',C:AL},{D:'5~30分钟',C:A0},{D:'5分钟以下',C:V}]}]}};header={'Origin':'https://www.bilibili.com',Cv:'https://space.bilibili.com',AP:'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0'}
+151
View File
@@ -0,0 +1,151 @@
# coding=utf-8
# !/usr/bin/python
# 嗷呜
import os
import sys
sys.path.append('..')
from base.spider import Spider
import requests
class Spider(Spider):
def init(self, extend=""):
pass
def getName(self):
return "hitv"
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def destroy(self):
pass
def homeContent(self, filter):
result = {}
cateManual = {
# "直播": "live",
'排行榜': 'rank',
"电影": "1",
"剧集": "2",
"综艺": "3",
"动画": "4",
"短片": "5"
}
classes = []
for k in cateManual:
classes.append({
'type_name': k,
'type_id': cateManual[k]
})
result['class'] = classes
return result
host = "https://wys.upfuhn.com"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/80.0.3987.149 Safari/537.36"
}
def list(self, list):
videos = []
for it in list:
videos.append({
"vod_id": it['video_site_id'],
"vod_name": it['video_name'],
"vod_pic": it['video_horizontal_url'] or it['video_vertical_url'],
"vod_remarks": it['newest_series_num'],
"vod_year": it['years'],
})
return videos
def homeVideoContent(self):
url = f'{self.host}/v1/ys_video_sites/hot?t=1'
data = self.fetch(url, headers=self.headers).json()
videos = self.list(data['data']['data'])
result = {'list': videos}
return result
def categoryContent(self, tid, pg, filter, extend):
path = f'/v1/ys_video_sites?t={tid}&s_t=0&a&y&o=0&ps=21&pn={pg}'
rank = False
if tid == 'rank':
if pg == 1:
path = f'/v1/ys_video_sites/ranking'
rank = True
else:
path = ''
# elif tid == 'live' and pg == 1:
# path = f'/v1/ys_live_tvs'
videos = []
result = {}
try:
data = self.fetch(self.host + path, headers=self.headers).json()
print(data)
if rank:
for video in data['data']:
videos.extend(data['data'][video])
else:
videos = data['data']['data']
result = {}
result['list'] = self.list(videos)
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
except:
result['list'] = []
return result
def detailContent(self, ids):
tid = ids[0]
url = f'{self.host}/v1/ys_video_series/by_vid/{tid}'
data = self.fetch(url, headers=self.headers).json()
data1 = data['data']['ys_video_site']
urls = []
for it in data['data']['data']:
urls.append(it['series_num'] + '$' + it['video_url'])
vod = {
'vod_name': data1['video_name'],
'type_name': data1['tag'],
'vod_year': data1['years'],
'vod_area': data1['area'],
'vod_director': data1['main_actor'],
'vod_content': data1['video_desc'],
'vod_play_from': '嗷呜在线',
'vod_play_url': '#'.join(urls),
}
result = {
'list': [
vod
]
}
return result
def searchContent(self, key, quick, pg=1):
url = f'{self.host}/v1/ys_video_sites/search?s={key}&o=0&ps=200&pn={pg}'
data = self.fetch(url, headers=self.headers).json()
videos = data['data']['video_sites']
if data['data']['first_video_series'] is not None:
videos = [data['data']['first_video_series']] + videos
result = {}
result['list'] = self.list(videos)
result['page'] = pg
return result
def playerContent(self, flag, id, vipFlags):
result = {
'url': id,
'parse': 0,
'header': self.headers
}
return result
def localProxy(self, param):
pass
+205
View File
@@ -0,0 +1,205 @@
# coding=utf-8
# !/usr/bin/python
# 嗷呜
import sys
sys.path.append("..")
import re
from base.spider import Spider
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64encode, b64decode
import json
import time
class Spider(Spider):
def getName(self):
return "次元"
def init(self, extend=""):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
host = "http://www.ecydm.top"
t = str(int(time.time()))
def header(self):
header = {
"User-Agent": "okhttp/3.14.9",
"app-version-code": "167",
"app-ui-mode": "light",
"app-user-device-id": "25f869d32598d3d3089a929453dff0bb7",
"app-api-verify-time": self.t,
"app-api-verify-sign": self.aes("encrypt", self.t),
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
}
return header
def homeContent(self, filter):
data = self.fetch(
"{0}/api.php/getappapi.index/initV119".format(self.host),
headers=self.header(),
).json()
data1 = self.aes("decrypt", data["data"])
dy = {
"class": "类型",
"area": "地区",
"lang": "语言",
"year": "年份",
"letter": "字母",
"by": "排序",
"sort": "排序",
}
filters = {}
classes = []
json_data = json.loads(data1)["type_list"]
self.homedata = json.loads(data1)["banner_list"]
for item in json_data:
if item["type_name"] == "全部":
continue
has_non_empty_field = False
jsontype_extend = json.loads(item["type_extend"])
self.homedata.extend(item["recommend_list"])
jsontype_extend["sort"] = "最新,最热,最赞,日榜,月榜,周榜"
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
for key in dy:
if key in jsontype_extend and jsontype_extend[key].strip() != "":
has_non_empty_field = True
break
if has_non_empty_field:
filters[str(item["type_id"])] = []
for dkey in jsontype_extend:
if dkey in dy and jsontype_extend[dkey].strip() != "":
values = jsontype_extend[dkey].split(",")
value_array = [
{"n": value.strip(), "v": value.strip()}
for value in values
if value.strip() != ""
]
filters[str(item["type_id"])].append(
{"key": dkey, "name": dy[dkey], "value": value_array}
)
result = {}
result["class"] = classes
result["filters"] = filters
return result
def homeVideoContent(self):
result = {"list": self.homedata}
return result
def categoryContent(self, tid, pg, filter, extend):
body = {
"area": extend.get('area', '全部'),
"year": extend.get('year', '全部'),
"type_id": tid,
"page": pg,
"sort": extend.get('sort', '最新'),
"lang": extend.get('lang', '全部'),
"class": extend.get('class', '全部')
}
result = {}
url = "{0}/api.php/getappapi.index/typeFilterVodList".format(self.host)
data = self.post(url, headers=self.header(), data=body).json()
data1 = self.aes("decrypt", data["data"])
result["list"] = json.loads(data1)["recommend_list"]
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
return result
def detailContent(self, ids):
body = f"vod_id={ids[0]}"
url = "{0}/api.php/getappapi.index/vodDetail".format(self.host)
data = self.post(url, headers=self.header(), data=body).json()
data1 = json.loads(self.aes("decrypt", data["data"]))
vod = data1["vod"]
play = []
names = []
for itt in data1["vod_play_list"]:
a = []
names.append(itt["player_info"]["show"])
parse = itt["player_info"]["parse"]
for it in itt["urls"]:
if re.search(r"mp4|m3u8", it["url"]):
a.append(f"{it['name']}${it['url']}")
elif re.search(r"www.yemu.xyz", it["parse_api_url"]):
a.append(f"{it['name']}${it['parse_api_url']}")
else:
a.append(
f"{it['name']}${'parse_api=' + parse + '&url=' + self.aes('encrypt', it['url']) + '&token=' + it['token']}")
play.append("#".join(a))
vod["vod_play_from"] = "$$$".join(names)
vod["vod_play_url"] = "$$$".join(play)
result = {"list": [vod]}
return result
def searchContent(self, key, quick, pg="1"):
body = f"keywords={key}&type_id=0&page={pg}"
url = "{0}/api.php/getappapi.index/searchList".format(self.host)
data = self.post(url, headers=self.header(), data=body).text
data1 = json.loads(data)["data"]
data2 = self.aes("decrypt", data1)
result = {"list": json.loads(data2)["search_list",'page':pg]}
return result
def playerContent(self, flag, id, vipFlags):
def edu(str):
def replacer(match):
from urllib.parse import quote_plus
return match.group(1) + quote_plus(match.group(2)) + match.group(3)
return re.sub(r"(url=)(.*?)(&token)", replacer, str)
url = id
p = 0
if "m3u8" not in url and "mp4" not in url:
try:
body = edu(url)
data = self.post("{0}/api.php/getappapi.index/vodParse".format(self.host), headers=self.header(),
data=body).json()
data1 = json.loads(self.aes("decrypt", data["data"]))["json"]
url = json.loads(data1)["url"]
except Exception as e:
url = id
p = 1
if not url.startswith("https://www.yemu.xyz"):
url = "https://www.yemu.xyz/?url={0}".format(id)
result = {}
headers = self.header().copy()
del headers["Content-Type"]
result["parse"] = p
result["url"] = url
result["header"] = headers
return result
def localProxy(self, param):
pass
def aes(self, operation, text):
key = "20c79c979da8db0f".encode("utf-8")
iv = key
if operation == "encrypt":
cipher = AES.new(key, AES.MODE_CBC, iv)
ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size))
ct = b64encode(ct_bytes).decode("utf-8")
return ct
elif operation == "decrypt":
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
return pt.decode("utf-8")
+279
View File
@@ -0,0 +1,279 @@
# coding=utf-8
# !/usr/bin/python
# by嗷呜(finally)
import sys
import os
sys.path.append("..")
import re
import hashlib
import hmac
import random
import string
from Crypto.Util.Padding import unpad
from concurrent.futures import ThreadPoolExecutor
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
from base64 import b64encode, b64decode
import json
import time
from base.spider import Spider
class Spider(Spider):
def getName(self):
return "电影猎手"
def init(self, extend=""):
self.device = self.device_id()
self.host = self.gethost()
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
t = str(int(time.time()))
def homeContent(self, filter):
result = {}
filters = {}
classes = []
bba = self.url()
data = self.fetch(f"{self.host}/api/v1/app/config?pack={bba[0]}&signature={bba[1]}", headers=self.header()).text
data1 = self.aes(data)
dy = {"class":"类型","area":"地区","lang":"语言","year":"年份","letter":"字母","by":"排序","sort":"排序"}
data1['data']['movie_screen']['sort'].pop(0)
for item in data1['data']['movie_screen']['sort']:
item['n'] = item.pop('name')
item['v'] = item.pop('value')
for item in data1['data']['movie_screen']['filter']:
has_non_empty_field = False
classes.append({"type_name": item["name"], "type_id": str(item["id"])})
for key in dy:
if key in item and item[key]:
has_non_empty_field = True
break
if has_non_empty_field:
filters[str(item["id"])] = []
filters[str(item["id"])].append(
{"key": 'sort', "name": '排序', "value": data1['data']['movie_screen']['sort']})
for dkey in item:
if dkey in dy and item[dkey]:
item[dkey].pop(0)
value_array = [
{"n": value.strip(), "v": value.strip()}
for value in item[dkey]
if value.strip() != ""
]
filters[str(item["id"])].append(
{"key": dkey, "name": dy[dkey], "value": value_array}
)
result["class"] = classes
result["filters"] = filters
return result
def homeVideoContent(self):
bba = self.url()
url = f'{self.host}/api/v1/movie/index_recommend?pack={bba[0]}&signature={bba[1]}'
data = self.fetch(url, headers=self.header()).json()
videos = []
for item in data['data']:
if len(item['list']) > 0:
for it in item['list']:
try:
videos.append(self.voides(it))
except Exception as e:
continue
result = {"list": videos}
return result
def categoryContent(self, tid, pg, filter, extend):
body = {"type_id": tid, "sort": extend.get("sort", "by_default"), "class": extend.get("class", "类型"),
"area": extend.get("area", "地区"), "year": extend.get("year", "年份"), "page": str(pg),
"pageSize": "21"}
result = {}
list = []
bba = self.url(body)
url = f"{self.host}/api/v1/movie/screen/list?pack={bba[0]}&signature={bba[1]}"
data = self.fetch(url, headers=self.header()).json()['data']['list']
for item in data:
list.append(self.voides(item))
result["list"] = list
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
return result
def detailContent(self, ids):
body = {"id": ids[0]}
bba = self.url(body)
url = f'{self.host}/api/v1/movie/detail?pack={bba[0]}&signature={bba[1]}'
data = self.fetch(url, headers=self.header()).json()['data']
video = {'vod_name': data.get('name'),'type_name': data.get('type_name'),'vod_year': data.get('year'),'vod_area': data.get('area'),'vod_remarks': data.get('dynami'),'vod_content': data.get('content')}
play = []
names = []
tasks = []
for itt in data["play_from"]:
name = itt["name"]
a = []
if len(itt["list"]) > 0:
names.append(name)
play.append(self.playeach(itt['list']))
else:
tasks.append({"movie_id": ids[0], "from_code": itt["code"]})
names.append(name)
if tasks:
with ThreadPoolExecutor(max_workers=len(tasks)) as executor:
results = executor.map(self.playlist, tasks)
for result in results:
if result:
play.append(result)
else:
play.append("")
video["vod_play_from"] = "$$$".join(names)
video["vod_play_url"] = "$$$".join(play)
result = {"list": [video]}
return result
def searchContent(self, key, quick, pg=1):
body = {"keyword": key, "sort": "", "type_id": "0", "page": str(pg), "pageSize": "10",
"res_type": "by_movie_name"}
bba = self.url(body)
url = f"{self.host}/api/v1/movie/search?pack={bba[0]}&signature={bba[1]}"
data = self.fetch(url, headers=self.header()).json()['data'].get('list')
videos = []
for it in data:
try:
videos.append(self.voides(it))
except Exception as e:
continue
result = {"list": videos, "page": pg}
return result
def playerContent(self, flag, id, vipFlags):
url = id
if "m3u8" not in url and "mp4" not in url:
try:
add = id.split('|||')
data = {"from_code": add[0], "play_url": add[1], "episode_id": add[2], "type": "play"}
bba = self.url(data)
data2 = self.fetch(f"{self.host}/api/v1/movie_addr/parse_url?pack={bba[0]}&signature={bba[1]}",
headers=self.header()).json()['data']
url = data2.get('play_url') or data2.get('download_url')
try:
url1 = self.fetch(url, headers=self.header(), allow_redirects=False).headers['Location']
if url1 and "http" in url1:
url = url1
except:
pass
except Exception as e:
pass
if '.jpg' in url or '.jpeg' in url or '.png' in url:
url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
result = {}
result["parse"] = 0
result["url"] = url
result["header"] = {'user-agent': 'okhttp/4.9.2'}
return result
def localProxy(self, param):
url = b64decode(param["url"]).decode('utf-8')
durl = url[:url.rfind('/')]
data = self.fetch(url, headers=self.header()).content.decode("utf-8")
lines = data.strip().split('\n')
for index, string in enumerate(lines):
# if 'URI="' in string and 'http' not in string:
# lines[index] = index
# 暂时预留,貌似用不到
if '#EXT' not in string and 'http' not in string:
lines[index] = durl + ('' if string.startswith('/') else '/') + string
data = '\n'.join(lines)
return [200, "application/vnd.apple.mpegur", data]
def device_id(self):
characters = string.ascii_lowercase + string.digits
random_string = ''.join(random.choices(characters, k=32))
return random_string
def gethost(self):
headers = {
'User-Agent': 'okhttp/4.9.2',
'Connection': 'Keep-Alive',
}
response = self.fetch('https://app-site.ecoliving168.com/domain_v5.json', headers=headers).json()
url = response['api_service'].replace('/api/', '')
return url
def header(self):
headers = {
'User-Agent': 'Android',
'Accept': 'application/prs.55App.v2+json',
'timestamp': self.t,
'x-client-setting': '{"pure-mode":1}',
'x-client-uuid': '{"device_id":' + self.device + '}, "type":1,"brand":"Redmi", "model":"M2012K10C", "system_version":30, "sdk_version":"3.1.0.7"}',
'x-client-version': '3096 '
}
return headers
def url(self, id=None):
if not id:
id = {}
id["timestamp"] = self.t
public_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA02F/kPg5A2NX4qZ5JSns+bjhVMCC6JbTiTKpbgNgiXU+Kkorg6Dj76gS68gB8llhbUKCXjIdygnHPrxVHWfzmzisq9P9awmXBkCk74Skglx2LKHa/mNz9ivg6YzQ5pQFUEWS0DfomGBXVtqvBlOXMCRxp69oWaMsnfjnBV+0J7vHbXzUIkqBLdXSNfM9Ag5qdRDrJC3CqB65EJ3ARWVzZTTcXSdMW9i3qzEZPawPNPe5yPYbMZIoXLcrqvEZnRK1oak67/ihf7iwPJqdc+68ZYEmmdqwunOvRdjq89fQMVelmqcRD9RYe08v+xDxG9Co9z7hcXGTsUquMxkh29uNawIDAQAB'
encrypted_text = json.dumps(id)
public_key = RSA.import_key(b64decode(public_key))
cipher = PKCS1_v1_5.new(public_key)
encrypted_message = cipher.encrypt(encrypted_text.encode('utf-8'))
encrypted_message_base64 = b64encode(encrypted_message).decode('utf-8')
result = encrypted_message_base64.replace('+', '-').replace('/', '_').replace('=', '')
key = '635a580fcb5dc6e60caa39c31a7bde48'
sign = hmac.new(key.encode(), result.encode(), hashlib.md5).hexdigest()
return result, sign
def playlist(self, body):
try:
bba = self.url(body)
url = f'{self.host}/api/v1/movie_addr/list?pack={bba[0]}&signature={bba[1]}'
data = self.fetch(url, headers=self.header()).json()['data']
return self.playeach(data)
except Exception:
return []
def playeach(self,data):
play_urls = []
for it in data:
if re.search(r"mp4|m3u8", it["play_url"]):
play_urls.append(f"{it['episode_name']}${it['play_url']}")
else:
play_urls.append(
f"{it['episode_name']}${it['from_code']}|||{it['play_url']}|||{it['episode_id']}"
)
return '#'.join(play_urls)
def voides(self, item):
if item['name'] or item['title']:
voide = {
"vod_id": item.get('id') or item.get('click'),
'vod_name': item.get('name') or item.get('title'),
'vod_pic': item.get('cover') or item.get('image'),
'vod_year': item.get('year') or item.get('label'),
'vod_remarks': item.get('dynamic') or item.get('sub_title')
}
return voide
def aes(self, text):
text = text.replace('-', '+').replace('_', '/') + '=='
key = b"e6d5de5fcc51f53d"
iv = b"2f13eef7dfc6c613"
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size).decode("utf-8")
return json.loads(pt)
+270
View File
@@ -0,0 +1,270 @@
# coding=utf-8
# !/usr/bin/python
import sys
import requests
from bs4 import BeautifulSoup
import re
import base64
from base.spider import Spider
import random
sys.path.append('..')
xurl = "https://heiliaowang-44.buzz"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36',
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def destroy(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
res = requests.get(xurl, headers=headerx)
res.encoding = "utf-8"
doc = BeautifulSoup(res.text, "html.parser")
sourcediv = doc.find('div', class_='nav')
vod = sourcediv.find_all('dd')
string_list = ["首页", "激情图漫", "激情小说",
"情色小说", "随机推荐", "顶级资源"]
result = {}
result['class'] = []
result['class'].append({'type_id': "/type/328", 'type_name': "国产视频"})
result['class'].append({'type_id': "/type/329", 'type_name': "中文字幕"})
result['class'].append({'type_id': "/type/331", 'type_name': "日本有码"})
result['class'].append({'type_id': "/type/332", 'type_name': "日本无码"})
result['class'].append({'type_id': "/type/333", 'type_name': "欧美无码"})
result['class'].append({'type_id': "/type/334", 'type_name': "强奸乱轮"})
result['class'].append({'type_id': "/type/335", 'type_name': "制服诱惑"})
result['class'].append({'type_id': "/type/336", 'type_name': "直播主播"})
result['class'].append({'type_id': "/type/338", 'type_name': "明星换脸"})
result['class'].append({'type_id': "/type/339", 'type_name': "抖阴视频"})
result['class'].append({'type_id': "/type/340", 'type_name': "女优明星"})
result['class'].append({'type_id': "/type/343", 'type_name': "网爆门"})
result['class'].append({'type_id': "/type/345", 'type_name': "伦理三级"})
result['class'].append({'type_id': "/type/346", 'type_name': "AV解说"})
result['class'].append({'type_id': "/type/347", 'type_name': "SM调教"})
result['class'].append({'type_id': "/type/348", 'type_name': "萝莉少女"})
result['class'].append({'type_id': "/type/349", 'type_name': "极品媚黑"})
result['class'].append({'type_id': "/type/350", 'type_name': "女同性恋"})
result['class'].append({'type_id': "/type/351", 'type_name': "玩偶姐姐"})
result['class'].append({'type_id': "/type/353", 'type_name': "人妖系列"})
result['class'].append({'type_id': "/type/373", 'type_name': "韩国主播"})
result['class'].append({'type_id': "/type/378", 'type_name': "VR视角"})
for item in vod:
name = item.find('a').text
if name in string_list:
continue
id = item.find('a')['href']
id = id.replace(".html", "")
result['class'].append({'type_id': id, 'type_name': name})
return result
def homeVideoContent(self):
videos = []
try:
res = requests.get(xurl, headers=headerx)
res.encoding = "utf-8"
doc = BeautifulSoup(res.text, "html.parser")
sourcediv = doc.find_all('div', class_='pic')
for vod in sourcediv:
ul_elements = vod.find_all('ul')
for item in ul_elements:
name = item.select_one("li a")['title']
pic = item.select_one("li a img")["data-src"]
remark = item.select_one("li a span").text
id = item.select_one("li a")['href']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
except:
pass
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if not pg:
pg = 1
url = xurl +cid + "/" + str(pg) + ".html"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
doc = BeautifulSoup(detail.text, "html.parser")
sourcediv = doc.find_all('div', class_='pic')
for vod in sourcediv:
ul_elements = vod.find_all('ul')
for item in ul_elements:
name = item.select_one("li a")['title']
pic = item.select_one("li a img")["src"]
remark = item.select_one("li a span").text
id = item.select_one("li a")['href']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
videos = []
result = {}
res = requests.get(url=xurl + did, headers=headerx)
res.encoding = "utf-8"
doc = BeautifulSoup(res.text, "html.parser")
sourcediv = doc.find('div', style='padding-bottom: 10px;')
vod = sourcediv.find_all('a')
play_from = ""
play_url = ""
for item in vod:
play_from = play_from + item.text + "$$$"
play_url = play_url + item['href'] + "$$$"
while play_url[-1] == "#" or play_url[-1] == "$":
play_url = play_url[:-1]
while play_from[-1] == "#" or play_from[-1] == "$":
play_from = play_from[:-1]
source_match = re.search(r"<li>播放地址:<strong>(.*?)</strong></li>", res.text)
if source_match:
tx = source_match.group(1)
videos.append({
"vod_id": did,
"vod_name": tx,
"vod_pic": "",
"type_name": "ぃぅおか🍬 คิดถึง",
"vod_year": "",
"vod_area": "",
"vod_remarks": "",
"vod_actor": "",
"vod_director": "",
"vod_content": "",
"vod_play_from": play_from,
"vod_play_url": play_url
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
res = requests.get(url=xurl + id, headers=headerx)
res.encoding = "utf-8"
if '"rid"' in res.text:
decoded_str = ''
while not decoded_str:
source_match3 = re.search(r'"rid" : "(.*?)"', res.text)
if source_match3:
id = source_match3.group(1)
data = "rid=" + id
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36",
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
res2 = requests.post(url="https://heiliaowang-44.buzz/fetchPlayUrl3", headers=header, data=data)
source_match4 = re.search(r'"returnData"\s*:\s*"([^"]+)"', res2.text)
if source_match4:
decoded_str = source_match4.group(1)
else:
source_match = re.search(r"http:(.*?)\.m3u8", res.text)
decoded_str = ""
if source_match:
str3 = source_match.group(1)
if "aHR0c" in str3:
padding_needed = len(str3) % 4
if padding_needed:
str3 += '=' * (4 - padding_needed)
decoded_str = base64.b64decode(str3).decode("utf-8")
if not decoded_str:
source_match2 = re.search(r"'(.*?)\.m3u8';", res.text)
if source_match2:
decoded_str = source_match2.group(1) + ".m3u8"
result["parse"] = 0
result["playUrl"] = ''
result["url"] = decoded_str
result["header"] = headerx
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = 1
url = xurl +"/search/"+ key +"/n/" + str(page)+".html"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
doc = BeautifulSoup(detail.text, "html.parser")
sourcediv = doc.find_all('div', class_='pic')
for vod in sourcediv:
ul_elements = vod.find_all('ul')
for item in ul_elements:
name = item.select_one("li a")['title']
pic = item.select_one("li a img")["src"]
remark = item.select_one("li a span").text
id = item.select_one("li a")['href']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+373
View File
@@ -0,0 +1,373 @@
"""
作者 凯悦宾馆 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
import requests
from bs4 import BeautifulSoup
import re
from base.spider import Spider
import sys
import json
import base64
import urllib.parse
sys.path.append('..')
xurl = "http://www.45b7.com"
headerx1 = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
headerx = {
'User-Agent': 'Linux; Android 12; Pixel 3 XL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.101 Mobile Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️拾光👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️拾光👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨拾光👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "都市", "type_name": "都市🌠"},
{"type_id": "赘婿", "type_name": "赘婿🌠"},
{"type_id": "战神", "type_name": "战神🌠"},
{"type_id": "古代", "type_name": "古代🌠"},
{"type_id": "现代", "type_name": "现代🌠"},
{"type_id": "历史", "type_name": "历史🌠"},
{"type_id": "脑洞", "type_name": "脑洞🌠"},
{"type_id": "玄幻", "type_name": "玄幻🌠"},
{"type_id": "搞笑", "type_name": "搞笑🌠"},
{"type_id": "喜剧", "type_name": "喜剧🌠"},
{"type_id": "萌宝", "type_name": "萌宝🌠"},
{"type_id": "神豪", "type_name": "神豪🌠"},
{"type_id": "致富", "type_name": "致富🌠"},
{"type_id": "奇幻", "type_name": "奇幻🌠"},
{"type_id": "超能", "type_name": "超能🌠"},
{"type_id": "强者", "type_name": "强者🌠"},
{"type_id": "甜宠", "type_name": "甜宠🌠"},
{"type_id": "励志", "type_name": "励志🌠"},
{"type_id": "豪门", "type_name": "豪门🌠"},
{"type_id": "复仇", "type_name": "复仇🌠"},
{"type_id": "长生", "type_name": "长生🌠"},
{"type_id": "神医", "type_name": "神医🌠"},
{"type_id": "马甲", "type_name": "马甲🌠"},
{"type_id": "亲情", "type_name": "亲情🌠"},
{"type_id": "人物", "type_name": "人物🌠"},
{"type_id": "奇幻", "type_name": "奇幻🌠"},
{"type_id": "无敌", "type_name": "无敌🌠"},
{"type_id": "现实", "type_name": "现实🌠"},
{"type_id": "重生", "type_name": "重生🌠"},
{"type_id": "闪婚", "type_name": "闪婚🌠"},
{"type_id": "职场", "type_name": "职场🌠"},
{"type_id": "穿越", "type_name": "穿越🌠"},
{"type_id": "年代", "type_name": "年代🌠"},
{"type_id": "权谋", "type_name": "权谋🌠"},
{"type_id": "高手", "type_name": "高手🌠"},
{"type_id": "悬疑", "type_name": "悬疑🌠"},
{"type_id": "情仇", "type_name": "情仇🌠"},
{"type_id": "虐恋", "type_name": "虐恋🌠"},
{"type_id": "古装", "type_name": "古装🌠"},
{"type_id": "时空", "type_name": "时空🌠"},
{"type_id": "玄幻", "type_name": "玄幻🌠"},
{"type_id": "欢喜", "type_name": "欢喜🌠"},
{"type_id": "觉醒", "type_name": "觉醒🌠"},
{"type_id": "情感", "type_name": "情感🌠"},
{"type_id": "逆袭", "type_name": "逆袭🌠"},
{"type_id": "家庭", "type_name": "家庭🌠"}]
}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="FeaturedList_featuredBox")
for soup in soups:
vods = soup.find_all('div', class_="FeaturedList_featuredItem")
for vod in vods:
names = vod.find('a', class_="FeaturedList_bookName")
name = names.text.strip()
ids = vod.find('a', class_="FeaturedList_bookName")
id = ids['href']
pics = vod.find('a', class_="image_imageBox")
pic = pics.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="FeaturedList_lastChapter")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '拾光推荐📽️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
if pg:
page = int(pg)
else:
page = 1
page = int(pg)
videos = []
if page == '1':
url = f'{xurl}/vodshow/1---{cid}--------.html'
else:
url = f'{xurl}/vodshow/1---{cid}-----{str(page)}---.html'
try:
detail = requests.get(url=url, headers=headerx1)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="BrowseList_listBox")
for soup in soups:
vods = soup.find_all('div', class_="BrowseList_itemBox")
for vod in vods:
names = vod.find('a', class_="image_imageScaleBox")
name = names.find('img')['alt']
ids = vod.find('a', class_="image_imageScaleBox")
id = ids['href']
pics = vod.find('a', class_="image_imageScaleBox")
pic = pics.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="BrowseList_totalChapterNum")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多推荐📽️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
playurl = ''
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
content = '😸拾光趣乐屋🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'name="description" content=','/>', 0)
content = content.replace('\r', '').replace('\n', '').replace(' ', '')
bofang = self.extract_middle_text(res, '<div class="adm-swiper-item', '</div>', 3,'href="(.*?)">\s+(.*?)\s+</a>')
bofang = bofang.replace('$$$', '#')
videos.append({
"vod_id": did,
"vod_actor": '😸拾光',
"vod_director": '😸拾光',
"vod_content": content,
"vod_play_from": '😸拾光专线',
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
res = requests.get(url=after_https, headers=headerx)
res = res.text
url = self.extract_middle_text(res, '},"url":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/vodsearch/-------------.html?wd={key}'
else:
url = f'{xurl}/vodsearch/{key}----------{str(page)}---.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="MTagBookList_tagBookItem")
for vod in soups:
names = vod.find('a', class_="MTagBookList_bookName")
name = names.text.strip()
ids = vod.find('a', class_="MTagBookList_bookName")
id = ids['href']
pics = vod.find('a', class_="image_imageScaleBox")
pic = pics.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('a', class_="image_imageScaleBox")
remark = remarks.find('img')['alt']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '拾光推荐📽️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+193
View File
@@ -0,0 +1,193 @@
# coding=utf-8
# !/usr/bin/python
# by嗷呜
import re
import sys
from urllib.parse import quote
from Crypto.Hash import MD5
sys.path.append("..")
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64encode, b64decode
import json
import time
from base.spider import Spider
class Spider(Spider):
def getName(self):
return "光速"
def init(self, extend=""):
self.host = self.gethost()
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
def homeContent(self, filter):
data = self.getdata("/api.php/getappapi.index/initV119")
dy = {"class": "类型", "area": "地区", "lang": "语言", "year": "年份", "letter": "字母", "by": "排序",
"sort": "排序", }
filters = {}
classes = []
json_data = data["type_list"]
homedata = data["banner_list"]
for item in json_data:
if item["type_name"] == "全部":
continue
has_non_empty_field = False
jsontype_extend = json.loads(item["type_extend"])
homedata.extend(item["recommend_list"])
jsontype_extend["sort"] = "最新,最热,最赞"
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
for key in dy:
if key in jsontype_extend and jsontype_extend[key].strip() != "":
has_non_empty_field = True
break
if has_non_empty_field:
filters[str(item["type_id"])] = []
for dkey in jsontype_extend:
if dkey in dy and jsontype_extend[dkey].strip() != "":
values = jsontype_extend[dkey].split(",")
value_array = [{"n": value.strip(), "v": value.strip()} for value in values if
value.strip() != ""]
filters[str(item["type_id"])].append({"key": dkey, "name": dy[dkey], "value": value_array})
result = {}
result["class"] = classes
result["filters"] = filters
result["list"] = homedata
return result
def homeVideoContent(self):
pass
def categoryContent(self, tid, pg, filter, extend):
body = {"area": extend.get('area', '全部'), "year": extend.get('year', '全部'), "type_id": tid, "page": pg,
"sort": extend.get('sort', '最新'), "lang": extend.get('lang', '全部'),
"class": extend.get('class', '全部')}
result = {}
data = self.getdata("/api.php/getappapi.index/typeFilterVodList", body)
result["list"] = data["recommend_list"]
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
return result
def detailContent(self, ids):
body = f"vod_id={ids[0]}"
data = self.getdata("/api.php/getappapi.index/vodDetail", body)
vod = data["vod"]
play = []
names = []
for itt in data["vod_play_list"]:
a = []
names.append(itt["player_info"]["show"])
parse = itt["player_info"]["parse"]
ua = ''
if itt["player_info"].get("user_agent", ''):
ua = b64encode(itt["player_info"]["user_agent"].encode('utf-8')).decode('utf-8')
for it in itt["urls"]:
url = it["url"]
if not re.search(r'\.m3u8|\.mp4', url):
url = parse + '@@' + url
url = b64encode(url.encode('utf-8')).decode('utf-8')
a.append(f"{it['name']}${url}|||{ua}|||{it['token']}")
play.append("#".join(a))
vod["vod_play_from"] = "$$$".join(names)
vod["vod_play_url"] = "$$$".join(play)
result = {"list": [vod]}
return result
def searchContent(self, key, quick, pg="1"):
body = f"keywords={key}&type_id=0&page={pg}"
data = self.getdata("/api.php/getappapi.index/searchList", body)
result = {"list": data["search_list"], "page": pg}
return result
phend = {
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 11; M2012K10C Build/RP1A.200720.011)'}
def playerContent(self, flag, id, vipFlags):
ids = id.split("|||")
if ids[1]: self.phend['User-Agent'] = b64decode(ids[1]).decode('utf-8')
url = b64decode(ids[0]).decode('utf-8')
if not re.search(r'\.m3u8|\.mp4', url):
a = url.split("@@")
body = f"parse_api={a[0]}&url={quote(self.aes('encrypt', a[1]))}&token={ids[-1]}"
jd = self.getdata("/api.php/getappapi.index/vodParse", body)['json']
url = json.loads(jd)['url']
# if '.mp4' not in url:
# l=self.fetch(url, headers=self.phend,allow_redirects=False)
# if l.status_code == 200 and l.headers.get('Location',''):
# url=l.headers['Location']
if '.jpg' in url or '.png' in url or '.jpeg' in url:
url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
result = {}
result["parse"] = 0
result["url"] = url
result["header"] = self.phend
return result
def localProxy(self, param):
url = b64decode(param["url"]).decode('utf-8')
durl = url[:url.rfind('/')]
data = self.fetch(url, headers=self.phend).content.decode("utf-8")
inde = None
pd = True
lines = data.strip().split('\n')
for index, string in enumerate(lines):
# if '#EXT-X-DISCONTINUITY' in string and pd:
# pd = False
# inde = index
if '#EXT' not in string and 'http' not in string:
lines[index] = durl + ('' if string.startswith('/') else '/') + string
if inde:
del lines[inde:inde + 4]
data = '\n'.join(lines)
return [200, "application/vnd.apple.mpegur", data]
def gethost(self):
host = self.fetch('https://jingyu-1312635929.cos.ap-nanjing.myqcloud.com/1.json').text.strip()
return host
def aes(self, operation, text):
key = "4d83b87c4c5ea111".encode("utf-8")
iv = key
if operation == "encrypt":
cipher = AES.new(key, AES.MODE_CBC, iv)
ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size))
ct = b64encode(ct_bytes).decode("utf-8")
return ct
elif operation == "decrypt":
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
return pt.decode("utf-8")
def header(self):
t = str(int(time.time()))
md5_hash = MD5.new()
md5_hash.update(t.encode('utf-8'))
signature_md5 = md5_hash.hexdigest()
header = {"User-Agent": "okhttp/3.14.9", "app-version-code": "300", "app-ui-mode": "light",
"app-user-device-id": signature_md5, "app-api-verify-time": t,
"app-api-verify-sign": self.aes("encrypt", t), "Content-Type": "application/x-www-form-urlencoded"}
return header
def getdata(self, path, data=None):
# data = self.post(self.host + path, headers=self.header(), data=data).text
data = self.post(self.host + path, headers=self.header(), data=data, verify=False).json()["data"]
data1 = self.aes("decrypt", data)
return json.loads(data1)
+377
View File
@@ -0,0 +1,377 @@
"""
作者 凯悦宾馆 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
import requests
from bs4 import BeautifulSoup
import re
from base.spider import Spider
import sys
import json
import base64
import urllib.parse
sys.path.append('..')
xurl = "https://www.netfly.tv"
headerx = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️丢丢👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️丢丢👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨丢丢👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "/vod/show/1", "type_name": "丢丢电影🌠"},
{"type_id": "/vod/show/2", "type_name": "丢丢剧集🌠"},
{"type_id": "/vod/show/3", "type_name": "丢丢综艺🌠"},
{"type_id": "/vod/show/4", "type_name": "丢丢动漫🌠"},
{"type_id": "/vod/show/5", "type_name": "丢丢其他🌠"}],
"list": [],
"filters": {"/vod/show/1": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"/vod/show/2": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"/vod/show/3": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"/vod/show/4": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"/vod/show/5": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}]}}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
res = self.extract_middle_text(res, '<div class="module">', '专题片单', 0)
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="module-items")
for soup in soups:
vods = soup.find_all('a')
for vod in vods:
name = vod['title']
id = vod['href']
pics = vod.find('div', class_="module-item-pic")
pic = pics.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'module-item-note">', '</div>', 0)
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
if pg:
page = int(pg)
else:
page = 1
page = int(pg)
videos = []
if '年代' in ext.keys():
NdType = ext['年代']
else:
NdType = ''
if page == '1':
url = f'{xurl}{cid}-----------.html'
else:
url = f'{xurl}{cid}--------{str(page)}---{NdType}.html'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
res = self.extract_middle_text(res, '按评分排序', '<div id="page">', 0)
doc = BeautifulSoup(res, "lxml")
for soup in doc:
vods = soup.find_all('a')
for vod in vods:
name = vod['title']
id = vod['href']
pics = vod.find('div', class_="module-item-pic")
pic = pics.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'module-item-note">', '</div>', 0)
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
playurl = ''
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
content = '😸丢丢🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'20px;">','</p>', 0)
content = content.replace('\u3000', '').replace(' ', '').replace('<p>', '').replace('\n', '')
xianlu = self.extract_middle_text(res, '<div class="module-tab-items-box hisSwiper"','<div class="shortcuts-mobile-overlay">',2, 'data-dropdown-value=".*?"><span>(.*?)</span>')
bofang = self.extract_middle_text(res, '<div class="module-play-list-content', '</div>', 3,'href="(.*?)" title=".*?"><span>(.*?)</span>')
videos.append({
"vod_id": did,
"vod_actor": '😸皮皮 😸灰灰',
"vod_director": '😸丢丢',
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
res = requests.get(url=after_https, headers=headerx)
url = self.extract_middle_text(res.text, '},"url":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/vod/search/-------------.html?wd={key}'
else:
url = f'{xurl}/vod/search/{key}----------{str(page)}---.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="module-card-item")
for vod in soups:
names = vod.find('div', class_="module-item-pic")
name = names.find('img')['alt']
ids = vod.find('div', class_="module-card-item-title")
id = ids.find('a')['href']
pics = vod.find('div', class_="module-item-pic")
pic = pics.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'module-item-note">', '</div>', 0)
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+238
View File
@@ -0,0 +1,238 @@
# coding=utf-8
# !/usr/bin/python
# by嗷呜
import sys
sys.path.append("..")
import re
import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64encode, b64decode
import json
from base.spider import Spider
from urllib.parse import quote
class Spider(Spider):
def getName(self):
return "视觉"
def init(self, extend=""):
self.host = self.host()
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
def homeContent(self, filter):
data = self.fetch(
f"{self.host}/api/v3/drama/getCategory?orderBy=type_id",
headers=self.headers,
).json()
dy = {
"class": "类型",
"area": "地区",
"lang": "语言",
"year": "年份",
"letter": "字母",
"by": "排序",
"sort": "排序",
}
filters = {}
classes = []
for item in data["data"]:
has_non_empty_field = False
jsontype_extend = json.loads(item["converUrl"])
classes.append({"type_name": item["name"], "type_id": str(item["id"])})
for key in dy:
if key in jsontype_extend and jsontype_extend[key].strip() != "":
has_non_empty_field = True
break
if has_non_empty_field:
filters[str(item["id"])] = []
for dkey in jsontype_extend:
if dkey in dy and jsontype_extend[dkey].strip() != "":
values = jsontype_extend[dkey].split(",")
value_array = [
{"n": value.strip(), "v": value.strip()}
for value in values
if value.strip() != ""
]
filters[str(item["id"])].append(
{"key": dkey, "name": dy[dkey], "value": value_array}
)
result = {}
result["class"] = classes
result["filters"] = filters
return result
def homeVideoContent(self):
data = self.fetch(f"{self.host}/api/ex/v3/security/tag/list", headers=self.headers).json()["data"]
data1 = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)
list = []
for item in data1[0]['carousels']:
id = item['link'].split("id=")[1]
list.append({
"vod_id": id,
'vod_name': item.get("title"),
'vod_pic': item.get("cover"),
'vod_remarks': item.get("sort"),
})
result = {"list": list}
return result
def categoryContent(self, tid, pg, filter, extend):
params = []
if extend.get('area'):
params.append(f"vodArea={extend['area']}")
if extend.get('classs'):
params.append(f"vodClass={extend['class']}")
params.append("pagesize=20")
params.append(f"typeId1={tid}")
params.append(f"page={pg}")
if extend.get('year'):
params.append(f"vodYear={extend['year']}")
body = '&'.join(params)
path = self.aes(self.aes(body, self.key[1], 'encrypt'), self.key[0], 'encrypt', True)
data = self.fetch(f"{self.host}/api/ex/v3/security/drama/list?query={path}", headers=self.headers).json()[
"data"]
data = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)['list']
list = []
for item in data:
list.append({
'vod_id': item.get("id"),
'vod_pic': item["coverImage"].get("path"),
'vod_name': item.get("name"),
'vod_year': item.get("year"),
'vod_remarks': item.get("remark")
})
result = {}
result["list"] = list
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
return result
def detailContent(self, ids):
url = f"{self.host}/api/v3/drama/getDetail?id={ids[0]}"
data = self.fetch(url, headers=self.headers).json()["data"]
vod = {
'vod_name': data.get("name"),
'vod_area': data.get("area"),
'type_name': data.get("clazz"),
'vod_actor': data.get("actor"),
'vod_director': data.get("director"),
'vod_content': data.get("brief").strip(),
}
play = []
names = []
plays = {}
for itt in data["videos"]:
if itt["sourceCn"] not in names:
plays[itt["source"]] = []
names.append(itt["sourceCn"])
url = f"vodPlayFrom={itt['source']}&playUrl={itt['path']}"
if re.search(r"\.(mp4|m3u8|flv)$", itt["path"]):
url = itt["path"]
plays[itt["source"]].append(f"{itt['titleOld']}${url}")
for it in plays:
play.append("#".join(plays[it]))
vod["vod_play_from"] = "$$$".join(names)
vod["vod_play_url"] = "$$$".join(play)
result = {"list": [vod]}
return result
def searchContent(self, key, quick, pg=1):
body = f"pagesize=20&page={pg}&searchKeys={key}"
path = self.aes(self.aes(body, self.key[1], 'encrypt'), self.key[0], 'encrypt', True)
data = self.fetch(f"{self.host}/api/ex/v3/security/drama/list?query={path}", headers=self.headers).json()[
"data"]
data = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)['list']
list = []
for item in data:
list.append({
'vod_id': item.get("id"),
'vod_pic': item["coverImage"].get("path"),
'vod_name': item.get("name"),
'vod_year': item.get("year"),
'vod_remarks': item.get("remark")
})
result = {"list": list, "page": pg}
return result
def playerContent(self, flag, id, vipFlags):
url = id
if "vodPlayFrom" in url:
try:
path = self.aes(self.aes(id, self.key[1], 'encrypt'), self.key[0], 'encrypt', True)
data = self.fetch(f"{self.host}/api/ex/v3/security/videoUsableUrl?query={path}", headers=self.headers).json()[
"data"]
url = self.aes(self.aes(data, self.key[0]), self.key[1], 'decrypt', True)['playUrl']
# try:
# url1 = self.fetch(url, headers=self.headers, timeout=5, allow_redirects=False).headers['Location']
# if "http" in url1 and url1:
# url = url1
# except:
# pass
except Exception as e:
pass
if '.jpg' in url or '.jpeg' in url or '.png' in url:
url = self.getProxyUrl() + "&url=" + b64encode(url.encode('utf-8')).decode('utf-8') + "&type=m3u8"
result = {}
result["parse"] = 0
result["url"] = url
result["header"] = {'User-Agent': 'okhttp/3.12.1'}
return result
def localProxy(self, param):
url = b64decode(param["url"]).decode('utf-8')
durl = url[:url.rfind('/')]
data = self.fetch(url, headers=self.headers).content.decode("utf-8")
lines = data.strip().split('\n')
for index, string in enumerate(lines):
if '#EXT' not in string and 'http' not in string:
lines[index] = durl + ('' if string.startswith('/') else '/') + string
data = '\n'.join(lines)
return [200, "application/vnd.apple.mpegur", data]
def host(self):
try:
url = self.fetch('https://www.shijue.pro/token.txt', headers=self.headers).json()['domain']
return url
except:
return "http://118.25.18.217:6632"
headers = {
'User-Agent': 'okhttp/3.12.1',
'Content-Type': 'application/json;'
}
key = ['TFLYWVJ5EG5YB1PLZLVVMGVLBGRIDCSW', 'nj6E5K4yYYT5W4ScJ3J3rJ2zrzcJkpTk']
def aes(self, word, key, mode='decrypt', bool=False):
key = key.encode('utf-8')
if mode == 'decrypt':
word = b64decode(word)
cipher = AES.new(key, AES.MODE_ECB)
decrypted = cipher.decrypt(word)
word = unpad(decrypted, AES.block_size).decode('utf-8')
if bool:
word = json.loads(word)
elif mode == 'encrypt':
cipher = AES.new(key, AES.MODE_ECB)
padded = pad(word.encode('utf-8'), AES.block_size)
encrypted = cipher.encrypt(padded)
word = b64encode(encrypted).decode('utf-8')
if bool:
word = quote(word)
return word
+411
View File
@@ -0,0 +1,411 @@
"""
作者 凯悦推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from base.spider import Spider
from bs4 import BeautifulSoup
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.ingbo.tv"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️集多👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️集多👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨集多👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "1", "type_name": "集多电影🌠"},
{"type_id": "2", "type_name": "集多剧集🌠"},
{"type_id": "4", "type_name": "集多动漫🌠"},
{"type_id": "40", "type_name": "集多短剧🌠"},
{"type_id": "3", "type_name": "集多综艺🌠"}],
"list": [],
"filters": {"1": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "2024", "v": "3"},
{"n": "2023", "v": "4"},
{"n": "2022", "v": "5"},
{"n": "2021", "v": "6"},
{"n": "2020", "v": "7"},
{"n": "2019", "v": "8"},
{"n": "2018", "v": "9"}]}],
"2": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "2024", "v": "3"},
{"n": "2023", "v": "4"},
{"n": "2022", "v": "5"},
{"n": "2021", "v": "6"},
{"n": "2020", "v": "7"},
{"n": "2019", "v": "8"},
{"n": "2018", "v": "9"}]}],
"3": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "2024", "v": "3"},
{"n": "2023", "v": "4"},
{"n": "2022", "v": "5"},
{"n": "2021", "v": "6"},
{"n": "2020", "v": "7"},
{"n": "2019", "v": "8"},
{"n": "2018", "v": "9"}]}],
"40": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "2024", "v": "3"},
{"n": "2023", "v": "4"},
{"n": "2022", "v": "5"},
{"n": "2021", "v": "6"},
{"n": "2020", "v": "7"},
{"n": "2019", "v": "8"},
{"n": "2018", "v": "9"}]}],
"4": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "2024", "v": "3"},
{"n": "2023", "v": "4"},
{"n": "2022", "v": "5"},
{"n": "2021", "v": "6"},
{"n": "2020", "v": "7"},
{"n": "2019", "v": "8"},
{"n": "2018", "v": "9"}]}]}}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
res = self.extract_middle_text(res, '<span>热门电影</span>', '<span>推荐明星</span>', 0)
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="swiper-wrapper cms-list-swiper")
for soup in soups:
vods = soup.find_all('div', class_="public-list-box")
for vod in vods:
names = vod.find('div', class_="public-list-div")
name = names.find('a')['title']
ids = vod.find('div', class_="public-list-div")
id = ids.find('a')['href']
pics = vod.find('a', class_="public-list-exp")
pic = pics.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'hide ft2">', '</span>', 0)
remark = remark.replace('\n', '').replace(' ', '')
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if '年代' in ext.keys():
NdType = ext['年代']
else:
NdType = ''
if page == '1':
url = f'{xurl}/vod/1/{cid}/0/0/0/0/0/0'
else:
url = f'{xurl}/vod/list/{str(page)}/{cid}/0/{NdType}/0/0/0/0'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="public-pic-b")
for vod in soups:
names = vod.find('a', class_="public-list-exp")
name = names.find('img')['alt']
ids = vod.find('div', class_="public-list-div")
id = ids.find('a')['href']
pics = vod.find('a', class_="public-list-exp")
pic = pics.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'hide ft2">', '</span>', 0)
remark = remark.replace('\n', '').replace(' ', '')
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
url = 'https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1732707176882/jiduo.txt'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '😸集多🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'描述:</strong>','</div>', 0)
content = content.replace('\n', '').replace(' ', '')
if name not in content:
bofang = Jumps
else:
bofang = self.extract_middle_text(res, '<ul class="anthology-list-play size">', '</ul>', 3,'href="(.*?)" class="hide">\s+(.*?)\s+</a>')
xianlu = self.extract_middle_text(res, '<div class="title-tab flex switch-button">','</div>',2, 'href=".*?" title=".*?">(.*?)</a>')
videos.append({
"vod_id": did,
"vod_actor": '集多和他的朋友们',
"vod_director": '集多',
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
if '/tp/jd.m3u8' in after_https:
url = after_https
else:
res = requests.get(url=after_https, headers=headerx)
res = res.text
url = self.extract_middle_text(res, 'u0026url=', "'", 0).replace('\\', '')
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/public/auto/search1.html?keyword={key}'
else:
url = f'{xurl}/public/auto/search1.html?keyword={key}&page={str(page)}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="public-list-box")
for vod in soups:
names = vod.find('a', class_="public-list-exp")
name = names.find('img')['alt']
ids = vod.find('div', class_="public-list-div")
id = ids.find('a')['href']
pics = vod.find('a', class_="public-list-exp")
pic = pics.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'hide ft2">', '</span>', 0)
remark = remark.replace('\n', '').replace(' ', '')
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+377
View File
@@ -0,0 +1,377 @@
"""
作者 凯悦宾馆 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from base.spider import Spider
from bs4 import BeautifulSoup
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.ccy1.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️丢丢👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️丢丢👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨丢丢👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "77", "type_name": "丢丢电影🌠"},
{"type_id": "78", "type_name": "丢丢剧集🌠"},
{"type_id": "80", "type_name": "丢丢动漫🌠"},
{"type_id": "164", "type_name": "丢丢4K🌠"},
{"type_id": "79", "type_name": "丢丢综艺🌠"},
{"type_id": "166", "type_name": "丢丢体育🌠"},
{"type_id": "170", "type_name": "丢丢演唱会🌠"},
{"type_id": "165", "type_name": "丢丢短剧🌠"}],
"list": [],
"filters": {"77": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"78": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"80": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"164": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"79": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"166": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"170": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}],
"165": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": "0"},
{"n": "80年代", "v": "42"},
{"n": "90年代", "v": "43"},
{"n": "00年代", "v": "44"},
{"n": "10年代", "v": "45"},
{"n": "20年代", "v": "46"}]}]}}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="hide-b-20")
if soups and len(soups) > 1:
soups = soups[1]
vods = soups.find_all('div', class_="public-list-box")
for vod in vods:
names = vod.find('div', class_="public-list-div")
name = names.find('a')['title']
id = names.find('a')['href']
pic = vod.find('img')['data-src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('span', class_="public-list-prb hide")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if '年代' in ext.keys():
NdType = ext['年代']
else:
NdType = ''
if page == '1':
url = f'{xurl}/vod/list/1/{cid}/0/0/0/0/0/0'
else:
url = f'{xurl}/vod/list/{str(page)}/{cid}/0/{NdType}/0/0/0/0'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="border-box")
for soup in soups:
vods = soup.find_all('div', class_="public-list-box")
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('a', class_="public-list-exp")
id = ids['href']
pic = vod.find('img')['src']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('span', class_="public-list-prb")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
url = 'https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1732697392729/didiu.txt'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '😸丢丢🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'class="text cor3" >','</div>', 0)
if name not in content:
bofang = Jumps
else:
bofang = self.extract_middle_text(res, '<ul class="anthology-list-play', '</ul>', 3, 'href="(.*?)" class="hide" style="width:100px">\s+(.*?)\s+</a>')
xianlu = self.extract_middle_text(res, '<div class="swiper-wrapper"','</div>',2, '</i>&nbsp;(.*?)</a>')
videos.append({
"vod_id": did,
"vod_actor": '😸皮皮 😸灰灰',
"vod_director": '😸丢丢',
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
if '239755956819.mp4' in after_https:
url = after_https
else:
res = requests.get(url=after_https, headers=headerx)
res = res.text
url = self.extract_middle_text(res, '?url=', "'", 0).replace('\\', '')
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+356
View File
@@ -0,0 +1,356 @@
"""
作者 凯悦推荐 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from base.spider import Spider
from bs4 import BeautifulSoup
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "https://www.subaibai.com"
headerx = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
'authority': 'www.subaibai.com',
'Referer': 'https://www.subaibai.com/',
'Origin': 'https://www.subaibai.com/'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️集多👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️集多👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨集多👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "new-movie", "type_name": "集多电影🌠"},
{"type_id": "tv-drama", "type_name": "集多剧集🌠"},
{"type_id": "hot-month", "type_name": "集多热门电影🌠"},
{"type_id": "high-movie", "type_name": "集多高分电影🌠"},
{"type_id": "cartoon-movie", "type_name": "集多动漫电影🌠"},
{"type_id": "hongkong-movie", "type_name": "集多香港经典🌠"},
{"type_id": "domestic-drama", "type_name": "集多国产剧🌠"},
{"type_id": "american-drama", "type_name": "集多欧美剧🌠"},
{"type_id": "korean-drama", "type_name": "集多韩剧🌠"},
{"type_id": "anime-drama", "type_name": "集多动漫剧🌠"}]
}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="bt_img")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('h3', class_="dytit")
id = ids.find('a')['href']
id = id.replace('www.subaibaiys.com', 'www.subaibai.com')
pic = vod.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'class="rating">', '</div>', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if page == '1':
url = f'{xurl}/{cid}'
else:
url = f'{xurl}/{cid}/page/{str(page)}'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="bt_img")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('h3', class_="dytit")
id = ids.find('a')['href']
id = id.replace('www.subaibaiys.com', 'www.subaibai.com')
pic = vod.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'class="rating">', '</div>', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
url = 'https://fs-im-kefu.7moor-fs1.com/ly/4d2c3f00-7d4c-11e5-af15-41bf63ae4ea0/1732707176882/jiduo.txt'
response = requests.get(url)
response.encoding = 'utf-8'
code = response.text
name = self.extract_middle_text(code, "s1='", "'", 0)
Jumps = self.extract_middle_text(code, "s2='", "'", 0)
content = '集多🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'<div class="yp_context">','</p>', 0)
content = content.replace('\t', '').replace('<p>', '').replace(' ', '').replace('\n', '')
if name not in content:
bofang = Jumps
else:
bofang = self.extract_middle_text(res, '<div class="paly_list_btn">', '</div>', 3, 'href="(.*?)">(.*?)</a>')
bofang = bofang.replace('www.subaibaiys.com', 'www.subaibai.com').replace('立即播放&nbsp;&nbsp;', '')
videos.append({
"vod_id": did,
"vod_actor": '集多和他的朋友们',
"vod_director": '集多',
"vod_content": content,
"vod_play_from": '集多专线',
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 1
if xiutan == 1:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = after_https
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/?s={key}'
else:
url = f'{xurl}//page/{str(page)}?s={key}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="bt_img")
for soup in soups:
vods = soup.find_all('li')
for vod in vods:
name = vod.find('img')['alt']
ids = vod.find('h3', class_="dytit")
id = ids.find('a')['href']
id = id.replace('www.subaibaiys.com', 'www.subaibai.com')
pic = vod.find('img')['data-original']
if 'http' not in pic:
pic = xurl + pic
remark = self.extract_middle_text(str(vod), 'class="rating">', '</div>', 0)
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": '集多▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+368
View File
@@ -0,0 +1,368 @@
"""
作者 凯悦宾馆 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
from Crypto.Util.Padding import unpad
from urllib.parse import unquote
from Crypto.Cipher import ARC4
from base.spider import Spider
from bs4 import BeautifulSoup
import urllib.request
import urllib.parse
import binascii
import requests
import base64
import json
import time
import sys
import re
import os
sys.path.append('..')
xurl = "http://img.shifen.me"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️丢丢👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️丢丢👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨丢丢👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "5", "type_name": "电影🌠"},
{"type_id": "14", "type_name": "剧集🌠"},
{"type_id": "19", "type_name": "动漫🌠"},
{"type_id": "23", "type_name": "综艺🌠"}]
}
return result
def homeVideoContent(self):
videos = []
try:
xurl1 = "http://42.194.235.17:20000/api/bt/list?genere_id&order&lang&keywords&code=unknownec1280db12795506&category_id=1&limit=24&channel=wandoujia&page=1&sort=update"
detail = requests.get(url=xurl1, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
for vod in data['data']:
name = vod['title']
id = vod['id']
id = f"http://42.194.235.17:20000/api/node/detail?channel=wandoujia&id={vod['id']}"
pic = vod['images']['poster']
remark = vod['torrents']['zh'][0]['title']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if pg:
page = int(pg)
else:
page = 1
if page == '1':
url = f'http://42.194.235.17:20000/api/bt/list?genere_id&order&lang&keywords&code=unknownec1280db12795506&category_id={cid}&limit=24&channel=wandoujia&page={str(page)}&sort=update'
else:
url = f'http://42.194.235.17:20000/api/bt/list?genere_id&order&lang&keywords&code=unknownec1280db12795506&category_id={cid}&limit=24&channel=wandoujia&page={str(page)}&sort=update'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
for vod in data['data']:
name = vod['title']
id = vod['id']
id = f"http://42.194.235.17:20000/api/node/detail?channel=wandoujia&id={id}"
pic = vod['images']['poster']
remark = vod['torrents']['zh'][0]['title']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
purl = ''
detail = requests.get(url=did, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
content = data['data']['description']
content = content.replace('\u3000', '').replace(' ', '').replace('\r', '').replace('\n', '')
for vod in data['data']['btbo_downlist']:
name = vod['title']
url1 = vod['url']
purl = purl + name + '$' + url1 + '#'
purl = purl[:-1]
videos.append({
"vod_id": did,
"vod_actor": '😸皮皮 😸灰灰',
"vod_director": '😸丢丢',
"vod_content": content,
"vod_play_from": '丢丢专线',
"vod_play_url": purl
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
result["parse"] = 0
result["playUrl"] = ''
result["url"] = id
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'http://42.194.235.17:20000/api/video/search?page={str(page)}&key={key}'
else:
url = f'http://42.194.235.17:20000/api/video/search?page={str(page)}&key={key}'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
if detail.status_code == 200:
data = detail.json()
for vod in data['data']:
name = vod['title']
id = vod['id']
id = f"http://42.194.235.17:20000/api/node/detail?channel=wandoujia&id={vod['id']}"
pic = vod['thumbnail']
remark = vod['mask']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
"""
=======================================
换行 \n 零个或者多个空格 \s+ 数字型 int 文本型 str 分页{} '年代':'2021'
性能要求高"lxml" 处理不规范的HTML"html5lib" 简单应用"html.parser" 解析XML"xml"
=======================================
/rss/index.xml?wd=爱情&page=1 搜索有验证
/index.php/ajax/suggest?mid=1&wd=爱情&page=1&limit=30 搜索有验证
/index.php/ajax/data?mid=1&tid={cateId}&class={class}&area={area}&page={catePg}&limit=30 分类有验证
/index.php/vod/type/class/{cid}/id/41/page/{str(page)}/year/{NdType}.html 隐藏分类
/{cateId}-{area}-{by}-{class}-{lang}-{letter}---{catePg}---{year}.html
短剧 穿越 古装 仙侠 女频 恋爱 反转 现代 都市 剧情 玄幻 脑洞 悬疑
=======================================
aaa = self.extract_middle_text(res, 'bbb', 'ccc', 0)
aaa = aaa.replace('aaa', '').replace('bbb', '') 替换多余
取头 取尾 (不循环) 截取项 (不循环) 长用于直链 二次截取 0号子程序
aaa =self.extract_middle_text(res, 'bbb', 'ccc',1,'html">(.*?)<')
aaa = aaa.replace('aaa', '').replace('bbb', '') 替换多余
取头 取尾 (不循环) 截取项 (循环) 长用于详情 和2号区别没有$$$ 1号子程序
aaa = self.extract_middle_text(res, 'bbb','ccc', 2,'<span class=".*?" id=".*?">(.*?)</span>')
aaa = aaa.replace('aaa', '').replace('bbb', '') 替换多余
取头 取尾 (不循环) 截取项 (循环) 只能用于线路数组 里面包含$$$ 2号子程序
aaa = self.extract_middle_text(res, 'bbb', 'ccc', 3,'href="(.*?)" class=".*?">(.*?)</a>')
aaa = aaa.replace('aaa', '').replace('bbb', '') 替换多余
取头 取尾 (循环) 截取项 (循环) 长用于播放数组 3号子程序
=======================================
"""
if __name__ == '__main__':
spider_instance = Spider()
# res=spider_instance.homeContent('filter') # 分类🚨
# res = spider_instance.homeVideoContent() # 首页🚨
# res=spider_instance.categoryContent('5', 1, 'filter', {}) # 分页🚨
res = spider_instance.detailContent(['http://42.194.235.17:20000/api/node/detail?channel=wandoujia&id=559366']) # 详情页🚨
# res = spider_instance.playerContent('1', 'http://42.194.235.17:20000/api/nUser/commentList?url_id=176366&page=1&token=', 'vipFlags') # 播放页🚨
# res = spider_instance.searchContentPage('爱情', 'quick', '1') # 搜索页🚨
print(res)
+199
View File
@@ -0,0 +1,199 @@
# coding=utf-8
# !/usr/bin/python
# by嗷呜
import sys
sys.path.append("..")
import re
from base.spider import Spider
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64encode, b64decode
import json
import time
class Spider(Spider):
def getName(self):
return "酷云"
def init(self, extend=""):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def action(self, action):
pass
def destroy(self):
pass
host = "https://sc1080.top"
t = str(int(time.time()))
def header(self):
header = {
"User-Agent": "okhttp/3.14.9",
"app-version-code": "134",
"app-ui-mode": "light",
"app-user-device-id": "25f869d32598d3d3089a929453dff0bb7",
"app-api-verify-time": self.t,
"app-api-verify-sign": self.aes("encrypt", self.t),
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
}
return header
def homeContent(self, filter):
data = self.fetch(
"{0}/api.php/getappapi.index/initV119".format(self.host),
headers=self.header(),
).json()
data1 = self.aes("decrypt", data["data"])
dy = {
"class": "类型",
"area": "地区",
"lang": "语言",
"year": "年份",
"letter": "字母",
"by": "排序",
"sort": "排序",
}
filters = {}
classes = []
json_data = json.loads(data1)["type_list"]
self.homedata = json.loads(data1)["banner_list"]
for item in json_data:
if item["type_name"] == "全部":
continue
has_non_empty_field = False
jsontype_extend = json.loads(item["type_extend"])
self.homedata.extend(item["recommend_list"])
jsontype_extend["sort"] = "最新,最热,最赞,日榜,月榜,周榜"
classes.append({"type_name": item["type_name"], "type_id": item["type_id"]})
for key in dy:
if key in jsontype_extend and jsontype_extend[key].strip() != "":
has_non_empty_field = True
break
if has_non_empty_field:
filters[str(item["type_id"])] = []
for dkey in jsontype_extend:
if dkey in dy and jsontype_extend[dkey].strip() != "":
values = jsontype_extend[dkey].split(",")
value_array = [
{"n": value.strip(), "v": value.strip()}
for value in values
if value.strip() != ""
]
filters[str(item["type_id"])].append(
{"key": dkey, "name": dy[dkey], "value": value_array}
)
result = {}
result["class"] = classes
result["filters"] = filters
return result
def homeVideoContent(self):
result = {"list": self.homedata}
return result
def categoryContent(self, tid, pg, filter, extend):
body = {
"area": extend.get('area', '全部'),
"year": extend.get('year', '全部'),
"type_id": tid,
"page": pg,
"sort": extend.get('sort', '最新'),
"lang": extend.get('lang', '全部'),
"class": extend.get('class', '全部')
}
result = {}
url = "{0}/api.php/getappapi.index/typeFilterVodList".format(self.host)
data = self.post(url, headers=self.header(), data=body).json()
data1 = self.aes("decrypt", data["data"])
result["list"] = json.loads(data1)["recommend_list"]
result["page"] = pg
result["pagecount"] = 9999
result["limit"] = 90
result["total"] = 999999
return result
def detailContent(self, ids):
body = f"vod_id={ids[0]}"
url = "{0}/api.php/getappapi.index/vodDetail".format(self.host)
data = self.post(url, headers=self.header(), data=body).json()
data1 = json.loads(self.aes("decrypt", data["data"]))
vod = data1["vod"]
play = []
names = []
for itt in data1["vod_play_list"]:
a = []
names.append(itt["player_info"]["show"])
parse = itt["player_info"]["parse"]
for it in itt["urls"]:
if re.search(r"mp4|m3u8", it["url"]):
a.append(f"{it['name']}${it['url']}")
else:
a.append(
f"{it['name']}${'parse_api=' + parse + '&url=' + self.aes('encrypt', it['url']) + '&token=' + it['token']}")
play.append("#".join(a))
vod["vod_play_from"] = "$$$".join(names)
vod["vod_play_url"] = "$$$".join(play)
result = {"list": [vod]}
return result
def searchContent(self, key, quick, pg=1):
body = f"keywords={key}&type_id=0&page={pg}"
url = "{0}/api.php/getappapi.index/searchList".format(self.host)
data = self.post(url, headers=self.header(), data=body).text
data1 = json.loads(data)["data"]
data2 = self.aes("decrypt", data1)
result = {"list": json.loads(data2)["search_list"],'page':pg}
return result
def playerContent(self, flag, id, vipFlags):
def edu(str):
def replacer(match):
from urllib.parse import quote_plus
return match.group(1) + quote_plus(match.group(2)) + match.group(3)
return re.sub(r"(url=)(.*?)(&token)", replacer, str)
url = id
if "m3u8" not in url and "mp4" not in url:
try:
body = edu(url)
data = self.post("{0}/api.php/getappapi.index/vodParse".format(self.host), headers=self.header(),
data=body).json()
data1 = json.loads(self.aes("decrypt", data["data"]))["json"]
url = json.loads(data1)["url"]
except Exception as e:
url = id
result = {}
headers = self.header().copy()
del headers["Content-Type"]
result["parse"] = 0
result["url"] = url
result["header"] = headers
return result
def localProxy(self, param):
pass
def aes(self, operation, text):
key = "e59d44b2eef03ba2".encode("utf-8")
iv = key
if operation == "encrypt":
cipher = AES.new(key, AES.MODE_CBC, iv)
ct_bytes = cipher.encrypt(pad(text.encode("utf-8"), AES.block_size))
ct = b64encode(ct_bytes).decode("utf-8")
return ct
elif operation == "decrypt":
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(b64decode(text)), AES.block_size)
return pt.decode("utf-8")
+373
View File
@@ -0,0 +1,373 @@
"""
作者 凯悦宾馆 🚓 内容均从互联网收集而来 仅供交流学习使用 版权归原创者所有 如侵犯了您的权益 请通知作者 将及时删除侵权内容
====================kaiyuebinguan====================
"""
import requests
from bs4 import BeautifulSoup
import re
from base.spider import Spider
import sys
import json
import base64
import urllib.parse
sys.path.append('..')
xurl = "https://www.tpua.vip"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36'
}
pm = ''
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def extract_middle_text(self, text, start_str, end_str, pl, start_index1: str = '', end_index2: str = ''):
if pl == 3:
plx = []
while True:
start_index = text.find(start_str)
if start_index == -1:
break
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
break
middle_text = text[start_index + len(start_str):end_index]
plx.append(middle_text)
text = text.replace(start_str + middle_text + end_str, '')
if len(plx) > 0:
purl = ''
for i in range(len(plx)):
matches = re.findall(start_index1, plx[i])
output = ""
for match in matches:
match3 = re.search(r'(?:^|[^0-9])(\d+)(?:[^0-9]|$)', match[1])
if match3:
number = match3.group(1)
else:
number = 0
if 'http' not in match[0]:
output += f"#{'📽️丢丢👉' + match[1]}${number}{xurl}{match[0]}"
else:
output += f"#{'📽️丢丢👉' + match[1]}${number}{match[0]}"
output = output[1:]
purl = purl + output + "$$$"
purl = purl[:-3]
return purl
else:
return ""
else:
start_index = text.find(start_str)
if start_index == -1:
return ""
end_index = text.find(end_str, start_index + len(start_str))
if end_index == -1:
return ""
if pl == 0:
middle_text = text[start_index + len(start_str):end_index]
return middle_text.replace("\\", "")
if pl == 1:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
jg = ' '.join(matches)
return jg
if pl == 2:
middle_text = text[start_index + len(start_str):end_index]
matches = re.findall(start_index1, middle_text)
if matches:
new_list = [f'✨丢丢👉{item}' for item in matches]
jg = '$$$'.join(new_list)
return jg
def homeContent(self, filter):
result = {}
result = {"class": [{"type_id": "dianying", "type_name": "丢丢电影🌠"},
{"type_id": "dianshiju", "type_name": "丢丢剧集🌠"},
{"type_id": "zongyi", "type_name": "丢丢动漫🌠"},
{"type_id": "duanju", "type_name": "丢丢短剧🌠"},
{"type_id": "dongman", "type_name": "丢丢综艺🌠"}],
"list": [],
"filters": {"dianying": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"dianshiju": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"duanju": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"zongyi": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}],
"dongman": [{"key": "年代",
"name": "年代",
"value": [{"n": "全部", "v": ""},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
{"n": "2019", "v": "2019"},
{"n": "2018", "v": "2018"}]}]}}
return result
def homeVideoContent(self):
videos = []
try:
detail = requests.get(url=xurl, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="clearfix")
for soup in soups:
vods = soup.find_all('a', class_="video-pic")
for vod in vods:
name = vod['title']
id = vod['href']
pic = vod['data-original']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('span', class_="note")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
result = {'list': videos}
return result
except:
pass
def categoryContent(self, cid, pg, filter, ext):
result = {}
if pg:
page = int(pg)
else:
page = 1
page = int(pg)
videos = []
if '年代' in ext.keys():
NdType = ext['年代']
else:
NdType = ''
if page == '1':
url = f'{xurl}/list/{cid}___2024__.html'
else:
url = f'{xurl}/list/{cid}___{NdType}___{str(page)}.html'
try:
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('ul', class_="clearfix")
for soup in soups:
vods = soup.find_all('a', class_="video-pic")
for vod in vods:
name = vod['title']
id = vod['href']
pic = vod['data-original']
if 'http' not in pic:
pic = xurl + pic
remarks = vod.find('span', class_="note")
remark = remarks.text.strip()
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
except:
pass
result = {'list': videos}
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
global pm
did = ids[0]
result = {}
videos = []
playurl = ''
if 'http' not in did:
did = xurl + did
res1 = requests.get(url=did, headers=headerx)
res1.encoding = "utf-8"
res = res1.text
content = '😸丢丢🎉为您介绍剧情📢本资源来源于网络🚓侵权请联系删除👉' + self.extract_middle_text(res,'details-content-all collapse">','</span>', 0)
content = content.replace('&lt;p&gt;', '').replace('&lt;br/&gt;', '').replace(' ', '').replace('&lt;/p&gt', '').replace('\u3000', '')
xianlu = self.extract_middle_text(res, '<ul class="nav nav-tabs hidden-xs"','</ul>',2, 'data-toggle=".*?">(.*?)</a>')
bofang = self.extract_middle_text(res, '<ul class="clearfix fade in active"', '</ul>', 3,'href="(.*?)">(.*?)<')
videos.append({
"vod_id": did,
"vod_actor": '😸皮皮 😸灰灰',
"vod_director": '😸丢丢',
"vod_content": content,
"vod_play_from": xianlu,
"vod_play_url": bofang
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
parts = id.split("http")
xiutan = 0
if xiutan == 0:
if len(parts) > 1:
before_https, after_https = parts[0], 'http' + parts[1]
res = requests.get(url=after_https, headers=headerx)
res = res.text
url = self.extract_middle_text(res, '","url":"', '"', 0).replace('\\', '')
result = {}
result["parse"] = xiutan
result["playUrl"] = ''
result["url"] = url
result["header"] = headerx
return result
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = '1'
if page == '1':
url = f'{xurl}/search/{key}-1.html'
else:
url = f'{xurl}/search/{key}-{str(page)}.html'
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
res = detail.text
doc = BeautifulSoup(res, "lxml")
soups = doc.find_all('div', class_="details-info-min")
for vod in soups:
names = vod.find('a', class_="video-pic")
name = names['title']
ids = vod.find('a', class_="video-pic")
id = ids['href']
pics = vod.find('a', class_="video-pic")
pic = pics['data-original']
remark = self.extract_middle_text(str(vod), '状态:</span>', '</li>', 0)
video = {
"vod_id": id,
"vod_name": '丢丢📽️' + name,
"vod_pic": pic,
"vod_remarks": '丢丢▶️' + remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None
+270
View File
@@ -0,0 +1,270 @@
# coding=utf-8
# !/usr/bin/python
import sys
import requests
from bs4 import BeautifulSoup
import re
import base64
from base.spider import Spider
import random
sys.path.append('..')
xurl = "https://heiliaowang-44.buzz"
headerx = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36',
}
class Spider(Spider):
global xurl
global headerx
def getName(self):
return "首页"
def init(self, extend):
pass
def destroy(self):
pass
def isVideoFormat(self, url):
pass
def manualVideoCheck(self):
pass
def homeContent(self, filter):
res = requests.get(xurl, headers=headerx)
res.encoding = "utf-8"
doc = BeautifulSoup(res.text, "html.parser")
sourcediv = doc.find('div', class_='nav')
vod = sourcediv.find_all('dd')
string_list = ["首页", "激情图漫", "激情小说",
"情色小说", "随机推荐", "顶级资源"]
result = {}
result['class'] = []
result['class'].append({'type_id': "/type/328", 'type_name': "国产视频"})
result['class'].append({'type_id': "/type/329", 'type_name': "中文字幕"})
result['class'].append({'type_id': "/type/331", 'type_name': "日本有码"})
result['class'].append({'type_id': "/type/332", 'type_name': "日本无码"})
result['class'].append({'type_id': "/type/333", 'type_name': "欧美无码"})
result['class'].append({'type_id': "/type/334", 'type_name': "强奸乱轮"})
result['class'].append({'type_id': "/type/335", 'type_name': "制服诱惑"})
result['class'].append({'type_id': "/type/336", 'type_name': "直播主播"})
result['class'].append({'type_id': "/type/338", 'type_name': "明星换脸"})
result['class'].append({'type_id': "/type/339", 'type_name': "抖阴视频"})
result['class'].append({'type_id': "/type/340", 'type_name': "女优明星"})
result['class'].append({'type_id': "/type/343", 'type_name': "网爆门"})
result['class'].append({'type_id': "/type/345", 'type_name': "伦理三级"})
result['class'].append({'type_id': "/type/346", 'type_name': "AV解说"})
result['class'].append({'type_id': "/type/347", 'type_name': "SM调教"})
result['class'].append({'type_id': "/type/348", 'type_name': "萝莉少女"})
result['class'].append({'type_id': "/type/349", 'type_name': "极品媚黑"})
result['class'].append({'type_id': "/type/350", 'type_name': "女同性恋"})
result['class'].append({'type_id': "/type/351", 'type_name': "玩偶姐姐"})
result['class'].append({'type_id': "/type/353", 'type_name': "人妖系列"})
result['class'].append({'type_id': "/type/373", 'type_name': "韩国主播"})
result['class'].append({'type_id': "/type/378", 'type_name': "VR视角"})
for item in vod:
name = item.find('a').text
if name in string_list:
continue
id = item.find('a')['href']
id = id.replace(".html", "")
result['class'].append({'type_id': id, 'type_name': name})
return result
def homeVideoContent(self):
videos = []
try:
res = requests.get(xurl, headers=headerx)
res.encoding = "utf-8"
doc = BeautifulSoup(res.text, "html.parser")
sourcediv = doc.find_all('div', class_='pic')
for vod in sourcediv:
ul_elements = vod.find_all('ul')
for item in ul_elements:
name = item.select_one("li a")['title']
pic = item.select_one("li a img")["src"]
remark = item.select_one("li a span").text
id = item.select_one("li a")['href']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
except:
pass
result = {'list': videos}
return result
def categoryContent(self, cid, pg, filter, ext):
result = {}
videos = []
if not pg:
pg = 1
url = xurl +cid + "/" + str(pg) + ".html"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
doc = BeautifulSoup(detail.text, "html.parser")
sourcediv = doc.find_all('div', class_='pic')
for vod in sourcediv:
ul_elements = vod.find_all('ul')
for item in ul_elements:
name = item.select_one("li a")['title']
pic = item.select_one("li a img")["src"]
remark = item.select_one("li a span").text
id = item.select_one("li a")['href']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
result['list'] = videos
result['page'] = pg
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def detailContent(self, ids):
did = ids[0]
videos = []
result = {}
res = requests.get(url=xurl + did, headers=headerx)
res.encoding = "utf-8"
doc = BeautifulSoup(res.text, "html.parser")
sourcediv = doc.find('div', style='padding-bottom: 10px;')
vod = sourcediv.find_all('a')
play_from = ""
play_url = ""
for item in vod:
play_from = play_from + item.text + "$$$"
play_url = play_url + item['href'] + "$$$"
while play_url[-1] == "#" or play_url[-1] == "$":
play_url = play_url[:-1]
while play_from[-1] == "#" or play_from[-1] == "$":
play_from = play_from[:-1]
source_match = re.search(r"<li>播放地址:<strong>(.*?)</strong></li>", res.text)
if source_match:
tx = source_match.group(1)
videos.append({
"vod_id": did,
"vod_name": tx,
"vod_pic": "",
"type_name": "ぃぅおか🍬 คิดถึง",
"vod_year": "",
"vod_area": "",
"vod_remarks": "",
"vod_actor": "",
"vod_director": "",
"vod_content": "",
"vod_play_from": play_from,
"vod_play_url": play_url
})
result['list'] = videos
return result
def playerContent(self, flag, id, vipFlags):
result = {}
res = requests.get(url=xurl + id, headers=headerx)
res.encoding = "utf-8"
if '"rid"' in res.text:
decoded_str = ''
while not decoded_str:
source_match3 = re.search(r'"rid" : "(.*?)"', res.text)
if source_match3:
id = source_match3.group(1)
data = "rid=" + id
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36",
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
res2 = requests.post(url="https://heiliaowang-44.buzz/fetchPlayUrl3", headers=header, data=data)
source_match4 = re.search(r'"returnData"\s*:\s*"([^"]+)"', res2.text)
if source_match4:
decoded_str = source_match4.group(1)
else:
source_match = re.search(r"http:(.*?)\.m3u8", res.text)
decoded_str = ""
if source_match:
str3 = source_match.group(1)
if "aHR0c" in str3:
padding_needed = len(str3) % 4
if padding_needed:
str3 += '=' * (4 - padding_needed)
decoded_str = base64.b64decode(str3).decode("utf-8")
if not decoded_str:
source_match2 = re.search(r"'(.*?)\.m3u8';", res.text)
if source_match2:
decoded_str = source_match2.group(1) + ".m3u8"
result["parse"] = 0
result["playUrl"] = ''
result["url"] = decoded_str
result["header"] = headerx
return result
def searchContent(self, key, quick):
return self.searchContentPage(key, quick, '1')
def searchContentPage(self, key, quick, page):
result = {}
videos = []
if not page:
page = 1
url = xurl +"/search/"+ key +"/n/" + str(page)+".html"
detail = requests.get(url=url, headers=headerx)
detail.encoding = "utf-8"
doc = BeautifulSoup(detail.text, "html.parser")
sourcediv = doc.find_all('div', class_='pic')
for vod in sourcediv:
ul_elements = vod.find_all('ul')
for item in ul_elements:
name = item.select_one("li a")['title']
pic = item.select_one("li a img")["src"]
remark = item.select_one("li a span").text
id = item.select_one("li a")['href']
video = {
"vod_id": id,
"vod_name": name,
"vod_pic": pic,
"vod_remarks": remark
}
videos.append(video)
result['list'] = videos
result['page'] = page
result['pagecount'] = 9999
result['limit'] = 90
result['total'] = 999999
return result
def localProxy(self, params):
if params['type'] == "m3u8":
return self.proxyM3u8(params)
elif params['type'] == "media":
return self.proxyMedia(params)
elif params['type'] == "ts":
return self.proxyTs(params)
return None