修复抖音直播及弹幕录制 (#626)

* 修复抖音直播及弹幕录制

* 修复抖音直播及弹幕录制
This commit is contained in:
⁢4.435km/s authored and GitHub committed 2023-09-05 15:46:06 +00:00
1 parent 3d3efa4247
commit e5019fcd71
2 files changed
+63 -30

No files matched your search

+10 -16
View File
@@ -2,7 +2,6 @@
# 2023.07.14:KNaiFen:这部分代码参考了https://github.com/SmallPeaches/DanmakuRender
import gzip
import time
import aiohttp
import json
@@ -15,9 +14,6 @@ from google.protobuf import json_format
class Douyin:
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'Referer': 'https://live.douyin.com/',
'Cookie': config.get('user', {}).get('douyin_cookie', '')
@@ -28,6 +24,7 @@ class Douyin:
@staticmethod
async def get_ws_info(url):
async with aiohttp.ClientSession() as session:
from biliup.plugins.douyin import DouyinUtils
if "/user/" in url:
async with session.get(url, headers=Douyin.headers, timeout=5) as resp:
user_page = await resp.text()
@@ -36,22 +33,19 @@ class Douyin:
room_id = match1(user_page_data, r'"web_rid":"([^"]+)"')
else:
room_id = url.split('douyin.com/')[1].split('/')[0].split('?')[0]
if room_id[0] == "+":
room_id = room_id[1:]
if room_id.isdigit():
room_id = f"+{room_id}"
async with session.get(f'https://live.douyin.com/{room_id}', headers=Douyin.headers, timeout=5) as resp:
page = await resp.text()
if "ttwid" not in Douyin.headers['Cookie'] and "ttwid" in resp.cookies:
Douyin.headers['Cookie'] = f'ttwid={resp.cookies.get("ttwid").value};{Douyin.headers["Cookie"]}'
data = json.loads(
unquote(
page.split('<script id="RENDER_DATA" type="application/json">')[1].split('</script>')[0]))
real_rid = data['app']['initialState']['roomStore']['roomInfo']['roomId']
user_unique_id = data['app']['odin']['user_unique_id']
if "ttwid" not in Douyin.headers['Cookie']:
Douyin.headers['Cookie'] = f'ttwid={DouyinUtils.get_ttwid()};{Douyin.headers["Cookie"]}'
url = f"wss://webcast3-ws-web-lf.douyin.com/webcast/im/push/v2/?app_name=douyin_web&version_code=180800&webcast_sdk_version=1.3.0&update_version_code=1.3.0&compress=gzip&internal_ext=internal_src:dim|wss_push_room_id:{real_rid}|wss_push_did:{user_unique_id}|dim_log_id:2023011316221327ACACF0E44A2C0E8200|fetch_time:${int(time.time())}123|seq:1|wss_info:0-1673598133900-0-0|wrds_kvs:WebcastRoomRankMessage-1673597852921055645_WebcastRoomStatsMessage-1673598128993068211&cursor=u-1_h-1_t-1672732684536_r-1_d-1&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&debug=false&endpoint=live_pc&support_wrds=1&im_path=/webcast/im/fetch/&device_platform=web&cookie_enabled=true&screen_width=1228&screen_height=691&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0%20Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/92.0.4515.159%20Safari/537.36&browser_online=true&tz_name=Asia/Shanghai&identity=audience&room_id={real_rid}&heartbeatDuration=0&signature=00000000"
async with session.get(
DouyinUtils.build_request_url(f"https://live.douyin.com/webcast/room/web/enter/?web_rid={room_id}"),
headers=Douyin.headers, timeout=5) as resp:
room_info = json.loads(await resp.text())['data']['data'][0]
url = DouyinUtils.build_request_url(
f"wss://webcast3-ws-web-lf.douyin.com/webcast/im/push/v2/?room_id={room_info['id_str']}&compress=gzip&signature=00000000")
return url, []
@staticmethod
+53 -14
View File
@@ -1,12 +1,14 @@
import json
from urllib.parse import unquote
from typing import Optional
from urllib.parse import unquote, urlparse, parse_qs, urlencode, urlunparse
import requests
from . import logger, match1
from biliup.config import config
from .Danmaku import DanmakuClient
from ..common.tools import NamedLock
from ..engine.decorators import Plugin
from ..engine.download import DownloadBase
from biliup.plugins.Danmaku import DanmakuClient
@Plugin.download(regexp=r'(?:https?://)?(?:(?:www|m|live)\.)?douyin\.com')
@@ -27,8 +29,11 @@ class Douyin(DownloadBase):
if room_id is None or not room_id:
logger.debug(f"{Douyin.__name__}: {self.url}: 未开播")
return False
except (KeyError, IndexError):
logger.warning(f"{Douyin.__name__}: {self.url}: 获取房间ID失败,请检查Cookie设置")
return False
except:
logger.warning(f"{Douyin.__name__}: {self.url}: 获取房间ID错误")
logger.warning(f"{Douyin.__name__}: {self.url}: 获取房间ID失败")
return False
else:
try:
@@ -41,19 +46,19 @@ class Douyin(DownloadBase):
if room_id[0] == "+":
room_id = room_id[1:]
if room_id.isdigit():
room_id = f"+{room_id}"
try:
page = requests.get(f"https://live.douyin.com/{room_id}", headers=self.fake_headers, timeout=5).text
page_data = unquote(
page.split('<script id="RENDER_DATA" type="application/json">')[1].split('</script>')[0])
room_info = json.loads(page_data)['app']['initialState']['roomStore']['roomInfo']['room']
except (KeyError, IndexError):
logger.warning(f"{Douyin.__name__}: {self.url}: 获取错误,请检查Cookie设置")
return False
if "ttwid" not in self.fake_headers['Cookie']:
self.fake_headers['Cookie'] = f'ttwid={DouyinUtils.get_ttwid()};{self.fake_headers["Cookie"]}'
page = requests.get(
DouyinUtils.build_request_url(f"https://live.douyin.com/webcast/room/web/enter/?web_rid={room_id}"),
headers=self.fake_headers, timeout=5).text
room_info = json.loads(page)['data']['data']
if len(room_info) > 0:
room_info = room_info[0]
else:
room_info = {}
except:
logger.warning(f"{Douyin.__name__}: {self.url}: 获取错误")
logger.warning(f"{Douyin.__name__}: {self.url}: 获取失败")
return False
try:
@@ -111,3 +116,37 @@ class Douyin(DownloadBase):
def close(self):
if self.danmaku:
self.danmaku.stop()
class DouyinUtils:
# 抖音ttwid
_douyin_ttwid: Optional[str] = None
@staticmethod
def get_ttwid() -> Optional[str]:
with NamedLock("douyin_ttwid_get"):
if not DouyinUtils._douyin_ttwid:
page = requests.get("https://live.douyin.com/1-2-3-4-5-6-7-8-9-0", timeout=5)
DouyinUtils._douyin_ttwid = page.cookies.get("ttwid")
return DouyinUtils._douyin_ttwid
@staticmethod
def build_request_url(url: str) -> str:
parsed_url = urlparse(url)
existing_params = parse_qs(parsed_url.query)
existing_params['aid'] = ['6383']
existing_params['device_platform'] = ['web']
existing_params['browser_language'] = ['zh-CN']
existing_params['browser_platform'] = ['Win32']
existing_params['browser_name'] = ['Chrome']
existing_params['browser_version'] = ['92.0.4515.159']
new_query_string = urlencode(existing_params, doseq=True)
new_url = urlunparse((
parsed_url.scheme,
parsed_url.netloc,
parsed_url.path,
parsed_url.params,
new_query_string,
parsed_url.fragment
))
return new_url