Intro skip: parse Jikan v4's actual response shape
Jikan /anime/{id}/episodes returns the episode list DIRECTLY under
'data' (flat array), not {'episodes': [...]}. The old code called
.get() on that list -> AttributeError, swallowed by the endpoint's
except -> [] -> the skip button could never appear, even with Jikan
up. Accept both shapes now.
Verified end-to-end with a mocked /api/intros response: the button is
wired into the player, visible exactly while currentTime is inside the
intro window (111-188s test), hidden outside it.
The live button still awaits Jikan/MAL recovery (504ing since this
feature landed); failures are not cached, so it activates on the first
successful fetch.
Skipped: MAL-direct fallback — official API needs a client key
(403 without), and the keyless HTML page carries no intro data.
This commit is contained in:
1 parent
eb5082bd3b
commit
27de918cb0
2 files changed
+36
-2
No files matched your search
+6
-2
@@ -132,9 +132,13 @@ def _parse_intros(eps):
|
|||||||
|
|
||||||
|
|
||||||
def _intros(mal_id):
|
def _intros(mal_id):
|
||||||
"""Jikan (keyless MAL mirror): per-episode intro start/length, seconds"""
|
"""Jikan (keyless MAL mirror): per-episode intro start/length, seconds."""
|
||||||
|
# Jikan v4 returns the list directly under 'data'; tolerate a wrapped
|
||||||
|
# shape too, so a format change doesn't silently kill the button
|
||||||
r = _get("https://api.jikan.moe/v4/anime/{}".format(mal_id) + "/episodes")
|
r = _get("https://api.jikan.moe/v4/anime/{}".format(mal_id) + "/episodes")
|
||||||
return _parse_intros(r.json().get("data", {}).get("episodes", []))
|
d = r.json().get("data")
|
||||||
|
eps = d if isinstance(d, list) else (d or {}).get("episodes", [])
|
||||||
|
return _parse_intros(eps)
|
||||||
|
|
||||||
|
|
||||||
def _master_m3u8(ep_id, lang="eng"):
|
def _master_m3u8(ep_id, lang="eng"):
|
||||||
|
|||||||
@@ -312,3 +312,33 @@ def test_parse_intros():
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_intros_parses_jikan_shapes():
|
||||||
|
# _intros against a stubbed HTTP layer: Jikan v4 returns the episode
|
||||||
|
# list directly under 'data' (not {'episodes': [...]}) — a regression
|
||||||
|
# here would silently disable the skip button whenever Jikan is up.
|
||||||
|
import server.upstream as u
|
||||||
|
|
||||||
|
class R:
|
||||||
|
def json(self):
|
||||||
|
return {"data": [
|
||||||
|
{"title": "Episode 1", "intro": {"start": 111, "length": 77}},
|
||||||
|
{"title": "Episode 2", "intro": {"start": 0, "length": 0}},
|
||||||
|
]}
|
||||||
|
|
||||||
|
u._CACHE.clear()
|
||||||
|
u._get = lambda url: R() # stub the network
|
||||||
|
assert u._intros(92573) == [
|
||||||
|
{"start": 111, "length": 77},
|
||||||
|
{"start": 0, "length": 0},
|
||||||
|
]
|
||||||
|
# wrapped shape still works
|
||||||
|
class W:
|
||||||
|
def json(self):
|
||||||
|
return {"data": {"episodes": [
|
||||||
|
{"intro": {"start": 90, "length": 60}},
|
||||||
|
]}}
|
||||||
|
u._get = lambda url: W()
|
||||||
|
assert u._intros(92573)[0]["start"] == 90
|
||||||
|
u._CACHE.clear()
|
||||||
Reference in new issue
Block a user