feat(p0): add favorite folder sync and sqlite data foundation

Implement P0 of the reaction dashboard: config loading with hot reload, SQLite migrations with backups, single-writer queue, read-only Bilibili fav client, folder import/diff sync, invalid-resource handling, blacklist seed, scheduler, and JSON redacted logging. Includes offline unit and transport-level contract tests; all existing and new tests pass.
This commit is contained in:
kairee committed 2026-10-31 18:08:33 +08:00
commit e2cdf997af
39 files changed
+8575

No files matched your search

+163
View File
@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
"""脱敏后的真实接口样本(2026-10-31 只读抓取)。
样本只保留 P0 需要的字段结构,但包含真实接口的完整嵌套形状:
``upper`` / ``cnt_info`` / ``attr`` / ``bv_id`` / ``bvid`` 等。
不包含 Cookie、token 或任何凭据。
"""
from __future__ import annotations
import copy
from typing import Any
# GET x/v3/fav/resource/ids?media_id=3700023351(两条有效 + 两条后来静默缺失)
IDS_PAYLOAD: dict[str, Any] = {
"code": 0,
"message": "0",
"ttl": 1,
"data": [
{"id": 117530286889638, "type": 2, "bv_id": "BV1xvxi6LEZD", "bvid": "BV1xvxi6LEZD"},
{"id": 117014421051497, "type": 2, "bv_id": "BV17tGN6kETF", "bvid": "BV17tGN6kETF"},
{"id": 116911710935631, "type": 2, "bv_id": "BV1JoNy66Exp", "bvid": "BV1JoNy66Exp"},
{"id": 116769540805008, "type": 2, "bv_id": "BV183jw6hEpt", "bvid": "BV183jw6hEpt"},
],
}
# GET x/v3/fav/resource/infos 的真实有效条目
VALID_INFO: dict[str, Any] = {
"id": 117530286889638,
"type": 2,
"title": "【咻咻满充电专场①】百变音色机能怪,还有什么风格是你驾驭不了的?!",
"cover": "http://i1.hdslb.com/bfs/archive/e5d3d4f25777b08c1dfae8bc9dc3d56b21d548f1.jpg",
"intro": "视频唱见咻咻满充电专场,感谢宝宝的充电@推堡儿",
"page": 2,
"duration": 9504,
"upper": {
"mid": 434442072,
"name": "_-抱抱-_",
"face": "https://i0.hdslb.com/bfs/face/3176d3d551875a4dd7dac202963ec76d393ddd18.jpg",
"jump_link": "",
},
"attr": 0,
"cnt_info": {
"collect": 43,
"play": 799,
"danmaku": 7,
"vt": 0,
"play_switch": 0,
"reply": 0,
"view_text_1": "799",
},
"link": "bilibili://video/117530286889638",
"ctime": 1793370433,
"pubtime": 1793370433,
"fav_time": 0,
"bv_id": "BV1xvxi6LEZD",
"bvid": "BV1xvxi6LEZD",
"season": None,
"ogv": None,
"ugc": {"first_cid": 43184885058},
"media_list_link": "bilibili://music/playlist/playpage/3728825651?page_type=3&oid=117530286889638&otype=2",
}
# attr=9 表示已失效视频(真实样本)
INVALID_INFO: dict[str, Any] = {
"id": 116769540805008,
"type": 2,
"title": "已失效视频",
"cover": "http://i0.hdslb.com/bfs/archive/be27fd62c99036dce67efface486fb0a88ffed06.jpg",
"intro": "-",
"page": 1,
"duration": 4504,
"upper": {
"mid": 3707011906669054,
"name": "裤裤喝可乐",
"face": "https://i1.hdslb.com/bfs/face/c1d2eb1c9e5c783b8b0aa6e6154892724dfe2812.jpg",
"jump_link": "",
},
"attr": 9,
"cnt_info": {
"collect": 27,
"play": 977,
"danmaku": 0,
"vt": 0,
"play_switch": 0,
"reply": 0,
"view_text_1": "977",
},
"link": "bilibili://video/116769540805008",
"ctime": 1781762147,
"pubtime": 1781762147,
"fav_time": 0,
"bv_id": "BV183jw6hEpt",
"bvid": "BV183jw6hEpt",
"season": None,
"ogv": None,
"ugc": {"first_cid": 39207702089},
"media_list_link": "bilibili://music/playlist/playpage/3728825651?page_type=3&oid=116769540805008&otype=2",
}
# GET x/v3/fav/folder/created/list-all 的真实条目
FOLDERS_PAYLOAD: dict[str, Any] = {
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"count": 2,
"list": [
{
"id": 4451053851,
"fid": 44510538,
"mid": 28802351,
"attr": 2,
"title": "咻咻满-reaction-2025",
"fav_state": 0,
"media_count": 167,
"is_kid_playlist": False,
"kid_playlist_desc": "",
},
{
"id": 3700023351,
"fid": 37000233,
"mid": 28802351,
"attr": 54,
"title": "咻咻满 -reaction-2026",
"fav_state": 0,
"media_count": 664,
"is_kid_playlist": False,
"kid_playlist_desc": "",
},
],
},
}
def info_for(
aid: int,
*,
title: str,
up_mid: int,
up_name: str,
pubdate: int = 1793370433,
duration: int = 9504,
attr: int = 0,
bvid: str | None = None,
) -> dict[str, Any]:
"""基于真实样本复制一条 infos 条目,只改测试需要的字段。"""
item = copy.deepcopy(VALID_INFO)
item["id"] = aid
item["title"] = title
item["upper"]["mid"] = up_mid
item["upper"]["name"] = up_name
item["pubtime"] = pubdate
item["ctime"] = pubdate
item["duration"] = duration
item["attr"] = attr
item["bvid"] = bvid or f"BV{aid}"
item["bv_id"] = item["bvid"]
item["link"] = f"bilibili://video/{aid}"
item["media_list_link"] = (
f"bilibili://music/playlist/playpage/3728825651?page_type=3&oid={aid}&otype=2"
)
return item