diff --git a/biliup/common/Daemon.py b/biliup/common/Daemon.py index 3d79f56..506ad2a 100644 --- a/biliup/common/Daemon.py +++ b/biliup/common/Daemon.py @@ -121,4 +121,5 @@ class Daemon(object): def _run(self): """ run your fun""" - asyncio.run(self.fn()) + loop = asyncio.get_event_loop() + loop.run_until_complete(self.fn()) diff --git a/biliup/engine/download.py b/biliup/engine/download.py index 27a95e1..f0134fd 100644 --- a/biliup/engine/download.py +++ b/biliup/engine/download.py @@ -64,7 +64,9 @@ class DownloadBase: filename = f'{self.fname}%Y-%m-%dT%H_%M_%S' filename = get_valid_filename(filename) fmtname = time.strftime(filename.encode("unicode-escape").decode()).encode().decode("unicode-escape") - threading.Thread(target=asyncio.run, args=(self.danmaku_download_start(fmtname),)).start() + # threading.Thread(target=asyncio.run, args=(self.danmaku_download_start(fmtname),)).start() + loop = asyncio.new_event_loop() + threading.Thread(target=loop.run_until_complete, args=(self.danmaku_download_start(fmtname),)).start() if self.downloader == 'stream-gears': stream_gears_download(self.raw_stream_url, self.fake_headers, filename, config.get('segment_time'), config.get('file_size')) @@ -168,8 +170,17 @@ class DownloadBase: i = 0 logger.info('开始下载%s:%s' % (self.__class__.__name__, self.fname)) date = time.localtime() + lasttime_download = 0 + thistime_download = 0 + delay = config.get('delay') if (config.get('delay') > 5) else 5 while i < 30: try: + # 限制每次拉流的时间间隔必须大于config.get('delay'),防止主播还没推流的时候疯狂重复请求 + thistime_download = time.time() + interval = thistime_download - lasttime_download + if interval < delay: + logger.info(f"频繁请求:等待{interval}秒后再次请求直播流") + time.sleep(config.get('delay') - interval) ret = self.run() except: logger.exception("Uncaught exception:") @@ -177,21 +188,17 @@ class DownloadBase: finally: self.close() if ret is False: - if i < 4: - logger.info(f"获取直播流失败{i},等待5秒尝试重新获取") - time.sleep(5) - i += 1 - continue - else: - if config.get('delay'): - time.sleep(config.get('delay')) - logger.info(f"delay: {config.get('delay')}") - if self.check_stream(): - time.sleep(5) - continue + if config.get('delay'): + time.sleep(config.get('delay')) + logger.info(f"delay: {config.get('delay')}") + if self.check_stream(): + time.sleep(5) + continue break elif ret == 1 or self.downloader == 'stream-gears': time.sleep(45) + + lasttime_download = thistime_download i += 1 logger.info(f'退出下载{i}: {self.fname}') return { diff --git a/biliup/engine/upload.py b/biliup/engine/upload.py index 7c13282..7a6db69 100644 --- a/biliup/engine/upload.py +++ b/biliup/engine/upload.py @@ -34,7 +34,7 @@ class UploadBase: def filter_file(self, index): - media_extensions = ['.mp4', '.flv', '.ts'] + media_extensions = ['.mp4', '.flv', '.ts', '.flv.part'] file_list = UploadBase.file_list(index) if len(file_list) == 0: return False @@ -53,10 +53,16 @@ class UploadBase: logger.info(f'过滤删除-{r}') if ext == '.xml': #过滤不存在对应视频的xml弹幕文件 xml_file_name = name - media_regex = re.compile(r'^{}(\.(mp4|flv|ts))?$'.format( - re.escape(xml_file_name) - )) - if not any(media_regex.match(f'{xml_file_name}{ext2}') for ext2 in media_extensions for x in file_list): + # media_regex = re.compile(r'^{}(\.(mp4|flv|ts))?$'.format( + # re.escape(xml_file_name) + # )) + # if not any(media_regex.match(f'{xml_file_name}{ext2}') for ext2 in media_extensions for x in file_list): + # self.remove_file(r) + # logger.info(f'无视频,已过滤删除-{r}') + have_video = False + for video_ext in media_extensions: + if f"{xml_file_name}{video_ext}" in file_list: have_video = True + if not have_video: self.remove_file(r) logger.info(f'无视频,已过滤删除-{r}') file_list = UploadBase.file_list(index) diff --git a/biliup/plugins/Danmaku/__init__.py b/biliup/plugins/Danmaku/__init__.py index 632f90d..616dadf 100644 --- a/biliup/plugins/Danmaku/__init__.py +++ b/biliup/plugins/Danmaku/__init__.py @@ -1,5 +1,6 @@ # 部分弹幕功能代码来自项目:https://github.com/IsoaSFlus/danmaku,感谢大佬 # 快手弹幕代码来源及思路:https://github.com/py-wuhao/ks_barrage,感谢大佬 +# 部分斗鱼录播修复代码与思路来源于:https://github.com/SmallPeaches/DanmakuRender,感谢大佬 # 仅抓取用户弹幕,不包括入场提醒、礼物赠送等。 import asyncio @@ -7,6 +8,7 @@ import os import re import ssl import time +import logging from functools import partial import lxml.etree as etree @@ -16,7 +18,9 @@ import aiohttp from biliup.plugins.Danmaku.douyu import Douyu from biliup.plugins.Danmaku.huya import Huya from biliup.plugins.Danmaku.bilibili import Bilibili +from biliup.plugins.Danmaku.twitch import Twitch +logger = logging.getLogger('biliup') __all__ = ['DanmakuClient'] @@ -37,7 +41,7 @@ class DanmakuClient: self.__url = url else: self.__url = 'http://' + url - for u, s in {'douyu.com': Douyu, 'huya.com': Huya, 'live.bilibili.com': Bilibili}.items(): + for u, s in {'douyu.com': Douyu, 'huya.com': Huya, 'live.bilibili.com': Bilibili, 'twitch.tv': Twitch}.items(): if re.match(r'^(?:http[s]?://)?.*?%s/(.+?)$' % u, url): self.__site = s self.__u = u @@ -50,39 +54,56 @@ class DanmakuClient: ws_url, reg_datas = await self.__site.get_ws_info(self.__url) ctx = ssl.create_default_context() ctx.set_ciphers('DEFAULT') - self.__ws = await self.__hs.ws_connect(ws_url, ssl_context=ctx) - if reg_datas: + try: + self.__ws = await self.__hs.ws_connect(ws_url, ssl_context=ctx) for reg_data in reg_datas: - await self.__ws.send_bytes(reg_data) + if type(reg_data) == str: + await self.__ws.send_str(reg_data) + else: + await self.__ws.send_bytes(reg_data) + except Exception as Error: + logger.debug(f"init_ws:捕获到异常:{Error}") if not os.path.exists(self.__filename): async with aiofiles.open(self.__filename, mode='w') as f: await f.write("\n" - "\n" - "" - ) + "\n" + "" + ) async def heartbeats(self): while not self.__stop and self.__site.heartbeat: await asyncio.sleep(self.__site.heartbeatInterval) try: - await self.__ws.send_bytes(self.__site.heartbeat) + if type(self.__site.heartbeat) == str: + await self.__ws.send_str(self.__site.heartbeat) + else: + await self.__ws.send_bytes(self.__site.heartbeat) except Exception as Error: - print(f"捕获到异常:{Error}") + logger.debug(f"heartbeats:捕获到异常:{Error}") + if not self.__stop: + logger.info(f'触发弹幕重连') + await self.init_ws() + await asyncio.sleep(3) + await self.__hs.close() async def fetch_danmaku(self): # while not self.__stop: - await asyncio.sleep(1) - await self.init_ws() - await asyncio.sleep(1) - async for msg in self.__ws: + await asyncio.sleep(1) + await self.init_ws() + await asyncio.sleep(1) + async for msg in self.__ws: + try: if self.__stop: await self.__dm_queue.put(None) return - self.__link_status = True + # self.__link_status = True ms = self.__site.decode_msg(msg.data) for m in ms: await self.__dm_queue.put(m) + except Exception as Error: + logger.debug(f"fetch_danmaku:弹幕处理异常:{Error}") + await asyncio.sleep(10) async def print_danmaku(self): parser = etree.XMLParser(recover=True) @@ -102,7 +123,6 @@ class DanmakuClient: m = await self.__dm_queue.get() if m is None: return - # print(m) if m['msg_type'] == 'danmaku': d = etree.SubElement(root, 'd') if 'col' in m: @@ -114,16 +134,20 @@ class DanmakuClient: msg_time = format(time.time() - self.__starttime, '.3f') d.set('p', f"{msg_time},1,25,{color},0,0,0,0") d.text = m["content"] - - if msg_i >= 5: - loop = asyncio.get_running_loop() - await loop.run_in_executor(None, partial(write_file, self.__filename)) - msg_i = 0 - else: - msg_i = msg_i + 1 - except Exception as Error: - print(f"捕获到异常:{Error}") + logger.debug(f"print_danmaku:弹幕处理异常:{Error}") + + try: + if m['msg_type'] == 'danmaku' and msg_i >= 5: + # loop = asyncio.get_running_loop() + # await loop.run_in_executor(None, partial(write_file, self.__filename)) + write_file(self.__filename) + msg_i = 0 + else: + msg_i = msg_i + 1 + except Exception as Error: + logger.debug(f"print_danmaku:弹幕写入异常:{Error}") + async def start(self): self.__dm_queue = asyncio.Queue() @@ -134,10 +158,10 @@ class DanmakuClient: self.fetch_danmaku(), self.print_danmaku(), ) - print("弹幕录制结束") def stop(self): self.__stop = True + self.__hs.close() if not (os.path.exists(f"{self.__filename_video_suffix}.part") or os.path.exists(f"{self.__filename_video_suffix}")): os.remove(self.__filename) diff --git a/biliup/plugins/Danmaku/douyu.py b/biliup/plugins/Danmaku/douyu.py index 82dc511..5c5667b 100644 --- a/biliup/plugins/Danmaku/douyu.py +++ b/biliup/plugins/Danmaku/douyu.py @@ -6,10 +6,9 @@ import aiohttp class Douyu: - wss_url = 'wss://danmuproxy.douyu.com:8503/' - heartbeat = b'\x14\x00\x00\x00\x14\x00\x00\x00\xb1\x02\x00\x00\x74\x79\x70\x65\x40\x3d\x6d\x72\x6b\x6c' \ - b'\x2f\x00 ' - heartbeatInterval = 60 + wss_url = 'wss://danmuproxy.douyu.com:8506/' + heartbeat = b"\x14\x00\x00\x00\x14\x00\x00\x00\xb1\x02\x00\x00\x74\x79\x70\x65\x40\x3d\x6d\x72\x6b\x6c\x2f\x00" + heartbeatInterval = 30 @staticmethod async def get_ws_info(url): @@ -47,5 +46,6 @@ class Douyu: msga['col'] = msg.get('col', '0') msgs.append(msga) except Exception as Error: - print(f"捕获到异常:{Error}") + # print(f"decode_msg:捕获到异常:{Error}") + pass return msgs diff --git a/biliup/plugins/Danmaku/huya.py b/biliup/plugins/Danmaku/huya.py index 7ab9625..29c4c3d 100644 --- a/biliup/plugins/Danmaku/huya.py +++ b/biliup/plugins/Danmaku/huya.py @@ -16,37 +16,41 @@ class Huya: @staticmethod async def get_ws_info(url): - reg_datas = [] - url = 'https://m.huya.com/' + url.split('/')[-1] - headers = { - 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, ' - 'like Gecko) Chrome/79.0.3945.88 Mobile Safari/537.36'} - async with aiohttp.ClientSession() as session: - async with session.get(url, headers=headers) as resp: - room_page = await resp.text() - m = re.search(r"lYyid\":([0-9]+)", room_page, re.MULTILINE) - ayyuid = m.group(1) - m = re.search(r"lChannelId\":([0-9]+)", room_page, re.MULTILINE) - tid = m.group(1) - m = re.search(r"lSubChannelId\":([0-9]+)", room_page, re.MULTILINE) - sid = m.group(1) + try: + reg_datas = [] + url = 'https://m.huya.com/' + url.split('/')[-1] + headers = { + 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, ' + 'like Gecko) Chrome/79.0.3945.88 Mobile Safari/537.36'} + async with aiohttp.ClientSession() as session: + async with session.get(url, headers=headers) as resp: + room_page = await resp.text() + m = re.search(r"lYyid\":([0-9]+)", room_page, re.MULTILINE) + ayyuid = m.group(1) + m = re.search(r"lChannelId\":([0-9]+)", room_page, re.MULTILINE) + tid = m.group(1) + m = re.search(r"lSubChannelId\":([0-9]+)", room_page, re.MULTILINE) + sid = m.group(1) - oos = tarscore.TarsOutputStream() - oos.write(tarscore.int64, 0, int(ayyuid)) - oos.write(tarscore.boolean, 1, True) # Anonymous - oos.write(tarscore.string, 2, "") # sGuid - oos.write(tarscore.string, 3, "") - oos.write(tarscore.int64, 4, int(tid)) - oos.write(tarscore.int64, 5, int(sid)) - oos.write(tarscore.int64, 6, 0) - oos.write(tarscore.int64, 7, 0) + oos = tarscore.TarsOutputStream() + oos.write(tarscore.int64, 0, int(ayyuid)) + oos.write(tarscore.boolean, 1, True) # Anonymous + oos.write(tarscore.string, 2, "") # sGuid + oos.write(tarscore.string, 3, "") + oos.write(tarscore.int64, 4, int(tid)) + oos.write(tarscore.int64, 5, int(sid)) + oos.write(tarscore.int64, 6, 0) + oos.write(tarscore.int64, 7, 0) - wscmd = tarscore.TarsOutputStream() - wscmd.write(tarscore.int32, 0, 1) - wscmd.write(tarscore.bytes, 1, oos.getBuffer()) + wscmd = tarscore.TarsOutputStream() + wscmd.write(tarscore.int32, 0, 1) + wscmd.write(tarscore.bytes, 1, oos.getBuffer()) - reg_datas.append(wscmd.getBuffer()) - return Huya.wss_url, reg_datas + reg_datas.append(wscmd.getBuffer()) + except: + print("huya:get_ws_info()执行错误") + finally: + return Huya.wss_url, reg_datas @staticmethod def decode_msg(data): diff --git a/biliup/plugins/Danmaku/twitch.py b/biliup/plugins/Danmaku/twitch.py new file mode 100644 index 0000000..a240c1d --- /dev/null +++ b/biliup/plugins/Danmaku/twitch.py @@ -0,0 +1,42 @@ +import random +import re + + +class Twitch: + heartbeat = "PING" + heartbeatInterval = 40 + + @staticmethod + async def get_ws_info(url): + reg_datas = [] + room_id = re.search(r"/([^/?]+)[^/]*$", url).group(1) + + reg_datas.append("CAP REQ :twitch.tv/tags twitch.tv/commands twitch.tv/membership") + reg_datas.append("PASS SCHMOOPIIE") + nick = f"justinfan{int(8e4 * random.random() + 1e3)}" + reg_datas.append(f"NICK {nick}") + reg_datas.append(f"USER {nick} 8 * :{nick}") + reg_datas.append(f"JOIN #{room_id}") + + return "wss://irc-ws.chat.twitch.tv", reg_datas + + @staticmethod + def decode_msg(data): + msgs = [] + if data is not None: + for d in data.splitlines(): + msgt = {} + try: + msgt["content"] = re.search(r"PRIVMSG [^:]+:(.+)", d).group(1) + msgt["name"] = re.search(r"display-name=([^;]+);", d).group(1) + # if msgt["content"][0] == '@': continue # 丢掉表情符号 + c = re.search(r"color=#([a-zA-Z0-9]{6});", d).group(1) + msgt["color"] = int(c, 16) + msgt["msg_type"] = "danmaku" + # print(msgt) + msgs.append(msgt) + except Exception as Error: + # print(f"twitch:decode_msg:捕获到异常:{Error}") + # traceback.print_exc() + pass + return msgs diff --git a/biliup/plugins/douyu.py b/biliup/plugins/douyu.py index 0be15a8..1647b3f 100644 --- a/biliup/plugins/douyu.py +++ b/biliup/plugins/douyu.py @@ -7,6 +7,10 @@ from ..engine.decorators import Plugin from ..engine.download import DownloadBase from ..plugins import logger +# import http.client +# http.client.HTTPConnection._http_vsn = 10 +# http.client.HTTPConnection._http_vsn_str = 'HTTP/1.0' + @Plugin.download(regexp=r'(?:https?://)?(?:(?:www|m)\.)?douyu\.com') class Douyu(DownloadBase): @@ -16,29 +20,40 @@ class Douyu(DownloadBase): def check_stream(self): if len(self.url.split("douyu.com/")) < 2: - logger.debug("直播间地址:" + self.url + " 错误") + logger.error("斗鱼:" + self.url + ":地址错误") return False - html = requests.get(self.url).text - vid = match1(html, r'\$ROOM\.room_id\s*=\s*(\d+)', - r'room_id\s*=\s*(\d+)', - r'"room_id.?":(\d+)', - r'data-onlineid=(\d+)') - if not vid: - logger.debug("直播间" + vid + ":被关闭或不存在") + + try: + html = requests.get(self.url).text + vid = match1(html, r'\$ROOM\.room_id\s*=\s*(\d+)', + r'room_id\s*=\s*(\d+)', + r'"room_id.?":(\d+)', + r'data-onlineid=(\d+)') + if not vid: + logger.debug("斗鱼:" + self.url + ":被关闭或不存在") + return False + except: + logger.warning("斗鱼:" + self.url + ":获取vid错误") return False - roominfo = requests.get(f"https://www.douyu.com/betard/{vid}").json()['room'] - if roominfo['show_status'] != 1 or roominfo['videoLoop'] != 0: - logger.debug("直播间" + vid + ":未开播或正在放录播") + + try: + roominfo = requests.get(f"https://www.douyu.com/betard/{vid}").json()['room'] + if roominfo['show_status'] != 1 or roominfo['videoLoop'] != 0: + logger.debug("斗鱼:" + vid + ":未开播或正在放录播") + return False + self.room_title = roominfo['room_name'] + html_h5enc = requests.get(f'https://www.douyu.com/swf_api/homeH5Enc?rids={vid}').json() + js_enc = html_h5enc['data']['room' + vid] + params = { + 'cdn': config.get('douyucdn', 'tct-h5'), + 'iar': 0, + 'ive': 0, + 'rate': 0, + } + except: + logger.warning("斗鱼:" + vid + ":获取roominfo错误") return False - self.room_title = roominfo['room_name'] - html_h5enc = requests.get(f'https://www.douyu.com/swf_api/homeH5Enc?rids={vid}').json() - js_enc = html_h5enc['data']['room' + vid] - params = { - 'cdn': config.get('douyucdn', 'tct-h5'), - 'iar': 0, - 'ive': 0, - 'rate': 0, - } + try: ub98484234(js_enc, vid, params) except: @@ -62,9 +77,15 @@ class Douyu(DownloadBase): logger.info("结束弹幕录制") def get_play_info(vid, headers, params): - html_content = requests.post(f'https://www.douyu.com/lapi/live/getH5Play/{vid}', headers=headers, params=params).json() - live_data = html_content["data"] + try: + html_content = requests.post(f'https://www.douyu.com/lapi/live/getH5Play/{vid}', headers=headers, params=params).json() + live_data = html_content["data"] + except: + logger.warning(f"douyu:get_play_info:请求出错:https://www.douyu.com/lapi/live/getH5Play/{vid}") + return None # 禁用斗鱼主线路 + if not type(live_data) == type({}): + return live_data if not live_data['rtmp_cdn'].endswith('h5') or 'akm' in live_data['rtmp_cdn']: params['cdn'] = 'tct-h5' return get_play_info(vid, headers, params) diff --git a/biliup/plugins/huya.py b/biliup/plugins/huya.py index 1852dd8..90f2331 100644 --- a/biliup/plugins/huya.py +++ b/biliup/plugins/huya.py @@ -22,6 +22,7 @@ class Huya(DownloadBase): try: res = requests.get(self.url, timeout=5, headers=self.fake_headers) except: + logger.warning("虎牙:" + self.url + ":获取res错误") return False finally: res.close() @@ -35,26 +36,30 @@ class Huya(DownloadBase): else: huya = None if huya: - huyacdn = config.get('huyacdn', 'AL') - huyajson1 = json.loads(huya)['data'][0]['gameStreamInfoList'] - huyajson2 = json.loads(huya)['vMultiStreamInfo'] - ratio = huyajson2[0]['iBitRate'] - ibitrate_list = [] - sdisplayname_list = [] - for key in huyajson2: - ibitrate_list.append(key['iBitRate']) - sdisplayname_list.append(key['sDisplayName']) - if len(sdisplayname_list) > len(set(sdisplayname_list)): - ratio = max(ibitrate_list) - huyajson = huyajson1[0] - for cdn in huyajson1: - if cdn['sCdnType'] == huyacdn: - huyajson = cdn - absurl = f'{huyajson["sFlvUrl"]}/{huyajson["sStreamName"]}.{huyajson["sFlvUrlSuffix"]}?' \ - f'{huyajson["sFlvAntiCode"]}' - self.raw_stream_url = html.unescape(absurl) + "&ratio=" + str(ratio) - self.room_title = json.loads(huya)['data'][0]['gameLiveInfo']['introduction'] - return True + try: + huyacdn = config.get('huyacdn', 'AL') + huyajson1 = json.loads(huya)['data'][0]['gameStreamInfoList'] + huyajson2 = json.loads(huya)['vMultiStreamInfo'] + ratio = huyajson2[0]['iBitRate'] + ibitrate_list = [] + sdisplayname_list = [] + for key in huyajson2: + ibitrate_list.append(key['iBitRate']) + sdisplayname_list.append(key['sDisplayName']) + if len(sdisplayname_list) > len(set(sdisplayname_list)): + ratio = max(ibitrate_list) + huyajson = huyajson1[0] + for cdn in huyajson1: + if cdn['sCdnType'] == huyacdn: + huyajson = cdn + absurl = f'{huyajson["sFlvUrl"]}/{huyajson["sStreamName"]}.{huyajson["sFlvUrlSuffix"]}?' \ + f'{huyajson["sFlvAntiCode"]}' + self.raw_stream_url = html.unescape(absurl) + "&ratio=" + str(ratio) + self.room_title = json.loads(huya)['data'][0]['gameLiveInfo']['introduction'] + return True + except: + logger.warning("虎牙:" + self.url + ":json解析错误") + return False async def danmaku_download_start(self, filename): if self.huya_danmaku: diff --git a/biliup/plugins/twitch.py b/biliup/plugins/twitch.py index 431bcd0..009d4c8 100644 --- a/biliup/plugins/twitch.py +++ b/biliup/plugins/twitch.py @@ -10,6 +10,7 @@ from ..engine.decorators import Plugin from ..engine.download import DownloadBase from ..plugins import BatchCheckBase from biliup.config import config +from biliup.plugins.Danmaku import DanmakuClient VALID_URL_BASE = r'(?:https?://)?(?:(?:www|go|m)\.)?twitch\.tv/(?P[0-9_a-zA-Z]+)' _OPERATION_HASHES = { @@ -86,6 +87,7 @@ class TwitchVideos(DownloadBase): class Twitch(DownloadBase): def __init__(self, fname, url, suffix='flv'): DownloadBase.__init__(self, fname, url, suffix=suffix) + self.twitch_danmaku = config.get('twitch_danmaku', False) self.proc = None def check_stream(self): @@ -123,7 +125,16 @@ class Twitch(DownloadBase): self.raw_stream_url = info['formats'][-1]['url'] return True + async def danmaku_download_start(self, filename): + if self.twitch_danmaku: + logger.info("开始弹幕录制") + self.danmaku = DanmakuClient(self.url, filename + "." + self.suffix) + await self.danmaku.start() + def close(self): + if self.twitch_danmaku: + self.danmaku.stop() + logger.info("结束弹幕录制") try: if self.proc is not None: self.proc.terminate() diff --git a/public/config.toml b/public/config.toml index 03b4285..290694c 100644 --- a/public/config.toml +++ b/public/config.toml @@ -44,7 +44,7 @@ check_sourcecode = 15 -#########各平台分设置######### +#########各平台录播设置######### ### 使用直播间封面作为投稿封面。此封面优先级低于单个主播指定的自定义封面。(目前仅支持bilibili。直播封面将会保存于cover文件夹下,请自行定期删除) #use_live_cover = true @@ -119,6 +119,12 @@ check_sourcecode = 15 ### 仅下载该日期之前的视频(可与上面的youtube_after_date配合使用,构成指定下载范围区间) #youtube_before_date = '20230501' +#------Twitch------# +# 录制Twitch弹幕,只有使用FFMPEG作为下载器才支持,默认关闭 +#twitch_danmaku = false + + + #########录制主播设置######### # 最小配置示例 diff --git a/public/config.yaml b/public/config.yaml index 4faea9b..1872065 100644 --- a/public/config.yaml +++ b/public/config.yaml @@ -42,7 +42,7 @@ pool2_size: 5 ### 检测源码文件变化间隔,单位:秒,检测源码到变化后,程序会在空闲时自动重启 check_sourcecode: 15 -#########各平台分设置######### +#########各平台录播设置######### ### 使用直播间封面作为投稿封面。此封面优先级低于单个主播指定的自定义封面。(直播封面将会保存于cover文件夹下,请自行定期删除) #use_live_cover: true @@ -117,6 +117,12 @@ check_sourcecode: 15 ### 仅下载该日期之前的视频(可与上面的youtube_after_date配合使用,构成指定下载范围区间) #youtube_before_date: '20230501' +#------Twitch------# +# 录制Twitch弹幕,只有使用FFMPEG作为下载器才支持,默认关闭 +#twitch_danmaku: false + + + #########录制主播设置######### streamers: ### 最小配置示例