2018-05-13 21:57:36 +08:00
|
|
|
# -*- coding: utf-8 -*-
|
2019-02-20 00:25:14 +08:00
|
|
|
import asyncio
|
2023-09-02 12:40:38 +08:00
|
|
|
import http.cookies
|
2024-03-01 14:48:55 +08:00
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
import os
|
2024-03-02 00:27:24 +08:00
|
|
|
import signal
|
2024-03-01 14:48:55 +08:00
|
|
|
import threading
|
2024-03-01 19:14:15 +08:00
|
|
|
import time
|
2023-09-03 16:53:08 +08:00
|
|
|
from typing import *
|
2018-06-03 14:06:00 +08:00
|
|
|
|
2023-09-02 12:40:38 +08:00
|
|
|
import aiohttp
|
2024-03-01 14:48:55 +08:00
|
|
|
import redis
|
2023-09-02 12:40:38 +08:00
|
|
|
|
2019-06-06 21:50:51 +08:00
|
|
|
import blivedm
|
2024-03-01 14:48:55 +08:00
|
|
|
from blivedm.clients import ws_base
|
2019-02-19 23:15:00 +08:00
|
|
|
|
2024-03-01 16:31:00 +08:00
|
|
|
os.makedirs("logs", exist_ok=True)
|
|
|
|
room_status_log = open("logs/room_status.jsonl", "a", encoding="utf-8")
|
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
# set log level to INFO
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
2021-12-18 18:05:07 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
logger = logging.getLogger()
|
|
|
|
|
|
|
|
room_list_key = "bilibili.live.danmu.room_list"
|
2024-03-01 16:31:00 +08:00
|
|
|
r = redis.Redis(host="redis", port=6379, db=0)
|
2024-03-01 14:48:55 +08:00
|
|
|
|
|
|
|
TEST_ROOM_IDS = [int(room_id) for room_id in set(r.lrange(room_list_key, 0, -1))]
|
|
|
|
clients = {}
|
|
|
|
log_files = {}
|
|
|
|
|
|
|
|
with open("cookie.txt", "r", encoding="utf-8") as f:
|
|
|
|
SESSDATA = f.read().strip()
|
2023-09-03 18:09:12 +08:00
|
|
|
|
2023-09-03 16:53:08 +08:00
|
|
|
session: Optional[aiohttp.ClientSession] = None
|
2023-09-02 12:40:38 +08:00
|
|
|
|
2019-02-19 23:15:00 +08:00
|
|
|
|
2024-03-02 00:27:24 +08:00
|
|
|
def handle_sighup(signum, frame):
|
|
|
|
global log_files
|
|
|
|
|
|
|
|
for room_id in log_files:
|
|
|
|
log_files[room_id].close()
|
|
|
|
|
|
|
|
log_files = {}
|
|
|
|
|
|
|
|
|
|
|
|
signal.signal(signal.SIGHUP, handle_sighup)
|
|
|
|
|
|
|
|
|
2021-12-12 21:54:07 +08:00
|
|
|
async def main():
|
2024-03-01 15:01:34 +08:00
|
|
|
flush_files()
|
|
|
|
|
2023-09-02 12:40:38 +08:00
|
|
|
init_session()
|
2023-09-03 16:53:08 +08:00
|
|
|
try:
|
2024-03-01 14:48:55 +08:00
|
|
|
for room_id in TEST_ROOM_IDS:
|
|
|
|
client = None
|
|
|
|
try:
|
2024-03-01 16:31:00 +08:00
|
|
|
client = await connect_room(room_id)
|
2024-03-01 14:48:55 +08:00
|
|
|
except Exception as e:
|
|
|
|
if client is not None:
|
|
|
|
await client.stop_and_close()
|
|
|
|
|
|
|
|
raise e
|
|
|
|
|
|
|
|
# run subscribe_redis on new thread
|
2024-03-01 15:10:44 +08:00
|
|
|
threading.Thread(target=subscribe_redis, daemon=True).start()
|
2024-03-01 14:48:55 +08:00
|
|
|
|
|
|
|
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:
|
2024-03-01 14:48:55 +08:00
|
|
|
for room_id in clients:
|
|
|
|
await clients[room_id].stop_and_close()
|
2023-09-03 16:53:08 +08:00
|
|
|
await session.close()
|
2021-12-18 18:05:07 +08:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
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")
|
|
|
|
return client
|
|
|
|
|
|
|
|
|
2024-03-01 15:01:34 +08:00
|
|
|
def flush_files():
|
2024-03-01 16:31:00 +08:00
|
|
|
room_status_log.flush()
|
|
|
|
|
2024-03-01 15:01:34 +08:00
|
|
|
for room_id in log_files:
|
|
|
|
log_files[room_id].flush()
|
2024-03-01 15:10:44 +08:00
|
|
|
|
|
|
|
timer = threading.Timer(1, flush_files)
|
|
|
|
timer.daemon = True
|
|
|
|
timer.start()
|
2024-03-01 15:01:34 +08:00
|
|
|
|
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
def subscribe_redis():
|
|
|
|
p = r.pubsub()
|
|
|
|
p.psubscribe(**{f"__keyspace@0__:{room_list_key}": room_changed_handler})
|
2024-03-01 15:23:09 +08:00
|
|
|
for message in p.listen():
|
|
|
|
pass
|
2023-09-02 12:40:38 +08:00
|
|
|
|
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
# noinspection PyUnusedLocal
|
|
|
|
def room_changed_handler(message):
|
|
|
|
global TEST_ROOM_IDS
|
|
|
|
TEST_ROOM_IDS = set(int(room_id) for room_id in set(r.lrange(room_list_key, 0, -1)))
|
2021-12-13 00:07:00 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
for removed in clients.keys() - TEST_ROOM_IDS:
|
|
|
|
asyncio.run(clients[removed].stop_and_close())
|
|
|
|
del clients[removed]
|
2021-12-12 21:54:07 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
if removed in log_files:
|
|
|
|
log_files[removed].close()
|
|
|
|
del log_files[removed]
|
2021-12-12 21:54:07 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
for added in TEST_ROOM_IDS - clients.keys():
|
|
|
|
client = None
|
|
|
|
try:
|
2024-03-01 16:31:00 +08:00
|
|
|
client = asyncio.run(connect_room(added))
|
2024-03-01 14:48:55 +08:00
|
|
|
except Exception as e:
|
|
|
|
if client is not None:
|
|
|
|
asyncio.run(client.stop_and_close())
|
2021-12-12 21:54:07 +08:00
|
|
|
|
2021-12-18 18:05:07 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
def init_session():
|
|
|
|
cookies = http.cookies.SimpleCookie()
|
2024-03-01 16:31:00 +08:00
|
|
|
cookies["SESSDATA"] = SESSDATA
|
|
|
|
cookies["SESSDATA"]["domain"] = "bilibili.com"
|
2021-12-18 18:05:07 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
global session
|
|
|
|
session = aiohttp.ClientSession()
|
|
|
|
session.cookie_jar.update_cookies(cookies)
|
2019-06-06 21:50:51 +08:00
|
|
|
|
2019-02-19 23:15:00 +08:00
|
|
|
|
2024-03-01 14:48:55 +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-02-19 23:15:00 +08:00
|
|
|
|
2019-09-23 21:43:37 +08:00
|
|
|
|
2024-03-01 14:48:55 +08:00
|
|
|
jsonl_logger = JsonlLogger()
|
2019-02-19 23:15:00 +08:00
|
|
|
|
2024-03-01 16:31:00 +08:00
|
|
|
if __name__ == "__main__":
|
2023-03-26 00:51:50 +08:00
|
|
|
asyncio.run(main())
|