history: flag rows whose slug no longer means the same anime
Provider switch (anidb -> hianime-first) left anidb-era rows whose slugs
200 on hianime as a DIFFERENT anime: /watch/jujutsu-kaisen-2552 is now
Burning Kabaddi (the trailing number is a hianime id), and the stored
anidb ep id doesn't even exist in that anime's list — the row rendered
as watched JJK but linked to the wrong show.
Client-side validation (no data migration): every history row's slug is
checked against GET /api/anime/{slug} once per slug; title mismatch (or
a dead slug) marks the entry stale. Stale rows:
- home: one card per stale anime above the hero + 'history ->' link
- history page: separate 'Moved or renamed on the source' section
Each card: title, 'find it ->' (search by stored title) and x (remove,
same endpoint as regular cards). Current rows are untouched: a hianime
slug whose details name matches the stored title passes.
Tests: API contract for a stale row (deletable while on the board);
live browser test (gated) with the real jujutsu-kaisen-2552 row:
remap card renders, card doesn't link to the wrong slug, find-it
lands on the title's search.
This commit is contained in:
1 parent
0f6bd0a52a
commit
379f591180
3 files changed
+141
-3
No files matched your search
@@ -506,3 +506,25 @@ def test_fetch_parallel_stitches_range_lanes():
|
||||
finally:
|
||||
u._session = real
|
||||
u._get = real_get
|
||||
|
||||
|
||||
def test_stale_entries_surfaced_as_remappable(base=BASE):
|
||||
# provider switch left anidb-era rows: their slug 200s on hianime as a
|
||||
# DIFFERENT anime (id 2552 = Burning Kabaddi). The client flags the
|
||||
# mismatch; the API contract is unchanged — the entry is deletable by
|
||||
# slug+ep while it sits on the remap board.
|
||||
jar = login("bob", "bobpw12345", base)
|
||||
stale = {"title": "Jujutsu Kaisen", "slug_id": "jujutsu-kaisen-2552",
|
||||
"season_id": 2552, "ep_id": 35996, "lang": "jpn", "ep": 1, "pos": 42}
|
||||
good = {"title": "Seed Anime", "slug_id": "seed-1", "season_id": 1,
|
||||
"ep_id": 1, "lang": "eng", "ep": 1, "pos": 10}
|
||||
assert req("POST", "/api/history", stale, jar=jar, base=base) == 200
|
||||
assert req("POST", "/api/history", good, jar=jar, base=base) == 200
|
||||
all_ = _json("GET", "/api/history?all=1", jar=jar, base=base)
|
||||
got = [x for x in all_ if x["slug_id"] == "jujutsu-kaisen-2552"]
|
||||
assert got and got[0]["ep_id"] == 35996 and got[0]["pos"] == 42, got
|
||||
removed = _json("DELETE", "/api/history?slug_id=jujutsu-kaisen-2552&ep_id=35996",
|
||||
jar=jar, base=base)
|
||||
assert removed["removed"] >= 1, removed
|
||||
all_ = _json("GET", "/api/history?all=1", jar=jar, base=base)
|
||||
assert not [x for x in all_ if x["slug_id"] == "jujutsu-kaisen-2552"], all_
|
||||
@@ -450,3 +450,43 @@ async def _autoplay_blocked():
|
||||
timeout=120000, polling=250)
|
||||
assert not errors, errors
|
||||
await browser.close()
|
||||
|
||||
|
||||
def test_stale_history_remap_board():
|
||||
asyncio.run(_stale_history_remap_board())
|
||||
|
||||
|
||||
async def _stale_history_remap_board():
|
||||
# provider switch (anidb -> hianime) left rows whose anidb slug 200s on
|
||||
# hianime as a DIFFERENT anime (jujutsu-kaisen-2552 = Burning Kabaddi).
|
||||
# The history page must flag it for remap instead of linking to that show.
|
||||
jar = http.cookiejar.CookieJar()
|
||||
op = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
|
||||
op.open(urllib.request.Request(BASE + "/login",
|
||||
data=json.dumps({"username": "erin", "password": "erinpw12345"}).encode(),
|
||||
headers={"Content-Type": "application/json", "X-Aniweb": "1"}, method="POST"))
|
||||
op.open(urllib.request.Request(BASE + "/api/history",
|
||||
data=json.dumps({"title": "Jujutsu Kaisen", "slug_id": "jujutsu-kaisen-2552",
|
||||
"season_id": 2552, "ep_id": 35996, "lang": "jpn", "ep": 1,
|
||||
"pos": 42}).encode(),
|
||||
headers={"Content-Type": "application/json", "X-Aniweb": "1"}, method="POST"))
|
||||
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(args=LAUNCH_ARGS)
|
||||
page = await (await browser.new_context()).new_page()
|
||||
errors = []
|
||||
page.on("pageerror", lambda e: errors.append(str(e)))
|
||||
await _login(page, "erin", "erinpw12345")
|
||||
await page.goto(BASE + "/?history")
|
||||
await page.wait_for_function(
|
||||
"document.querySelector('a.card.remap')", timeout=60000, polling=POLL)
|
||||
stale = page.locator("a.card.remap", has_text="Jujutsu Kaisen")
|
||||
assert "not found" in await stale.inner_text()
|
||||
# the card must not link to the wrong-slug detail page; find-it goes
|
||||
# to the title's search instead
|
||||
assert not await stale.get_attribute("href")
|
||||
await stale.locator("button:has-text('find it')").click(force=True)
|
||||
await page.wait_for_function(
|
||||
"location.search.includes('q=')", timeout=15000, polling=POLL)
|
||||
assert not errors, errors
|
||||
await browser.close()
|
||||
Reference in new issue
Block a user