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:
1 parent
178ab64b18
commit
6a21b5d905
21 files changed
+895
-82
No files matched your search
@@ -38,10 +38,11 @@ def http_json(payload):
|
||||
|
||||
|
||||
class FakeFavTransport:
|
||||
def __init__(self, folders, infos, *, fail_media=None):
|
||||
def __init__(self, folders, infos, *, fail_media=None, omit_ids_data=None):
|
||||
self.folders = {k: list(v) for k, v in folders.items()}
|
||||
self.infos = dict(infos)
|
||||
self.fail_media = fail_media
|
||||
self.omit_ids_data = omit_ids_data
|
||||
self.ids_calls = []
|
||||
self.info_calls = []
|
||||
|
||||
@@ -52,6 +53,8 @@ class FakeFavTransport:
|
||||
self.ids_calls.append(media_id)
|
||||
if self.fail_media == media_id:
|
||||
raise TransportError("ids 网络错误")
|
||||
if self.omit_ids_data == media_id:
|
||||
return http_json({"code": 0, "message": "OK", "ttl": 1})
|
||||
data_rows = [
|
||||
{"id": aid, "type": 2, "bv_id": f"BV{aid}", "bvid": f"BV{aid}"}
|
||||
for aid in self.folders.get(media_id, [])
|
||||
@@ -284,6 +287,51 @@ def test_blacklist_seed_only_once():
|
||||
db.close()
|
||||
|
||||
|
||||
def test_empty_remote_requires_explicit_opt_in():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
transport = FakeFavTransport(
|
||||
{F1: [1101, 1102], F2: []},
|
||||
{1101: valid(1101), 1102: valid(1102)},
|
||||
)
|
||||
clock = [1_800_000_000]
|
||||
db, repo, service = make_service(tmp, transport, clock)
|
||||
try:
|
||||
service.run()
|
||||
transport.folders[F1] = []
|
||||
clock[0] += 3600
|
||||
summary = service.run()
|
||||
assert summary.ok is False
|
||||
assert "疑似接口异常" in summary.folders[0].error
|
||||
assert repo.get_video(1101)["status"] == "active"
|
||||
assert repo.folder_active_aids(F1) == {1101, 1102}
|
||||
|
||||
service.allow_empty_folders = True
|
||||
summary = service.run()
|
||||
assert summary.ok is True
|
||||
assert repo.get_video(1101)["status"] == "unfaved"
|
||||
assert repo.folder_active_aids(F1) == set()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_missing_ids_data_aborts_folder():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
transport = FakeFavTransport(
|
||||
{F1: [1101], F2: []},
|
||||
{1101: valid(1101)},
|
||||
omit_ids_data=F1,
|
||||
)
|
||||
clock = [1_800_000_000]
|
||||
db, repo, service = make_service(tmp, transport, clock)
|
||||
try:
|
||||
summary = service.run()
|
||||
assert summary.ok is False
|
||||
assert "data" in summary.folders[0].error
|
||||
assert repo.get_video(1101) is None
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def main():
|
||||
test_initial_import_and_incremental_skip()
|
||||
test_diff_add_and_remove()
|
||||
@@ -291,6 +339,8 @@ def main():
|
||||
test_capacity_warning_does_not_move_folder()
|
||||
test_folder_error_does_not_block_other_folders()
|
||||
test_blacklist_seed_only_once()
|
||||
test_empty_remote_requires_explicit_opt_in()
|
||||
test_missing_ids_data_aborts_folder()
|
||||
print("OK: 收藏夹初始导入、差集同步、失效识别与容量预警测试全部通过")
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user