2023-11-05 16:29:11 +08:00
|
|
|
|
#!/usr/bin/env python
|
2019-05-21 19:15:12 +08:00
|
|
|
|
# -*- coding: utf-8 -*-
|
2019-05-26 17:14:59 +08:00
|
|
|
|
import argparse
|
2023-09-06 21:34:04 +08:00
|
|
|
|
import asyncio
|
2019-05-22 14:10:27 +08:00
|
|
|
|
import logging
|
2020-09-03 20:01:54 +08:00
|
|
|
|
import logging.handlers
|
2019-05-21 19:15:12 +08:00
|
|
|
|
import os
|
2023-09-06 21:34:04 +08:00
|
|
|
|
import signal
|
2023-09-10 09:48:12 +08:00
|
|
|
|
import sys
|
2019-09-16 20:48:03 +08:00
|
|
|
|
import webbrowser
|
2023-09-06 21:34:04 +08:00
|
|
|
|
from typing import *
|
2019-05-21 19:15:12 +08:00
|
|
|
|
|
|
|
|
|
import tornado.ioloop
|
|
|
|
|
import tornado.web
|
|
|
|
|
|
2020-02-03 16:18:21 +08:00
|
|
|
|
import api.chat
|
|
|
|
|
import api.main
|
2023-09-08 20:53:04 +08:00
|
|
|
|
import api.open_live
|
2023-11-04 16:52:07 +08:00
|
|
|
|
import api.plugin
|
2020-02-03 16:18:21 +08:00
|
|
|
|
import config
|
|
|
|
|
import models.database
|
2022-02-15 00:18:46 +08:00
|
|
|
|
import services.avatar
|
|
|
|
|
import services.chat
|
2023-11-26 12:18:14 +08:00
|
|
|
|
import services.open_live
|
2023-11-04 16:52:07 +08:00
|
|
|
|
import services.plugin
|
2022-02-15 00:18:46 +08:00
|
|
|
|
import services.translate
|
2019-09-16 20:48:03 +08:00
|
|
|
|
import update
|
2023-07-29 01:22:21 +08:00
|
|
|
|
import utils.request
|
2019-05-22 01:11:23 +08:00
|
|
|
|
|
2019-05-22 14:10:27 +08:00
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
2023-09-06 21:34:04 +08:00
|
|
|
|
ROUTES = [
|
2023-09-08 20:53:04 +08:00
|
|
|
|
*api.main.ROUTES,
|
|
|
|
|
*api.chat.ROUTES,
|
|
|
|
|
*api.open_live.ROUTES,
|
2023-11-04 16:52:07 +08:00
|
|
|
|
*api.plugin.ROUTES,
|
2023-09-08 20:53:04 +08:00
|
|
|
|
*api.main.LAST_ROUTES,
|
2020-02-03 16:18:21 +08:00
|
|
|
|
]
|
|
|
|
|
|
2023-09-06 21:34:04 +08:00
|
|
|
|
server: Optional[tornado.httpserver.HTTPServer] = None
|
|
|
|
|
|
2024-10-15 23:12:33 +08:00
|
|
|
|
cmd_args = None
|
2023-09-06 21:34:04 +08:00
|
|
|
|
shut_down_event: Optional[asyncio.Event] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def main():
|
|
|
|
|
if not init():
|
|
|
|
|
return 1
|
|
|
|
|
try:
|
|
|
|
|
await run()
|
|
|
|
|
finally:
|
|
|
|
|
await shut_down()
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def init():
|
|
|
|
|
init_signal_handlers()
|
2019-05-21 19:15:12 +08:00
|
|
|
|
|
2024-10-15 23:12:33 +08:00
|
|
|
|
global cmd_args
|
|
|
|
|
cmd_args = parse_args()
|
2020-02-03 16:18:21 +08:00
|
|
|
|
|
2024-10-15 23:12:33 +08:00
|
|
|
|
init_logging(cmd_args.debug)
|
2023-09-06 21:34:04 +08:00
|
|
|
|
logger.info('App started, initializing')
|
2024-10-15 23:12:33 +08:00
|
|
|
|
config.init(cmd_args)
|
2023-07-29 01:22:21 +08:00
|
|
|
|
|
2023-07-29 12:48:57 +08:00
|
|
|
|
utils.request.init()
|
2024-02-18 17:04:20 +08:00
|
|
|
|
models.database.init()
|
2023-07-29 01:22:21 +08:00
|
|
|
|
|
2022-02-15 00:18:46 +08:00
|
|
|
|
services.avatar.init()
|
|
|
|
|
services.translate.init()
|
2023-11-26 12:18:14 +08:00
|
|
|
|
services.open_live.init()
|
2022-02-15 00:18:46 +08:00
|
|
|
|
services.chat.init()
|
2023-07-29 01:22:21 +08:00
|
|
|
|
|
2024-02-18 17:04:20 +08:00
|
|
|
|
init_server()
|
2023-11-04 16:52:07 +08:00
|
|
|
|
if server is None:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
services.plugin.init()
|
|
|
|
|
|
|
|
|
|
update.check_update()
|
|
|
|
|
return True
|
2023-09-06 21:34:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def init_signal_handlers():
|
|
|
|
|
global shut_down_event
|
|
|
|
|
shut_down_event = asyncio.Event()
|
|
|
|
|
|
2024-10-15 23:12:33 +08:00
|
|
|
|
is_win = sys.platform == 'win32'
|
|
|
|
|
loop = asyncio.get_running_loop()
|
|
|
|
|
if not is_win:
|
|
|
|
|
def add_signal_handler(signum, callback):
|
|
|
|
|
loop.add_signal_handler(signum, callback)
|
|
|
|
|
else:
|
|
|
|
|
def add_signal_handler(signum, callback):
|
|
|
|
|
# 不太安全,但Windows只能用这个
|
|
|
|
|
signal.signal(signum, lambda _signum, _frame: loop.call_soon(callback))
|
|
|
|
|
|
|
|
|
|
shut_down_signums = (signal.SIGINT, signal.SIGTERM)
|
|
|
|
|
if not is_win:
|
|
|
|
|
reload_signum = signal.SIGHUP
|
|
|
|
|
else:
|
|
|
|
|
reload_signum = signal.SIGBREAK
|
|
|
|
|
|
|
|
|
|
for shut_down_signum in shut_down_signums:
|
|
|
|
|
add_signal_handler(shut_down_signum, on_shut_down_signal)
|
|
|
|
|
add_signal_handler(reload_signum, on_reload_signal)
|
2023-09-06 21:34:04 +08:00
|
|
|
|
|
|
|
|
|
|
2024-10-15 23:12:33 +08:00
|
|
|
|
def on_shut_down_signal():
|
2023-09-06 21:34:04 +08:00
|
|
|
|
shut_down_event.set()
|
2020-02-03 16:18:21 +08:00
|
|
|
|
|
|
|
|
|
|
2024-10-15 23:12:33 +08:00
|
|
|
|
def on_reload_signal():
|
|
|
|
|
logger.info('Received reload signal')
|
|
|
|
|
config.reload(cmd_args)
|
|
|
|
|
|
|
|
|
|
|
2020-02-03 16:18:21 +08:00
|
|
|
|
def parse_args():
|
2020-09-03 20:01:54 +08:00
|
|
|
|
parser = argparse.ArgumentParser(description='用于OBS的仿YouTube风格的bilibili直播评论栏')
|
2023-08-26 17:01:19 +08:00
|
|
|
|
parser.add_argument('--host', help='服务器host,默认和配置中的一样', default=None)
|
|
|
|
|
parser.add_argument('--port', help='服务器端口,默认和配置中的一样', type=int, default=None)
|
2019-05-26 17:14:59 +08:00
|
|
|
|
parser.add_argument('--debug', help='调试模式', action='store_true')
|
2020-02-03 16:18:21 +08:00
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
2019-05-26 17:14:59 +08:00
|
|
|
|
|
2020-02-03 16:18:21 +08:00
|
|
|
|
def init_logging(debug):
|
2022-03-01 22:13:25 +08:00
|
|
|
|
filename = os.path.join(config.BASE_PATH, 'log', 'blivechat.log')
|
2020-09-03 20:01:54 +08:00
|
|
|
|
stream_handler = logging.StreamHandler()
|
|
|
|
|
file_handler = logging.handlers.TimedRotatingFileHandler(
|
2022-03-01 22:13:25 +08:00
|
|
|
|
filename, encoding='utf-8', when='midnight', backupCount=7, delay=True
|
2020-09-03 20:01:54 +08:00
|
|
|
|
)
|
2019-05-22 14:10:27 +08:00
|
|
|
|
logging.basicConfig(
|
|
|
|
|
format='{asctime} {levelname} [{name}]: {message}',
|
|
|
|
|
style='{',
|
2020-09-03 20:01:54 +08:00
|
|
|
|
level=logging.INFO if not debug else logging.DEBUG,
|
|
|
|
|
handlers=[stream_handler, file_handler]
|
2019-05-22 14:10:27 +08:00
|
|
|
|
)
|
|
|
|
|
|
2020-09-14 21:50:40 +08:00
|
|
|
|
# 屏蔽访问日志
|
|
|
|
|
logging.getLogger('tornado.access').setLevel(logging.WARNING)
|
|
|
|
|
|
2019-09-16 20:48:03 +08:00
|
|
|
|
|
2024-02-18 17:04:20 +08:00
|
|
|
|
def init_server():
|
2023-08-26 17:01:19 +08:00
|
|
|
|
cfg = config.get_config()
|
2019-05-26 17:14:59 +08:00
|
|
|
|
app = tornado.web.Application(
|
2023-09-06 21:34:04 +08:00
|
|
|
|
ROUTES,
|
2020-02-03 16:18:21 +08:00
|
|
|
|
websocket_ping_interval=10,
|
2024-02-18 17:04:20 +08:00
|
|
|
|
debug=cfg.debug,
|
2019-05-26 17:14:59 +08:00
|
|
|
|
autoreload=False
|
|
|
|
|
)
|
2019-09-16 20:48:03 +08:00
|
|
|
|
try:
|
2023-09-06 21:34:04 +08:00
|
|
|
|
global server
|
|
|
|
|
server = app.listen(
|
2024-02-18 17:04:20 +08:00
|
|
|
|
cfg.port,
|
|
|
|
|
cfg.host,
|
2022-02-27 22:05:37 +08:00
|
|
|
|
xheaders=cfg.tornado_xheaders,
|
|
|
|
|
max_body_size=1024 * 1024,
|
|
|
|
|
max_buffer_size=1024 * 1024
|
2020-08-22 18:38:52 +08:00
|
|
|
|
)
|
2019-09-16 20:48:03 +08:00
|
|
|
|
except OSError:
|
2024-02-18 17:04:20 +08:00
|
|
|
|
logger.warning('Address is used %s:%d', cfg.host, cfg.port)
|
2019-09-16 20:48:03 +08:00
|
|
|
|
return
|
|
|
|
|
finally:
|
2023-07-30 15:29:40 +08:00
|
|
|
|
if cfg.open_browser_at_startup:
|
2024-02-18 17:04:20 +08:00
|
|
|
|
url = 'http://localhost/' if cfg.port == 80 else f'http://localhost:{cfg.port}/'
|
2023-07-30 15:29:40 +08:00
|
|
|
|
webbrowser.open(url)
|
2024-02-18 17:04:20 +08:00
|
|
|
|
logger.info('Server started: %s:%d', cfg.host, cfg.port)
|
2023-09-06 21:34:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def run():
|
|
|
|
|
logger.info('Running event loop')
|
|
|
|
|
await shut_down_event.wait()
|
|
|
|
|
logger.info('Received shutdown signal')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def shut_down():
|
2023-11-04 16:52:07 +08:00
|
|
|
|
services.plugin.shut_down()
|
|
|
|
|
|
2023-09-06 21:34:04 +08:00
|
|
|
|
logger.info('Closing server')
|
|
|
|
|
server.stop()
|
|
|
|
|
await server.close_all_connections()
|
|
|
|
|
|
|
|
|
|
logger.info('Closing websocket connections')
|
|
|
|
|
await services.chat.shut_down()
|
|
|
|
|
|
|
|
|
|
await utils.request.shut_down()
|
|
|
|
|
|
|
|
|
|
logger.info('App shut down')
|
2019-05-21 19:15:12 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2023-09-10 09:48:12 +08:00
|
|
|
|
sys.exit(asyncio.run(main()))
|