fix(monitor): 博主改名之后,旧作品上的名字也跟着改
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

昵称是**博主级**的属性,而作品是逐条刷的:一个博主只有落在采集窗口里的那几条会被
重刷,掉出窗口的老作品会一直留着旧名字。于是改名之后库里一半新一半旧 ——

* 作品栏组头取的是该博主名下作品的 max(name),**恰好可能取到旧的那个**(比如从
  「BBB」改成「AAA」,max 还是 BBB);
* 导出和 SQL 直接看到旧名字。

两处修:

1. ingest 收完这一轮之后,把这一轮看到的 (博主, 昵称) 铺到该博主在本任务下的
   **全部**作品上。带上 `!= name` 让没变化的不产生写入。只限本任务 —— 另一个任务里
   的同一个人是另一条跟踪线。
2. `list_creators` 的昵称**优先取账号快照**:那一行每次采集都从资料接口重写,是
   最新的一份;小红书那条路没有快照,才退回作品上的名字。

顺带把两份 SQL 里的 COALESCE 顺序调成一致(不然查出来还是旧名字)。
This commit is contained in:
2026-10-11 10:08:58 +08:00
parent af21288dde
commit 36f41450ae
6 changed files with 138 additions and 8 deletions
+79
View File
@@ -1010,3 +1010,82 @@ class TestCreatorIdIsStored:
await ingest_run(db, run, task, tmp_path)
assert (await db.scalar(select(MonitorCreatorStat))).creator_id == ""
class TestNicknameRefresh:
"""博主改名之后,库里不能一半是新名字、一半是旧名字。
昵称是**博主级**的属性,而作品是逐条刷的 —— 一个博主只有落在采集窗口里的那几条会被
重刷,掉出窗口的老作品会一直留着旧名字。界面按作品名分组时取的是其中任意一个,
导出和 SQL 更是直接看到旧名字。
"""
@pytest.mark.asyncio
async def test_a_rename_reaches_the_works_outside_this_runs_window(self, db, tmp_path):
task = await _make_task(db, platform="dy")
# 第一轮:两条作品,都叫「旧名字」。
first = await _make_run(db, task, started_at=1)
_write_run_dir(
tmp_path,
[_dy_note("111", nickname="旧名字"), _dy_note("222", nickname="旧名字")],
comments=[],
subdir="douyin",
)
await ingest_run(db, first, task, tmp_path)
# 第二轮:只采到 111(222 掉出了采集窗口),而博主已经改名。
second = await _make_run(db, task, started_at=2000)
_write_run_dir(
tmp_path,
[_dy_note("111", nickname="新名字")],
comments=[],
subdir="douyin",
)
await ingest_run(db, second, task, tmp_path)
names = {
row.note_id: row.creator_name
for row in (await db.scalars(select(MonitorNote))).all()
}
assert names == {"111": "新名字", "222": "新名字"}
@pytest.mark.asyncio
async def test_the_rename_does_not_leak_into_another_task(self, db, tmp_path):
"""博主级不等于全局 —— 另一个任务里的同一个人是另一条跟踪线,别顺手改它。"""
mine = await _make_task(db, name="我的", platform="dy")
other = await _make_task(db, name="别人的", platform="dy")
run = await _make_run(db, other, started_at=1)
_write_run_dir(tmp_path, [_dy_note("999", nickname="别人的名字")], comments=[], subdir="douyin")
await ingest_run(db, run, other, tmp_path)
run = await _make_run(db, mine, started_at=1)
_write_run_dir(tmp_path, [_dy_note("111", nickname="旧名字")], comments=[], subdir="douyin")
await ingest_run(db, run, mine, tmp_path)
run = await _make_run(db, mine, started_at=2000)
_write_run_dir(tmp_path, [_dy_note("111", nickname="新名字")], comments=[], subdir="douyin")
await ingest_run(db, run, mine, tmp_path)
by_task = {
row.note_id: row.creator_name
for row in (await db.scalars(select(MonitorNote))).all()
}
assert by_task["999"] == "别人的名字"
assert by_task["111"] == "新名字"
@pytest.mark.asyncio
async def test_an_empty_name_does_not_wipe_the_stored_one(self, db, tmp_path):
"""平台这一轮没给昵称时,不要把已有的抹掉。"""
task = await _make_task(db, platform="dy")
run = await _make_run(db, task, started_at=1)
_write_run_dir(tmp_path, [_dy_note("111", nickname="有名字")], comments=[], subdir="douyin")
await ingest_run(db, run, task, tmp_path)
run = await _make_run(db, task, started_at=2000)
_write_run_dir(tmp_path, [_dy_note("111", nickname="")], comments=[], subdir="douyin")
await ingest_run(db, run, task, tmp_path)
assert (await db.scalar(select(MonitorNote))).creator_name == "有名字"