blivedm/main.py

186 lines
4.7 KiB
Python
Raw Normal View History

2019-02-20 00:25:14 +08:00
import asyncio
import http.cookies
import json
import logging
import os
import signal
import threading
2024-03-01 19:14:15 +08:00
import time
2023-09-03 16:53:08 +08:00
from typing import *
import aiohttp
2024-03-20 11:22:07 +08:00
import redis_util as redis
2019-06-06 21:50:51 +08:00
import blivedm
from blivedm.clients import ws_base
2024-03-20 11:22:07 +08:00
def room_from_config():
return conf.get("room_ids", [])
2024-03-20 11:22:07 +08:00
# noinspection PyUnusedLocal
def handle_sighup(signum, frame):
global log_files
global room_status_log
for room_id in log_files:
2024-03-03 02:23:07 +08:00
try:
log_files[room_id].close()
except Exception as e:
logger.exception(f"close log_files[{room_id}] failed with {e}")
try:
room_status_log.close()
except Exception as e:
logger.exception(f"close room_status_log failed with {e}")
log_files = {}
room_status_log = open("logs/room_status.jsonl", "a", encoding="utf-8")
2024-03-20 11:22:07 +08:00
def on_room_changed(new_room_ids):
global TEST_ROOM_IDS
TEST_ROOM_IDS = list(set(new_room_ids + room_from_config()))
for removed in clients.keys() - TEST_ROOM_IDS:
asyncio.run(clients[removed].stop_and_close())
del clients[removed]
if removed in log_files:
log_files[removed].close()
del log_files[removed]
for added in TEST_ROOM_IDS - clients.keys():
client = None
try:
client = asyncio.run(connect_room(added))
except Exception as e:
if client is not None:
asyncio.run(client.stop_and_close())
2021-12-12 21:54:07 +08:00
async def main():
2024-03-20 11:22:07 +08:00
global TEST_ROOM_IDS
flush_files()
2024-03-20 11:22:07 +08:00
redis.on_room_changed = on_room_changed
redis.init(conf.get("redis", None))
TEST_ROOM_IDS = list(set(TEST_ROOM_IDS + redis.get_room_list()))
init_session()
2023-09-03 16:53:08 +08:00
try:
for room_id in TEST_ROOM_IDS:
client = None
try:
2024-03-01 16:31:00 +08:00
client = await connect_room(room_id)
except Exception as e:
if client is not None:
await client.stop_and_close()
raise e
while True:
await asyncio.gather(*(
clients[room_id].join() for room_id in clients
))
2024-03-01 15:10:44 +08:00
await asyncio.sleep(1)
2023-09-03 16:53:08 +08:00
finally:
for room_id in clients:
await clients[room_id].stop_and_close()
2023-09-03 16:53:08 +08:00
await session.close()
2024-03-01 16:31:00 +08:00
async def connect_room(room_id):
logger.info("connect to room %s", room_id)
client = blivedm.BLiveClient(room_id, session=session)
client.set_handler(jsonl_logger)
await client.init_room()
client._need_init_room = False
client.start()
clients[room_id] = client
logger.info("connect to room %s success", room_id)
try:
room_status_log.write(json.dumps(
{
"room_id": room_id,
"live_status": client.live_status,
"live_start_time": client.live_start_time,
},
separators=(",", ":"),
ensure_ascii=False,
))
room_status_log.write("\n")
except Exception as e:
logger.exception(f"write room_status_log failed with {e}")
2024-03-01 16:31:00 +08:00
return client
def flush_files():
2024-03-02 00:30:58 +08:00
try:
room_status_log.flush()
2024-03-02 00:30:58 +08:00
for room_id in log_files:
log_files[room_id].flush()
except Exception as e:
logger.exception(f"flush_files failed with {e}")
2024-03-01 15:10:44 +08:00
timer = threading.Timer(1, flush_files)
timer.daemon = True
timer.start()
def init_session():
cookies = http.cookies.SimpleCookie()
2024-03-01 16:31:00 +08:00
cookies["SESSDATA"] = SESSDATA
cookies["SESSDATA"]["domain"] = "bilibili.com"
global session
session = aiohttp.ClientSession()
session.cookie_jar.update_cookies(cookies)
2019-06-06 21:50:51 +08:00
class JsonlLogger(blivedm.BaseHandler):
def _global_callback(self, client: ws_base.WebSocketClientBase, message: dict):
if client.room_id not in log_files:
log_files[client.room_id] = open(f"logs/{client.room_id}.jsonl", "a", encoding="utf-8")
2019-03-23 23:58:02 +08:00
2024-03-01 19:14:15 +08:00
if "cmd" in message and message["cmd"] == "PREPARING":
message["timestamp"] = int(time.time())
2024-03-01 15:23:09 +08:00
log_files[client.room_id].write(f"{json.dumps(message, separators=(',', ':'), ensure_ascii=False)}\n")
2019-09-23 21:43:37 +08:00
2024-03-20 11:22:07 +08:00
# set log level to INFO
logging.basicConfig(level=logging.INFO)
try:
with open("config.json") as conf_f:
conf = json.load(conf_f)
except FileNotFoundError:
conf = {}
redis_conf: dict | None = conf.get("redis", None)
os.makedirs("logs", exist_ok=True)
room_status_log = open("logs/room_status.jsonl", "a", encoding="utf-8")
logger = logging.getLogger()
clients = {}
log_files = {}
with open("cookie.txt", "r", encoding="utf-8") as f:
SESSDATA = f.read().strip()
session: Optional[aiohttp.ClientSession] = None
TEST_ROOM_IDS: list[int] = room_from_config()
signal.signal(signal.SIGHUP, handle_sighup)
jsonl_logger = JsonlLogger()
2024-03-01 16:31:00 +08:00
if __name__ == "__main__":
asyncio.run(main())