123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- # -*- coding: utf-8 -*-
- # by @嗷呜
- import json
- import re
- import sys
- import time
- from base64 import b64decode, b64encode
- from urllib.parse import parse_qs
- import requests
- from pyquery import PyQuery as pq
- sys.path.append('..')
- from base.spider import Spider
- from concurrent.futures import ThreadPoolExecutor
- class Spider(Spider):
- def init(self, extend=""):
- tid = 'douyin'
- headers = self.gethr(0, tid)
- response = requests.head(self.hosts[tid], headers=headers)
- ttwid = response.cookies.get('ttwid')
- headers.update({
- 'authority': self.hosts[tid].split('//')[-1],
- 'cookie': f'ttwid={ttwid}' if ttwid else ''
- })
- self.dyheaders = headers
- pass
- def getName(self):
- pass
- def isVideoFormat(self, url):
- pass
- def manualVideoCheck(self):
- pass
- def destroy(self):
- pass
- headers = [
- {
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"
- },
- {
- "User-Agent": "Dart/3.4 (dart:io)"
- }
- ]
- excepturl = 'https://www.baidu.com'
- hosts = {
- "huya": ["https://www.huya.com","https://mp.huya.com"],
- "douyin": "https://live.douyin.com",
- "douyu": "https://www.douyu.com",
- "wangyi": "https://cc.163.com",
- "bili": ["https://api.live.bilibili.com", "https://api.bilibili.com"]
- }
- referers = {
- "huya": "https://live.cdn.huya.com",
- "douyin": "https://live.douyin.com",
- "douyu": "https://m.douyu.com",
- "bili": "https://live.bilibili.com"
- }
- playheaders = {
- "wangyi": {
- "User-Agent": "ExoPlayer",
- "Connection": "Keep-Alive",
- "Icy-MetaData": "1"
- },
- "bili": {
- 'Accept': '*/*',
- 'Icy-MetaData': '1',
- 'referer': referers['bili'],
- 'user-agent': headers[0]['User-Agent']
- },
- 'douyin': {
- 'User-Agent': 'libmpv',
- 'Icy-MetaData': '1'
- },
- 'huya': {
- 'User-Agent': 'ExoPlayer',
- 'Connection': 'Keep-Alive',
- 'Icy-MetaData': '1'
- },
- 'douyu': {
- 'User-Agent': 'libmpv',
- 'Icy-MetaData': '1'
- }
- }
- def process_bili(self):
- try:
- self.blfdata = self.fetch(
- f'{self.hosts["bili"][0]}/room/v1/Area/getList?need_entrance=1&parent_id=0',
- headers=self.gethr(0, 'bili')
- ).json()
- return ('bili', [{'key': 'cate', 'name': '分类',
- 'value': [{'n': i['name'], 'v': str(i['id'])}
- for i in self.blfdata['data']]}])
- except Exception as e:
- print(f"bili处理错误: {e}")
- return 'bili', None
- def process_douyin(self):
- try:
- data = self.getpq(self.hosts['douyin'], headers=self.dyheaders)('script')
- for i in data.items():
- if 'categoryData' in i.text():
- content = i.text()
- start = content.find('{')
- end = content.rfind('}') + 1
- if start != -1 and end != -1:
- json_str = content[start:end]
- json_str = json_str.replace('\\"', '"')
- try:
- self.dyifdata = json.loads(json_str)
- return ('douyin', [{'key': 'cate', 'name': '分类',
- 'value': [{'n': i['partition']['title'],
- 'v': f"{i['partition']['id_str']}@@{i['partition']['title']}"}
- for i in self.dyifdata['categoryData']]}])
- except json.JSONDecodeError as e:
- print(f"douyin解析错误: {e}")
- return 'douyin', None
- except Exception as e:
- print(f"douyin请求或处理错误: {e}")
- return 'douyin', None
- def process_douyu(self):
- try:
- self.dyufdata = self.fetch(
- f'{self.referers["douyu"]}/api/cate/list',
- headers=self.headers[1]
- ).json()
- return ('douyu', [{'key': 'cate', 'name': '分类',
- 'value': [{'n': i['cate1Name'], 'v': str(i['cate1Id'])}
- for i in self.dyufdata['data']['cate1Info']]}])
- except Exception as e:
- print(f"douyu错误: {e}")
- return 'douyu', None
- def homeContent(self, filter):
- result = {}
- cateManual = {
- "虎牙": "huya",
- "哔哩": "bili",
- "抖音": "douyin",
- "斗鱼": "douyu",
- "网易": "wangyi"
- }
- classes = []
- filters = {
- 'huya': [{'key': 'cate', 'name': '分类',
- 'value': [{'n': '网游', 'v': '1'}, {'n': '单机', 'v': '2'},
- {'n': '娱乐', 'v': '8'}, {'n': '手游', 'v': '3'}]}]
- }
- with ThreadPoolExecutor(max_workers=3) as executor:
- futures = {
- executor.submit(self.process_bili): 'bili',
- executor.submit(self.process_douyin): 'douyin',
- executor.submit(self.process_douyu): 'douyu'
- }
- for future in futures:
- platform, filter_data = future.result()
- if filter_data:
- filters[platform] = filter_data
- for k in cateManual:
- classes.append({
- 'type_name': k,
- 'type_id': cateManual[k]
- })
- result['class'] = classes
- result['filters'] = filters
- return result
- def homeVideoContent(self):
- pass
- def categoryContent(self, tid, pg, filter, extend):
- vdata = []
- result = {}
- pagecount = 9999
- result['page'] = pg
- result['limit'] = 90
- result['total'] = 999999
- if tid == 'wangyi':
- vdata, pagecount = self.wyccContent(tid, pg, filter, extend, vdata)
- elif 'bili' in tid:
- vdata, pagecount = self.biliContent(tid, pg, filter, extend, vdata)
- elif 'huya' in tid:
- vdata, pagecount = self.huyaContent(tid, pg, filter, extend, vdata)
- elif 'douyin' in tid:
- vdata, pagecount = self.douyinContent(tid, pg, filter, extend, vdata)
- elif 'douyu' in tid:
- vdata, pagecount = self.douyuContent(tid, pg, filter, extend, vdata)
- result['list'] = vdata
- result['pagecount'] = pagecount
- return result
- def wyccContent(self, tid, pg, filter, extend, vdata):
- params = {
- 'format': 'json',
- 'start': (int(pg) - 1) * 20,
- 'size': '20',
- }
- response = self.fetch(f'{self.hosts[tid]}/api/category/live/', params=params, headers=self.headers[0]).json()
- for i in response['lives']:
- if i.get('cuteid'):
- bvdata = self.buildvod(
- vod_id=f"{tid}@@{i['cuteid']}",
- vod_name=i.get('title'),
- vod_pic=i.get('cover'),
- vod_remarks=i.get('nickname'),
- style={"type": "rect", "ratio": 1.33}
- )
- vdata.append(bvdata)
- return vdata, 9999
- def biliContent(self, tid, pg, filter, extend, vdata):
- if extend.get('cate') and pg == '1' and 'click' not in tid:
- for i in self.blfdata['data']:
- if str(i['id']) == extend['cate']:
- for j in i['list']:
- v = self.buildvod(
- vod_id=f"click_{tid}@@{i['id']}@@{j['id']}",
- vod_name=j.get('name'),
- vod_pic=j.get('pic'),
- vod_tag=1,
- style={"type": "oval", "ratio": 1}
- )
- vdata.append(v)
- return vdata, 1
- else:
- path = f'/xlive/web-interface/v1/second/getListByArea?platform=web&sort=online&page_size=30&page={pg}'
- if 'click' in tid:
- ids = tid.split('_')[1].split('@@')
- tid = ids[0]
- path = f'/xlive/web-interface/v1/second/getList?platform=web&parent_area_id={ids[1]}&area_id={ids[-1]}&sort_type=&page={pg}'
- data = self.fetch(f'{self.hosts[tid][0]}{path}', headers=self.gethr(0, tid)).json()
- for i in data['data']['list']:
- if i.get('roomid'):
- data = self.buildvod(
- f"{tid}@@{i['roomid']}",
- i.get('title'),
- i.get('cover'),
- i.get('watched_show', {}).get('text_large'),
- 0,
- i.get('uname'),
- style={"type": "rect", "ratio": 1.33}
- )
- vdata.append(data)
- return vdata, 9999
- def huyaContent(self, tid, pg, filter, extend, vdata):
- if extend.get('cate') and pg == '1' and 'click' not in tid:
- id = extend.get('cate')
- data = self.fetch(f'{self.referers[tid]}/liveconfig/game/bussLive?bussType={id}',
- headers=self.headers[1]).json()
- for i in data['data']:
- v = self.buildvod(
- vod_id=f"click_{tid}@@{int(i['gid'])}",
- vod_name=i.get('gameFullName'),
- vod_pic=f'https://huyaimg.msstatic.com/cdnimage/game/{int(i["gid"])}-MS.jpg',
- vod_tag=1,
- style={"type": "oval", "ratio": 1}
- )
- vdata.append(v)
- return vdata, 1
- else:
- gid = ''
- if 'click' in tid:
- ids = tid.split('_')[1].split('@@')
- tid = ids[0]
- gid = f'&gameId={ids[1]}'
- data = self.fetch(f'{self.hosts[tid][0]}/cache.php?m=LiveList&do=getLiveListByPage&tagAll=0{gid}&page={pg}',
- headers=self.headers[1]).json()
- for i in data['data']['datas']:
- if i.get('profileRoom'):
- v = self.buildvod(
- f"{tid}@@{i['profileRoom']}",
- i.get('introduction'),
- i.get('screenshot'),
- str(int(i.get('totalCount', '1')) / 10000) + '万',
- 0,
- i.get('nick'),
- style={"type": "rect", "ratio": 1.33}
- )
- vdata.append(v)
- return vdata, 9999
- def douyinContent(self, tid, pg, filter, extend, vdata):
- if extend.get('cate') and pg == '1' and 'click' not in tid:
- ids = extend.get('cate').split('@@')
- for i in self.dyifdata['categoryData']:
- c = i['partition']
- if c['id_str'] == ids[0] and c['title'] == ids[1]:
- vlist = i['sub_partition'].copy()
- vlist.insert(0, {'partition': c})
- for j in vlist:
- j = j['partition']
- v = self.buildvod(
- vod_id=f"click_{tid}@@{j['id_str']}@@{j['type']}",
- vod_name=j.get('title'),
- vod_pic='https://p3-pc-weboff.byteimg.com/tos-cn-i-9r5gewecjs/pwa_v3/512x512-1.png',
- vod_tag=1,
- style={"type": "oval", "ratio": 1}
- )
- vdata.append(v)
- return vdata, 1
- else:
- path = f'/webcast/web/partition/detail/room/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&count=15&offset={(int(pg) - 1) * 15}&partition=720&partition_type=1'
- if 'click' in tid:
- ids = tid.split('_')[1].split('@@')
- tid = ids[0]
- path = f'/webcast/web/partition/detail/room/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&count=15&offset={(int(pg) - 1) * 15}&partition={ids[1]}&partition_type={ids[-1]}&req_from=2'
- data = self.fetch(f'{self.hosts[tid]}{path}', headers=self.dyheaders).json()
- for i in data['data']['data']:
- v = self.buildvod(
- vod_id=f"{tid}@@{i['web_rid']}",
- vod_name=i['room'].get('title'),
- vod_pic=i['room']['cover'].get('url_list')[0],
- vod_year=i.get('user_count_str'),
- vod_remarks=i['room']['owner'].get('nickname'),
- style={"type": "rect", "ratio": 1.33}
- )
- vdata.append(v)
- return vdata, 9999
- def douyuContent(self, tid, pg, filter, extend, vdata):
- if extend.get('cate') and pg == '1' and 'click' not in tid:
- for i in self.dyufdata['data']['cate2Info']:
- if str(i['cate1Id']) == extend['cate']:
- v = self.buildvod(
- vod_id=f"click_{tid}@@{i['cate2Id']}",
- vod_name=i.get('cate2Name'),
- vod_pic=i.get('icon'),
- vod_remarks=i.get('count'),
- vod_tag=1,
- style={"type": "oval", "ratio": 1}
- )
- vdata.append(v)
- return vdata, 1
- else:
- path = f'/japi/weblist/apinc/allpage/6/{pg}'
- if 'click' in tid:
- ids = tid.split('_')[1].split('@@')
- tid = ids[0]
- path = f'/gapi/rkc/directory/mixList/2_{ids[1]}/{pg}'
- url = f'{self.hosts[tid]}{path}'
- data = self.fetch(url, headers=self.headers[1]).json()
- for i in data['data']['rl']:
- v = self.buildvod(
- vod_id=f"{tid}@@{i['rid']}",
- vod_name=i.get('rn'),
- vod_pic=i.get('rs16'),
- vod_year=str(int(i.get('ol', 1)) / 10000) + '万',
- vod_remarks=i.get('nn'),
- style={"type": "rect", "ratio": 1.33}
- )
- vdata.append(v)
- return vdata, 9999
- def detailContent(self, ids):
- ids = ids[0].split('@@')
- if ids[0] == 'wangyi':
- vod = self.wyccDetail(ids)
- elif ids[0] == 'bili':
- vod = self.biliDetail(ids)
- elif ids[0] == 'huya':
- vod = self.huyaDetail(ids)
- elif ids[0] == 'douyin':
- vod = self.douyinDetail(ids)
- elif ids[0] == 'douyu':
- vod = self.douyuDetail(ids)
- return {'list': [vod]}
- def wyccDetail(self, ids):
- try:
- vdata = self.getpq(f'{self.hosts[ids[0]]}/{ids[1]}', self.headers[0])('script').eq(-1).text()
- def get_quality_name(vbr):
- if vbr <= 600:
- return "标清"
- elif vbr <= 1000:
- return "高清"
- elif vbr <= 2000:
- return "超清"
- else:
- return "蓝光"
- data = json.loads(vdata)['props']['pageProps']['roomInfoInitData']
- name = data['live'].get('title', ids[0])
- vod = self.buildvod(vod_name=data.get('keywords_suffix'), vod_remarks=data['live'].get('title'),
- vod_content=data.get('description_suffix'))
- resolution_data = data['live']['quickplay']['resolution']
- all_streams = {}
- sorted_qualities = sorted(resolution_data.items(),
- key=lambda x: x[1]['vbr'],
- reverse=True)
- for quality, data in sorted_qualities:
- vbr = data['vbr']
- quality_name = get_quality_name(vbr)
- for cdn_name, url in data['cdn'].items():
- if cdn_name not in all_streams and type(url) == str and url.startswith('http'):
- all_streams[cdn_name] = []
- if isinstance(url, str) and url.startswith('http'):
- all_streams[cdn_name].extend([quality_name, url])
- plists = []
- names = []
- for i, (cdn_name, stream_list) in enumerate(all_streams.items(), 1):
- names.append(f'线路{i}')
- pstr = f"{name}${ids[0]}@@{self.e64(json.dumps(stream_list))}"
- plists.append(pstr)
- vod['vod_play_from'] = "$$$".join(names)
- vod['vod_play_url'] = "$$$".join(plists)
- return vod
- except Exception as e:
- return self.handle_exception(e)
- def biliDetail(self, ids):
- try:
- vdata = self.fetch(
- f'{self.hosts[ids[0]][0]}/xlive/web-room/v1/index/getInfoByRoom?room_id={ids[1]}&wts={int(time.time())}',
- headers=self.gethr(0, ids[0])).json()
- v = vdata['data']['room_info']
- vod = self.buildvod(
- vod_name=v.get('title'),
- type_name=v.get('parent_area_name') + '/' + v.get('area_name'),
- vod_remarks=v.get('tags'),
- vod_play_from=v.get('title'),
- )
- data = self.fetch(
- f'{self.hosts[ids[0]][0]}/xlive/web-room/v2/index/getRoomPlayInfo?room_id={ids[1]}&protocol=0%2C1&format=0%2C1%2C2&codec=0%2C1&platform=web',
- headers=self.gethr(0, ids[0])).json()
- vdnams = data['data']['playurl_info']['playurl']['g_qn_desc']
- all_accept_qns = []
- streams = data['data']['playurl_info']['playurl']['stream']
- for stream in streams:
- for format_item in stream['format']:
- for codec in format_item['codec']:
- if 'accept_qn' in codec:
- all_accept_qns.append(codec['accept_qn'])
- max_accept_qn = max(all_accept_qns, key=len) if all_accept_qns else []
- quality_map = {
- item['qn']: item['desc']
- for item in vdnams
- }
- quality_names = [f"{quality_map.get(qn)}${ids[0]}@@{ids[1]}@@{qn}" for qn in max_accept_qn]
- vod['vod_play_url'] = "#".join(quality_names)
- return vod
- except Exception as e:
- return self.handle_exception(e)
- def huyaDetail(self, ids):
- try:
- vdata = self.fetch(f'{self.hosts[ids[0]][1]}/cache.php?m=Live&do=profileRoom&roomid={ids[1]}',
- headers=self.headers[0]).json()
- v = vdata['data']['liveData']
- vod = self.buildvod(
- vod_name=v.get('introduction'),
- type_name=v.get('gameFullName'),
- vod_director=v.get('nick'),
- vod_remarks=v.get('contentIntro'),
- )
- data = dict(reversed(list(vdata['data']['stream'].items())))
- names = []
- plist = []
- for stream_type, stream_data in data.items():
- if isinstance(stream_data, dict) and 'multiLine' in stream_data and 'rateArray' in stream_data:
- names.append(f"线路{len(names) + 1}")
- qualities = sorted(
- stream_data['rateArray'],
- key=lambda x: (x['iBitRate'], x['sDisplayName']),
- reverse=True
- )
- cdn_urls = []
- for cdn in stream_data['multiLine']:
- quality_urls = []
- for quality in qualities:
- quality_name = quality['sDisplayName']
- bit_rate = quality['iBitRate']
- base_url = cdn['url']
- if bit_rate > 0:
- if '.m3u8' in base_url:
- new_url = base_url.replace(
- 'ratio=2000',
- f'ratio={bit_rate}'
- )
- else:
- new_url = base_url.replace(
- 'imgplus.flv',
- f'imgplus_{bit_rate}.flv'
- )
- else:
- new_url = base_url
- quality_urls.extend([quality_name, new_url])
- encoded_urls = self.e64(json.dumps(quality_urls))
- cdn_urls.append(f"{cdn['cdnType']}${ids[0]}@@{encoded_urls}")
- if cdn_urls:
- plist.append('#'.join(cdn_urls))
- vod['vod_play_from'] = "$$$".join(names)
- vod['vod_play_url'] = "$$$".join(plist)
- return vod
- except Exception as e:
- return self.handle_exception(e)
- def douyinDetail(self, ids):
- url = f'{self.hosts[ids[0]]}/webcast/room/web/enter/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&enter_from=web_live&web_rid={ids[1]}&room_id_str=&enter_source=&Room-Enter-User-Login-Ab=0&is_need_double_stream=false&cookie_enabled=true&screen_width=1980&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=125.0.0.0'
- data = self.fetch(url, headers=self.dyheaders).json()
- try:
- vdata = data['data']['data'][0]
- vod = self.buildvod(
- vod_name=vdata['title'],
- vod_remarks=vdata['user_count_str'],
- )
- resolution_data = vdata['stream_url']['live_core_sdk_data']['pull_data']['options']['qualities']
- stream_json = vdata['stream_url']['live_core_sdk_data']['pull_data']['stream_data']
- stream_json = json.loads(stream_json)
- available_types = []
- if any(sdk_key in stream_json['data'] and 'main' in stream_json['data'][sdk_key] for sdk_key in
- stream_json['data']):
- available_types.append('main')
- if any(sdk_key in stream_json['data'] and 'backup' in stream_json['data'][sdk_key] for sdk_key in
- stream_json['data']):
- available_types.append('backup')
- plist = []
- for line_type in available_types:
- format_arrays = {'flv': [], 'hls': [], 'lls': []}
- qualities = sorted(resolution_data, key=lambda x: x['level'], reverse=True)
- for quality in qualities:
- sdk_key = quality['sdk_key']
- if sdk_key in stream_json['data'] and line_type in stream_json['data'][sdk_key]:
- stream_info = stream_json['data'][sdk_key][line_type]
- if stream_info.get('flv'):
- format_arrays['flv'].extend([quality['name'], stream_info['flv']])
- if stream_info.get('hls'):
- format_arrays['hls'].extend([quality['name'], stream_info['hls']])
- if stream_info.get('lls'):
- format_arrays['lls'].extend([quality['name'], stream_info['lls']])
- format_urls = []
- for format_name, url_array in format_arrays.items():
- if url_array:
- encoded_urls = self.e64(json.dumps(url_array))
- format_urls.append(f"{format_name}${ids[0]}@@{encoded_urls}")
- if format_urls:
- plist.append('#'.join(format_urls))
- names = ['线路1', '线路2'][:len(plist)]
- vod['vod_play_from'] = "$$$".join(names)
- vod['vod_play_url'] = "$$$".join(plist)
- return vod
- except Exception as e:
- return self.handle_exception(e)
- def douyuDetail(self, ids):
- headers = self.gethr(0, zr=f'{self.hosts[ids[0]]}/{ids[1]}')
- try:
- data = self.fetch(f'{self.hosts[ids[0]]}/betard/{ids[1]}', headers=headers).json()
- vname = data['room']['room_name']
- vod = self.buildvod(
- vod_name=vname,
- vod_remarks=data['room'].get('second_lvl_name'),
- vod_director=data['room'].get('nickname'),
- )
- vdata = self.fetch(f'{self.hosts[ids[0]]}/swf_api/homeH5Enc?rids={ids[1]}', headers=headers).json()
- json_body = vdata['data']
- json_body = {"html": self.douyu_text(json_body[f'room{ids[1]}']), "rid": ids[1]}
- sign = self.post('http://alive.nsapps.cn/api/AllLive/DouyuSign', json=json_body, headers=self.headers[1]).json()['data']
- body = f'{sign}&cdn=&rate=-1&ver=Douyu_223061205&iar=1&ive=1&hevc=0&fa=0'
- body=self.params_to_json(body)
- nubdata = self.post(f'{self.hosts[ids[0]]}/lapi/live/getH5Play/{ids[1]}', data=body, headers=headers).json()
- plist = []
- names = []
- for i,x in enumerate(nubdata['data']['cdnsWithName']):
- names.append(f'线路{i+1}')
- d = {'sign': sign, 'cdn': x['cdn'], 'id': ids[1]}
- plist.append(
- f'{vname}${ids[0]}@@{self.e64(json.dumps(d))}@@{self.e64(json.dumps(nubdata["data"]["multirates"]))}')
- vod['vod_play_from'] = "$$$".join(names)
- vod['vod_play_url'] = "$$$".join(plist)
- return vod
- except Exception as e:
- return self.handle_exception(e)
- def douyu_text(self, text):
- function_positions = [m.start() for m in re.finditer('function', text)]
- total_functions = len(function_positions)
- if total_functions % 2 == 0:
- target_index = total_functions // 2 + 1
- else:
- target_index = (total_functions - 1) // 2 + 1
- if total_functions >= target_index:
- cut_position = function_positions[target_index - 1]
- ctext = text[4:cut_position]
- return re.sub(r'eval\(strc\)\([\w\d,]+\)', 'strc', ctext)
- return text
- def searchContent(self, key, quick, pg="1"):
- pass
- def playerContent(self, flag, id, vipFlags):
- try:
- ids = id.split('@@')
- p = 1
- if ids[0] in ['wangyi', 'douyin','huya']:
- p, url = 0, json.loads(self.d64(ids[1]))
- elif ids[0] == 'bili':
- p, url = self.biliplay(ids)
- elif ids[0] == 'huya':
- p, url = 0, json.loads(self.d64(ids[1]))
- elif ids[0] == 'douyu':
- p, url = self.douyuplay(ids)
- return {'parse': p, 'url': url, 'header': self.playheaders[ids[0]]}
- except Exception as e:
- return {'parse': 1, 'url': self.excepturl, 'header': self.headers[0]}
- def biliplay(self, ids):
- try:
- data = self.fetch(
- f'{self.hosts[ids[0]][0]}/xlive/web-room/v2/index/getRoomPlayInfo?room_id={ids[1]}&protocol=0,1&format=0,2&codec=0&platform=web&qn={ids[2]}',
- headers=self.gethr(0, ids[0])).json()
- urls = []
- line_index = 1
- for stream in data['data']['playurl_info']['playurl']['stream']:
- for format_item in stream['format']:
- for codec in format_item['codec']:
- for url_info in codec['url_info']:
- full_url = f"{url_info['host']}/{codec['base_url'].lstrip('/')}{url_info['extra']}"
- urls.extend([f"线路{line_index}", full_url])
- line_index += 1
- return 0, urls
- except Exception as e:
- return 1, self.excepturl
- def douyuplay(self, ids):
- try:
- sdata = json.loads(self.d64(ids[1]))
- headers = self.gethr(0, zr=f'{self.hosts[ids[0]]}/{sdata["id"]}')
- ldata = json.loads(self.d64(ids[2]))
- result_obj = {}
- with ThreadPoolExecutor(max_workers=len(ldata)) as executor:
- futures = [
- executor.submit(
- self.douyufp,
- sdata,
- quality,
- headers,
- self.hosts[ids[0]],
- result_obj
- ) for quality in ldata
- ]
- for future in futures:
- future.result()
- result = []
- for bit in sorted(result_obj.keys(), reverse=True):
- result.extend(result_obj[bit])
- if result:
- return 0, result
- return 1, self.excepturl
- except Exception as e:
- return 1, self.excepturl
- def douyufp(self, sdata, quality, headers, host, result_obj):
- try:
- body = f'{sdata["sign"]}&cdn={sdata["cdn"]}&rate={quality["rate"]}'
- body=self.params_to_json(body)
- data = self.post(f'{host}/lapi/live/getH5Play/{sdata["id"]}',
- data=body, headers=headers).json()
- if data.get('data'):
- play_url = data['data']['rtmp_url'] + '/' + data['data']['rtmp_live']
- bit = quality.get('bit', 0)
- if bit not in result_obj:
- result_obj[bit] = []
- result_obj[bit].extend([quality['name'], play_url])
- except Exception as e:
- print(f"Error fetching {quality['name']}: {str(e)}")
- def localProxy(self, param):
- pass
- def e64(self, text):
- try:
- text_bytes = text.encode('utf-8')
- encoded_bytes = b64encode(text_bytes)
- return encoded_bytes.decode('utf-8')
- except Exception as e:
- print(f"Base64编码错误: {str(e)}")
- return ""
- def d64(self, encoded_text):
- try:
- encoded_bytes = encoded_text.encode('utf-8')
- decoded_bytes = b64decode(encoded_bytes)
- return decoded_bytes.decode('utf-8')
- except Exception as e:
- print(f"Base64解码错误: {str(e)}")
- return ""
- def josn_to_params(self, params, skip_empty=False):
- query = []
- for k, v in params.items():
- if skip_empty and not v:
- continue
- query.append(f"{k}={v}")
- return "&".join(query)
- def params_to_json(self, query_string):
- parsed_data = parse_qs(query_string)
- result = {key: value[0] for key, value in parsed_data.items()}
- return result
- def buildvod(self, vod_id='', vod_name='', vod_pic='', vod_year='', vod_tag='', vod_remarks='', style='',
- type_name='', vod_area='', vod_actor='', vod_director='',
- vod_content='', vod_play_from='', vod_play_url=''):
- vod = {
- 'vod_id': vod_id,
- 'vod_name': vod_name,
- 'vod_pic': vod_pic,
- 'vod_year': vod_year,
- 'vod_tag': 'folder' if vod_tag else '',
- 'vod_remarks': vod_remarks,
- 'style': style,
- 'type_name': type_name,
- 'vod_area': vod_area,
- 'vod_actor': vod_actor,
- 'vod_director': vod_director,
- 'vod_content': vod_content,
- 'vod_play_from': vod_play_from,
- 'vod_play_url': vod_play_url
- }
- vod = {key: value for key, value in vod.items() if value}
- return vod
- def getpq(self, url, headers=None, cookies=None):
- data = self.fetch(url, headers=headers, cookies=cookies).text
- try:
- return pq(data)
- except Exception as e:
- print(f"解析页面错误: {str(e)}")
- return pq(data.encode('utf-8'))
- def gethr(self, index, rf='', zr=''):
- headers = self.headers[index]
- if zr:
- headers['referer'] = zr
- else:
- headers['referer'] = f"{self.referers[rf]}/"
- return headers
- def handle_exception(self, e):
- print(f"报错: {str(e)}")
- return {'vod_play_from': '哎呀翻车啦', 'vod_play_url': f'翻车啦${self.excepturl}'}
|