fix: close data integrity and hot-reload review findings

Backfill same-day snapshots for newly added or restored videos, preserve successful fan snapshots on resume, persist incomplete state before forced re-runs, and split collection completion from backup completion so failed backups can retry without API calls. Reject missing data payloads instead of treating them as empty folders, guard against mass-unfav on suspicious empty remote folders, rebuild Bilibili clients when credentials change, recompute primary folder ownership from active relations with per-folder fav_time, preserve original titles for dropped invalid videos, poll config every 60 seconds, and fix favsort verify interval and mixed resource types.
This commit is contained in:
kairee committed 2026-10-31 20:58:36 +08:00
1 parent 178ab64b18
commit 6a21b5d905
21 files changed
+895 -82

No files matched your search

+71 -2
View File
@@ -18,7 +18,7 @@ F1 = FolderConfig(year=2025, media_id=4451053851, title="2025")
F2 = FolderConfig(year=2026, media_id=3700023351, title="2026")
def resource(aid, *, attr=0, up_mid=100, title="视频", bvid=None):
def resource(aid, *, attr=0, up_mid=100, title="视频", bvid=None, fav_time=None):
return FavResource(
aid=aid,
bvid=bvid or f"BV{aid}",
@@ -29,7 +29,7 @@ def resource(aid, *, attr=0, up_mid=100, title="视频", bvid=None):
duration=600,
cover="http://example/cover.jpg",
attr=attr,
fav_time=None,
fav_time=fav_time,
)
@@ -227,6 +227,72 @@ def test_folder_sync_metadata_and_counts():
db.close()
def test_primary_folder_is_order_independent():
with tempfile.TemporaryDirectory() as tmp:
db, repo = setup(tmp)
try:
repo.upsert_from_fav(resource(1, fav_time=100), F1.media_id, was_added=True)
assert repo.get_video(1)["folder_id"] == F1.media_id
repo.upsert_from_fav(resource(1, fav_time=200), F2.media_id, was_added=True)
assert repo.get_video(1)["folder_id"] == F2.media_id
# 全量刷新按相反顺序遍历,主归属仍应指向 fav_time 更新的夹
repo.upsert_from_fav(resource(1, fav_time=100), F1.media_id, was_added=False)
assert repo.get_video(1)["folder_id"] == F2.media_id
repo.upsert_from_fav(resource(1, fav_time=200), F2.media_id, was_added=False)
assert repo.get_video(1)["folder_id"] == F2.media_id
# 从主夹移除、另一个夹仍持有时,主归属切换
status = repo.mark_resource_removed(F2.media_id, 1)
assert status == "active"
assert repo.get_video(1)["folder_id"] == F1.media_id
finally:
db.close()
def test_dropped_invalid_preserves_original_title():
with tempfile.TemporaryDirectory() as tmp:
db, repo = setup(tmp)
try:
repo.upsert_from_fav(
resource(1, title="原始标题"), F1.media_id, was_added=True
)
repo.set_video_status(1, "dropped")
repo.upsert_from_fav(
resource(1, title="已失效视频", attr=9),
F1.media_id,
was_added=False,
)
video = repo.get_video(1)
assert video["status"] == "dropped"
assert video["title"] == "原始标题"
finally:
db.close()
def test_pending_snapshot_aids():
with tempfile.TemporaryDirectory() as tmp:
db, repo = setup(tmp)
try:
repo.upsert_from_fav(resource(1), F1.media_id, was_added=True)
repo.upsert_from_fav(resource(2), F1.media_id, was_added=True)
repo.upsert_from_fav(resource(3), F1.media_id, was_added=True)
repo.set_video_status(3, "unfaved")
repo.upsert_snapshot(
"2026-10-31", 1,
metrics={"view": 1, "like": 1, "favorite": 1, "coin": 1,
"share": 1, "reply": 1, "danmaku": 1},
ok=True, err=None, captured_at=1,
)
repo.upsert_snapshot(
"2026-10-31", 2,
metrics=None, ok=False, err="x", captured_at=1,
)
assert repo.pending_snapshot_aids("2026-10-31") == [2, 3]
finally:
db.close()
def main():
test_upsert_and_folder_resource()
test_invalid_attr_and_missing()
@@ -236,6 +302,9 @@ def main():
test_multi_folder_moves_primary_and_warns()
test_blacklist_seed_idempotent()
test_folder_sync_metadata_and_counts()
test_primary_folder_is_order_independent()
test_dropped_invalid_preserves_original_title()
test_pending_snapshot_aids()
print("OK: 收藏夹/视频状态机与黑名单测试全部通过")