From 1f1da6118602f7dd55d95e3b81cc8640990caa9b Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:24:34 -0400 Subject: [PATCH 01/46] KSN: add `chivalry-of-a-failed-knight.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: Selection Battle arc (eps 1-12) + unadapted tail (manga complete) - anime `21092` → manga `85370` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/chivalry-of-a-failed-knight.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/chivalry-of-a-failed-knight.json diff --git a/src/data/index.ts b/src/data/index.ts index 28b373a..d810f3e 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -160,6 +160,7 @@ import landOfTheLustrous from "@/data/mappings/land-of-the-lustrous.json"; import rankingOfKings from "@/data/mappings/ranking-of-kings.json"; import toYourEternity from "@/data/mappings/to-your-eternity.json"; import callOfTheNight from "@/data/mappings/call-of-the-night.json"; +import chivalryOfAFailedKnight from "@/data/mappings/chivalry-of-a-failed-knight.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -389,6 +390,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ rankingOfKings, toYourEternity, callOfTheNight, + chivalryOfAFailedKnight, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/chivalry-of-a-failed-knight.json b/src/data/mappings/chivalry-of-a-failed-knight.json new file mode 100644 index 0000000..31b19a7 --- /dev/null +++ b/src/data/mappings/chivalry-of-a-failed-knight.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 21092, + "anilistMangaId": 85370, + "title": "Chivalry of a Failed Knight", + "sourceNotes": "Single 12-episode TV season (2015). Source is Riku Misora's light novel; paired here with the Megumu Soramichi manga adaptation (id 85370, 48 ch on AniList, complete — ANN cites the finale as ch 45). The anime covers only the Selection Battle (LN vols 1-3, roughly manga ch 1-34); the manga runs a bit further into LN vol 4, so its tail (ch 35-48) is unadapted. Per-episode chapter boundaries are proportional estimates — no published 1:1 episode-to-chapter guide exists.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 34], + "arc": "Selection Battle (Hagun qualifiers / Sword Eater incident, LN vols 1-3)" + }, + { + "chapters": [35, 48], + "arc": "Seven Stars Sword Art Festival (opening, LN vol 4) — manga only" + } + ] +} From c459fed0475af3b643a1c0feffa6c3c4c1b56012 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:25:00 -0400 Subject: [PATCH 02/46] KSN: add `masamune-kun-revenge.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: S1 + 'R' season across the full story (manga complete) - anime `21857` → manga `76716` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/masamune-kun-revenge.json | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/data/mappings/masamune-kun-revenge.json diff --git a/src/data/index.ts b/src/data/index.ts index d810f3e..f350ff3 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -161,6 +161,7 @@ import rankingOfKings from "@/data/mappings/ranking-of-kings.json"; import toYourEternity from "@/data/mappings/to-your-eternity.json"; import callOfTheNight from "@/data/mappings/call-of-the-night.json"; import chivalryOfAFailedKnight from "@/data/mappings/chivalry-of-a-failed-knight.json"; +import masamuneKunRevenge from "@/data/mappings/masamune-kun-revenge.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -391,6 +392,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ toYourEternity, callOfTheNight, chivalryOfAFailedKnight, + masamuneKunRevenge, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/masamune-kun-revenge.json b/src/data/mappings/masamune-kun-revenge.json new file mode 100644 index 0000000..996fe07 --- /dev/null +++ b/src/data/mappings/masamune-kun-revenge.json @@ -0,0 +1,18 @@ +{ + "anilistAnimeId": 21857, + "anilistMangaId": 76716, + "title": "Masamune-kun's Revenge", + "sourceNotes": "Cumulative episodes across S1 (12, 2017) + S2 'R' (12, eps 13-24, 2023) = 24 total. Manga by Hazuki Takeoka & Tiv is complete: the serialized main story runs 49 numbered chapters (plus a ch. 9.5) across 10 volumes, ending June 2018. AniList's entry reports 54 chapters because it folds in the Volume 0 bonus chapters and one-shot specials; the figures here track the 49-chapter main story, which both anime seasons fully adapt. The OVA and the separate 'After School' / 'engagement' sequels are excluded.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 29], + "arc": "The Revenge Plan (Aki & Yoshino / Tsunade Island / culture-festival play, vols 1-6)" + }, + { + "episodes": [13, 24], + "chapters": [30, 49], + "arc": "Resolution (the Yoshino twist through the finale, vols 7-10)" + } + ] +} From b4a301af5c323bc242e0afd668f8c1723799555c Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:25:17 -0400 Subject: [PATCH 03/46] KSN: add `nichijou.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: episodic gag arcs (manga vols 1-7 + KyoAni originals) + ongoing tail - anime `10165` → manga `33082` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/nichijou.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/nichijou.json diff --git a/src/data/index.ts b/src/data/index.ts index f350ff3..8061813 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -162,6 +162,7 @@ import toYourEternity from "@/data/mappings/to-your-eternity.json"; import callOfTheNight from "@/data/mappings/call-of-the-night.json"; import chivalryOfAFailedKnight from "@/data/mappings/chivalry-of-a-failed-knight.json"; import masamuneKunRevenge from "@/data/mappings/masamune-kun-revenge.json"; +import nichijou from "@/data/mappings/nichijou.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -393,6 +394,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ callOfTheNight, chivalryOfAFailedKnight, masamuneKunRevenge, + nichijou, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/nichijou.json b/src/data/mappings/nichijou.json new file mode 100644 index 0000000..00e71b2 --- /dev/null +++ b/src/data/mappings/nichijou.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 10165, + "anilistMangaId": 33082, + "title": "Nichijou - My Ordinary Life", + "sourceNotes": "Single 26-episode TV season (2011, Kyoto Animation). Nichijou is a slice-of-life gag manga by Keiichi Arawi with no continuous story arcs — just episodic vignettes — so the adaptation is treated as one entry plus an unadapted tail. The manga's first run ended in 2015 (vol 10, ~ch 192) but was revived in 2021 and is ONGOING (12 volumes / roughly ch 231 as of vol 12, Oct 2024); chapter counting is fuzzy because installments are short numbered segments with half-numbered entries. The anime adapts material from roughly vols 1-7 (ch 1-124), reordered and interleaved with KyoAni-original segments. The related 'Episode 0' is an OVA (no theatrical film exists), so no movies are listed.", + "mappings": [ + { + "episodes": [1, 26], + "chapters": [1, 124], + "arc": "Everyday vignettes (manga vols 1-7 + anime-original segments)" + }, + { + "chapters": [125, 231], + "arc": "Later vignettes (vols 8-12) — manga only, ongoing" + } + ] +} From 663574572445ec6fdb3cd459725804184ac29f04 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:25:34 -0400 Subject: [PATCH 04/46] KSN: add `gachiakuta.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs: S1 split-cour through ch 87 + ongoing tail - anime `178025` → manga `144946` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/gachiakuta.json | 37 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/gachiakuta.json diff --git a/src/data/index.ts b/src/data/index.ts index 8061813..65c8c1c 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -163,6 +163,7 @@ import callOfTheNight from "@/data/mappings/call-of-the-night.json"; import chivalryOfAFailedKnight from "@/data/mappings/chivalry-of-a-failed-knight.json"; import masamuneKunRevenge from "@/data/mappings/masamune-kun-revenge.json"; import nichijou from "@/data/mappings/nichijou.json"; +import gachiakuta from "@/data/mappings/gachiakuta.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -395,6 +396,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ chivalryOfAFailedKnight, masamuneKunRevenge, nichijou, + gachiakuta, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/gachiakuta.json b/src/data/mappings/gachiakuta.json new file mode 100644 index 0000000..d7fb861 --- /dev/null +++ b/src/data/mappings/gachiakuta.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 178025, + "anilistMangaId": 144946, + "title": "Gachiakuta", + "sourceNotes": "Season 1 was a split-cour, two-cour run totaling 24 episodes, both cours airing in 2025 (eps 1-12 Jul-Sep, eps 13-24 Oct-Dec). Manga by Kei Urana (Weekly Shonen Magazine) is ONGOING (roughly ch 168 / 18 volumes by mid-2026). The anime adapts ch 1-87, stopping partway into the Heritage Mural arc; remaining arcs are an unadapted manga-only tail. A second season is confirmed. Per-episode chapter boundaries follow AnimeFillerGuide's mapping (0 filler).", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 6], + "arc": "Ground Wanderer (Rudo framed, falls to the Ground)" + }, + { + "episodes": [4, 8], + "chapters": [7, 24], + "arc": "Workplace Observation & Raiders Trap" + }, + { + "episodes": [9, 13], + "chapters": [25, 43], + "arc": "Successor Spellcaster & The Lady of Penta" + }, + { + "episodes": [14, 22], + "chapters": [44, 81], + "arc": "Trash Storm" + }, + { + "episodes": [23, 24], + "chapters": [82, 87], + "arc": "Heritage Mural (opening; anime stops mid-arc)" + }, + { + "chapters": [88, 168], + "arc": "Heritage Mural finale → Doll Festival — manga only, ongoing" + } + ] +} From 06a76e5296661db96a9355da1de1b1d5a08b8d9d Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:25:50 -0400 Subject: [PATCH 05/46] KSN: add `zom-100.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: S1 through ch 22 (Hometown of the Dead) + ongoing tail - anime `159831` → manga `104660` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/zom-100.json | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/zom-100.json diff --git a/src/data/index.ts b/src/data/index.ts index 65c8c1c..0977270 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -164,6 +164,7 @@ import chivalryOfAFailedKnight from "@/data/mappings/chivalry-of-a-failed-knight import masamuneKunRevenge from "@/data/mappings/masamune-kun-revenge.json"; import nichijou from "@/data/mappings/nichijou.json"; import gachiakuta from "@/data/mappings/gachiakuta.json"; +import zom100 from "@/data/mappings/zom-100.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -397,6 +398,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ masamuneKunRevenge, nichijou, gachiakuta, + zom100, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/zom-100.json b/src/data/mappings/zom-100.json new file mode 100644 index 0000000..1dcc268 --- /dev/null +++ b/src/data/mappings/zom-100.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 159831, + "anilistMangaId": 104660, + "title": "Zom 100: Bucket List of the Dead", + "sourceNotes": "Single 12-episode TV season (2023). Manga by Haro Aso & Kotaro Takata (Monthly Sunday Gene-X) is ONGOING (roughly ch 88 / 22 volumes by mid-2026, with hiatuses). The anime adapts ch 1-22, concluding with the 'Hometown of the Dead' arc; everything after is an unadapted manga-only tail. Per-episode chapter boundaries are approximate (the anime's broadcast was heavily delayed). Only the 2023 live-action Netflix film exists — no animated film — so no movies are listed.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 7], + "arc": "Tokyo Outbreak (Bucket List begins / Flight Attendants / Hero, vols 1-2)" + }, + { + "episodes": [6, 8], + "chapters": [8, 11], + "arc": "RV & Truck Stop (vol 3)" + }, + { + "episodes": [9, 12], + "chapters": [12, 22], + "arc": "Hot Springs & Hometown of the Dead (vols 4-6)" + }, + { + "chapters": [23, 88], + "arc": "Cross-Country journey onward (Spartathalon → Vaccine of the Dead) — manga only, ongoing" + } + ] +} From e6567aad0c12239f0e5697439cf04871a5b65bdb Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:26:07 -0400 Subject: [PATCH 06/46] KSN: add `chunibyo.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: 2 seasons + unadapted tail; mapped to the light novel (no manga adaptation exists) - 1 movie: Love, Chunibyo & Other Delusions: Take on Me - anime `14741` → manga `70099` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/chunibyo.json | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/chunibyo.json diff --git a/src/data/index.ts b/src/data/index.ts index 0977270..8c510bc 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -165,6 +165,7 @@ import masamuneKunRevenge from "@/data/mappings/masamune-kun-revenge.json"; import nichijou from "@/data/mappings/nichijou.json"; import gachiakuta from "@/data/mappings/gachiakuta.json"; import zom100 from "@/data/mappings/zom-100.json"; +import chunibyo from "@/data/mappings/chunibyo.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -399,6 +400,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ nichijou, gachiakuta, zom100, + chunibyo, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/chunibyo.json b/src/data/mappings/chunibyo.json new file mode 100644 index 0000000..fe2aec6 --- /dev/null +++ b/src/data/mappings/chunibyo.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 14741, + "anilistMangaId": 70099, + "title": "Love, Chunibyo & Other Delusions", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 'Ren' / Heart Throb (12, eps 13-24) = 24 total. No canonical manga adaptation exists, so this maps to the Torako light novel (AniList id 70099, light-novel format, 4 volumes / 51 'chapters', FINISHED). The KyoAni anime is largely anime-original and deviates heavily from the novel, so chapter boundaries are nominal/approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 26], + "arc": "Far East Magical Napping Society of Summer (S1: Dark Flame Master & the Wicked Eye)" + }, + { + "episodes": [13, 24], + "chapters": [27, 51], + "arc": "Heart Throb (S2 'Ren': Sophia Ring SP Saturn 7 / Satone)" + } + ], + "movies": [ + { + "anilistId": 98762, + "title": "Love, Chunibyo & Other Delusions: Take on Me", + "year": 2018, + "afterEpisode": 24, + "note": "Canon new-story KyoAni film and series finale, set after S2 (Rikka & Yuuta's runaway journey)." + } + ] +} From 23e804b808dde6b6493644e087e566c4117420ef Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:26:23 -0400 Subject: [PATCH 07/46] KSN: add `tower-of-god.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: S1 Part 1 (webtoon eps 1-78) + unadapted tail - anime `115230` → manga `85143` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/tower-of-god.json | 32 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/tower-of-god.json diff --git a/src/data/index.ts b/src/data/index.ts index 8c510bc..b616c43 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -166,6 +166,7 @@ import nichijou from "@/data/mappings/nichijou.json"; import gachiakuta from "@/data/mappings/gachiakuta.json"; import zom100 from "@/data/mappings/zom-100.json"; import chunibyo from "@/data/mappings/chunibyo.json"; +import towerOfGod from "@/data/mappings/tower-of-god.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -401,6 +402,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ gachiakuta, zom100, chunibyo, + towerOfGod, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/tower-of-god.json b/src/data/mappings/tower-of-god.json new file mode 100644 index 0000000..179be10 --- /dev/null +++ b/src/data/mappings/tower-of-god.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 115230, + "anilistMangaId": 85143, + "title": "Tower of God", + "sourceNotes": "S1 anime (13 eps, 2020) adapts the entirety of webtoon Part 1 (episodes 1-78), heavily compressing the back half. Paired with SIU's webtoon 'Tower of God' (AniList id 85143, type MANGA); its 'chapters' are webtoon episodes. Numbering here uses the platform's cumulative episode index (Part 1 = 1-78); the webtoon reached its Season 3 finale at internal episode ~653 (Feb 2025, now on hiatus). Episode-to-arc boundaries within S1 are approximate. A 2024 anime Season 2 (26 eps, separate AniList id 153406) adapts early Part 2 (Workshop Battle) and is not mapped here.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 13], + "arc": "Headon's Floor → Yu Hansung's Examination (entrance tests)" + }, + { + "episodes": [5, 9], + "chapters": [14, 27], + "arc": "Crown Game / The Rest" + }, + { + "episodes": [10, 12], + "chapters": [28, 56], + "arc": "Position Test / Hide-and-Seek / The Submerged Fish" + }, + { + "episodes": [13, 13], + "chapters": [57, 78], + "arc": "Last Examination & Rachel's Betrayal (Part 1 finale)" + }, + { + "chapters": [79, 653], + "arc": "Part 2 & Part 3 (Workshop Battle → Hell Train → Season 3 finale; early Part 2 adapted by the 2024 anime S2)" + } + ] +} From 3ad9d99f44b3a22326d34509031176ea92e9586e Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:24 -0400 Subject: [PATCH 08/46] KSN: add `dragon-maid.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1 + S2 'S' + ongoing tail (episodic, approximate boundaries) - 1 movie: Miss Kobayashi's Dragon Maid: A lonely dragon wants to be loved - anime `21776` → manga `86303` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/dragon-maid.json | 31 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/data/mappings/dragon-maid.json diff --git a/src/data/index.ts b/src/data/index.ts index b616c43..1f6d8f7 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -167,6 +167,7 @@ import gachiakuta from "@/data/mappings/gachiakuta.json"; import zom100 from "@/data/mappings/zom-100.json"; import chunibyo from "@/data/mappings/chunibyo.json"; import towerOfGod from "@/data/mappings/tower-of-god.json"; +import dragonMaid from "@/data/mappings/dragon-maid.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -403,6 +404,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ zom100, chunibyo, towerOfGod, + dragonMaid, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/dragon-maid.json b/src/data/mappings/dragon-maid.json new file mode 100644 index 0000000..c26ec27 --- /dev/null +++ b/src/data/mappings/dragon-maid.json @@ -0,0 +1,31 @@ +{ + "anilistAnimeId": 21776, + "anilistMangaId": 86303, + "title": "Miss Kobayashi's Dragon Maid", + "sourceNotes": "Cumulative episodes across S1 (13) + S2 'S' (12, eps 14-25) = 25 total. Paired with the Coolkyousinnjya manga (ongoing, ~19 volumes / ch. ~190 as of 2026, serialized in Monthly Action / Manga Action). The manga is largely episodic slice-of-life and KyoAni adapts it out of order, so chapter boundaries are approximate; volume anchors are firmer (S1 ~vols 1-3, S2 ~vols 4-6, film ~vol 8).", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 34], + "arc": "Tohru & Kobayashi / Kanna's School → Tohru's Father (S1, vols 1-3)" + }, + { + "episodes": [14, 25], + "chapters": [35, 64], + "arc": "Ilulu's Introduction / Elma's Daily Life (Dragon Maid S, vols 4-6)" + }, + { + "chapters": [65, 190], + "arc": "Kanna's Father / Chaos-Harmony War & later episodic arcs (unadapted by TV; partly covered by the 2025 film)" + } + ], + "movies": [ + { + "anilistId": 181839, + "title": "Miss Kobayashi's Dragon Maid: A lonely dragon wants to be loved", + "year": 2025, + "afterEpisode": 25, + "note": "Canon KyoAni film set after Dragon Maid S, adapting the Kanna's father / Chaos-Harmony arc (~manga vol 8)." + } + ] +} From d756f3ccbe5eb86a75ec0fa746d1e2af541e1b4a Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:24 -0400 Subject: [PATCH 09/46] KSN: add `seraph-of-the-end.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1 + S2 'Battle in Nagoya' + ongoing tail - anime `20829` → manga `73661` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/seraph-of-the-end.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/seraph-of-the-end.json diff --git a/src/data/index.ts b/src/data/index.ts index 1f6d8f7..4166aaf 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -168,6 +168,7 @@ import zom100 from "@/data/mappings/zom-100.json"; import chunibyo from "@/data/mappings/chunibyo.json"; import towerOfGod from "@/data/mappings/tower-of-god.json"; import dragonMaid from "@/data/mappings/dragon-maid.json"; +import seraphOfTheEnd from "@/data/mappings/seraph-of-the-end.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -405,6 +406,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ chunibyo, towerOfGod, dragonMaid, + seraphOfTheEnd, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/seraph-of-the-end.json b/src/data/mappings/seraph-of-the-end.json new file mode 100644 index 0000000..f2f20c2 --- /dev/null +++ b/src/data/mappings/seraph-of-the-end.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 20829, + "anilistMangaId": 73661, + "title": "Seraph of the End: Vampire Reign", + "sourceNotes": "Cumulative episodes across S1 'Vampire Reign' (12) + S2 'Battle in Nagoya' (12, eps 13-24) = 24 total. Paired with the Takaya Kagami / Yamato Yamamoto manga (AniList id 73661, ongoing, ~37 volumes / latest collected ch. ~155 as of 2026, serialized in Jump SQ). The two anime seasons cover through the end of the Nagoya arc (~ch 41 / vol 11); everything from vol 12 onward is unadapted. The S1/S2 chapter cutoff is approximate due to anime reordering.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 15], + "arc": "Vampire Reign (S1: Prologue / Second Shibuya High / Shinjuku, vols 1-5)" + }, + { + "episodes": [13, 24], + "chapters": [16, 41], + "arc": "Battle in Nagoya (S2: Post-Shinjuku → Nagoya arc, vols 5-11)" + }, + { + "chapters": [42, 155], + "arc": "Post-Nagoya → Osaka → Shibuya → Akihabara → Mount Fuji & beyond (unadapted; manga ongoing)" + } + ] +} From 1efc0bc22f4a932422e1a11646327f866d00251e Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:25 -0400 Subject: [PATCH 10/46] KSN: add `wotakoi.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: 11-ep coverage (manga vols 1-3) + unadapted tail - anime `99578` → manga `86717` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/wotakoi.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/wotakoi.json diff --git a/src/data/index.ts b/src/data/index.ts index 4166aaf..bf63ac8 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -169,6 +169,7 @@ import chunibyo from "@/data/mappings/chunibyo.json"; import towerOfGod from "@/data/mappings/tower-of-god.json"; import dragonMaid from "@/data/mappings/dragon-maid.json"; import seraphOfTheEnd from "@/data/mappings/seraph-of-the-end.json"; +import wotakoi from "@/data/mappings/wotakoi.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -407,6 +408,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ towerOfGod, dragonMaid, seraphOfTheEnd, + wotakoi, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/wotakoi.json b/src/data/mappings/wotakoi.json new file mode 100644 index 0000000..a3edde6 --- /dev/null +++ b/src/data/mappings/wotakoi.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 99578, + "anilistMangaId": 86717, + "title": "Wotakoi: Love is Hard for Otaku", + "sourceNotes": "Single-season anime (11 eps, 2018). Paired with Fujita's manga (AniList id 86717), complete at 11 volumes (Comic POOL, ended July 2021); AniList counts 115 short web 'chapters' (other sources cite ~82 main numbered chapters). The anime is episodic and adapts roughly volumes 1-3 (through ~chapter 28), so boundaries are approximate.", + "mappings": [ + { + "episodes": [1, 11], + "chapters": [1, 28], + "arc": "Narumi & Hirotaka / Hanako & Kabakura (vols 1-3)" + }, + { + "chapters": [29, 115], + "arc": "Later chapters (vols 4-11; manga complete, unadapted by TV)" + } + ] +} From 294189663cdcde788ed90673fa2ad4ab22ca17c7 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:25 -0400 Subject: [PATCH 11/46] KSN: add `high-school-dxd.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: S1-S4/Hero (eps 1-48) across ch 1-78 - anime `11617` → manga `60859` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/high-school-dxd.json | 28 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/data/mappings/high-school-dxd.json diff --git a/src/data/index.ts b/src/data/index.ts index bf63ac8..999d4c1 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -170,6 +170,7 @@ import towerOfGod from "@/data/mappings/tower-of-god.json"; import dragonMaid from "@/data/mappings/dragon-maid.json"; import seraphOfTheEnd from "@/data/mappings/seraph-of-the-end.json"; import wotakoi from "@/data/mappings/wotakoi.json"; +import highSchoolDxd from "@/data/mappings/high-school-dxd.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -409,6 +410,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ dragonMaid, seraphOfTheEnd, wotakoi, + highSchoolDxd, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/high-school-dxd.json b/src/data/mappings/high-school-dxd.json new file mode 100644 index 0000000..fec186a --- /dev/null +++ b/src/data/mappings/high-school-dxd.json @@ -0,0 +1,28 @@ +{ + "anilistAnimeId": 11617, + "anilistMangaId": 60859, + "title": "High School DxD", + "sourceNotes": "Cumulative episodes across S1 'High School DxD' (12, eps 1-12) + S2 'High School DxD New' (12, eps 13-24) + S3 'High School DxD BorN' (12, eps 25-36) + S4 'High School DxD Hero' (12, eps 37-48) = 48 total; the S4 episode 0 special 'Holiness Behind the Gym' is excluded from the count. Paired with the Hiroji Mishima manga adaptation (complete at 78 ch / 11 vols). Both anime and manga adapt Ichiei Ishibumi's light novels, so per-arc chapter boundaries are approximate. The manga ran behind the anime and concluded around the early Heroic Oppai Dragon arc (~LN vol 7-8); S4 adapts later LN content (vols 9-10) the manga never fully reached, so the final entry's chapter range is nominal, extending to the manga's last chapter (78).", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 20], + "arc": "The Red Dragon Emperor's Awakening (Raynare & Riser Phenex) [LN vols 1-2]" + }, + { + "episodes": [13, 24], + "chapters": [21, 42], + "arc": "Excalibur of the Moonlit Schoolyard & Vampire of the Empty Classroom (Kokabiel / Peace Conference) [LN vols 3-4]" + }, + { + "episodes": [25, 36], + "chapters": [43, 64], + "arc": "Birth of the Breast Dragon Emperor / The Heroic Oppai Dragon (Diodora, Loki & Sairaorg) [LN vols 5-7]" + }, + { + "episodes": [37, 48], + "chapters": [65, 78], + "arc": "Hero: The Hero Faction (Cao Cao) [LN vols 9-10]" + } + ] +} From 2374818eca27226546737ca703f99f7883b1031b Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:25 -0400 Subject: [PATCH 12/46] KSN: add `rent-a-girlfriend.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs: S1-S3 (eps 1-36) + ongoing tail (current ch. 429) - anime `113813` → manga `99943` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/rent-a-girlfriend.json | 42 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/rent-a-girlfriend.json diff --git a/src/data/index.ts b/src/data/index.ts index 999d4c1..6750e06 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -171,6 +171,7 @@ import dragonMaid from "@/data/mappings/dragon-maid.json"; import seraphOfTheEnd from "@/data/mappings/seraph-of-the-end.json"; import wotakoi from "@/data/mappings/wotakoi.json"; import highSchoolDxd from "@/data/mappings/high-school-dxd.json"; +import rentAGirlfriend from "@/data/mappings/rent-a-girlfriend.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -411,6 +412,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ seraphOfTheEnd, wotakoi, highSchoolDxd, + rentAGirlfriend, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/rent-a-girlfriend.json b/src/data/mappings/rent-a-girlfriend.json new file mode 100644 index 0000000..dff79a1 --- /dev/null +++ b/src/data/mappings/rent-a-girlfriend.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 113813, + "anilistMangaId": 99943, + "title": "Rent-a-Girlfriend", + "sourceNotes": "Cumulative episodes across S1 (12, 2020, eps 1-12) + S2 (12, 2022, eps 13-24) + S3 (12, 2023, eps 25-36) = 36 total. Manga by Reiji Miyajima is ONGOING in Weekly Shonen Magazine (current ch. 429; 46 tankobon volumes as of June 2026; AniList lists its chapter count as null). S1 adapts roughly vol 1-6 (ch 1-50), S2 vol 7-12 (ch ~51-104), S3 vol 13-19 (ch ~105-167); intra-season chapter boundaries are approximate (split proportionally by episode). The unadapted tail (ch 168-429) is included chapters-only; note that S4 (2025) and S5 (2026) later adapt part of this tail but are out of scope for this S1-S3 mapping. No theatrical films.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 25], + "arc": "Rental Girlfriend / Grandmother Hospitalized (S1)" + }, + { + "episodes": [7, 12], + "chapters": [26, 50], + "arc": "Class Beach Trip / Next-Door Neighbor (S1)" + }, + { + "episodes": [13, 18], + "chapters": [51, 77], + "arc": "Ruka & Sumi / The Boyfriend Lie (S2)" + }, + { + "episodes": [19, 24], + "chapters": [78, 104], + "arc": "Stage Play / Chizuru's Acting Dream (S2)" + }, + { + "episodes": [25, 30], + "chapters": [105, 136], + "arc": "Indie Movie Production / Crowdfunding (S3)" + }, + { + "episodes": [31, 36], + "chapters": [137, 167], + "arc": "Film Screening / Grandmother's Passing (S3)" + }, + { + "chapters": [168, 429], + "arc": "Unadapted Tail (water park & Hawaii trips onward; later adapted by S4/S5)" + } + ] +} From c787f00ff6ce3ffab15126257a8a1e79d28aaacd Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:25 -0400 Subject: [PATCH 13/46] KSN: add `god-of-high-school.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: 13-ep adaptation (webtoon ch 1-112) + unadapted tail - anime `116006` → manga `85141` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/god-of-high-school.json | 27 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/god-of-high-school.json diff --git a/src/data/index.ts b/src/data/index.ts index 6750e06..6a99f2e 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -172,6 +172,7 @@ import seraphOfTheEnd from "@/data/mappings/seraph-of-the-end.json"; import wotakoi from "@/data/mappings/wotakoi.json"; import highSchoolDxd from "@/data/mappings/high-school-dxd.json"; import rentAGirlfriend from "@/data/mappings/rent-a-girlfriend.json"; +import godOfHighSchool from "@/data/mappings/god-of-high-school.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -413,6 +414,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ wotakoi, highSchoolDxd, rentAGirlfriend, + godOfHighSchool, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/god-of-high-school.json b/src/data/mappings/god-of-high-school.json new file mode 100644 index 0000000..9800e14 --- /dev/null +++ b/src/data/mappings/god-of-high-school.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 116006, + "anilistMangaId": 85141, + "title": "The God of High School", + "sourceNotes": "Single 13-episode cours by MAPPA (2020). Paired with Yongje Park's original Korean webtoon (AniList type MANGA, FINISHED at 569 webtoon episodes counted as chapters). The anime adapts only the early portion of the webtoon (roughly episodes 1-112, ending the National Tournament), then compresses, reorders, and diverges with an original divine-awakening finale. Per-arc chapter boundaries are approximate. A large unadapted tail (Sage Realm onward) runs from ch 113 to the 569 ending.", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 55], + "arc": "The God of High School — Seoul Preliminary & Main Tournament" + }, + { + "episodes": [8, 11], + "chapters": [56, 90], + "arc": "The Nationals (team tournament)" + }, + { + "episodes": [12, 13], + "chapters": [91, 112], + "arc": "Nox / Ragnarok conflict & Sun Wukong reveal (anime-original finale; diverges and compresses)" + }, + { + "chapters": [113, 569], + "arc": "Sage Realm → Ragnarok World Tournament → RE: Fight with God (unadapted)" + } + ] +} From 1fc1857f2a20012666dda7db5ba838c5f5d04b25 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:26 -0400 Subject: [PATCH 14/46] KSN: add `clannad.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 11 arcs: Clannad + After Story route arcs (eps 1-47) - anime `2167` → manga `32598` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/clannad.json | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/data/mappings/clannad.json diff --git a/src/data/index.ts b/src/data/index.ts index 6a99f2e..666dc03 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -173,6 +173,7 @@ import wotakoi from "@/data/mappings/wotakoi.json"; import highSchoolDxd from "@/data/mappings/high-school-dxd.json"; import rentAGirlfriend from "@/data/mappings/rent-a-girlfriend.json"; import godOfHighSchool from "@/data/mappings/god-of-high-school.json"; +import clannad from "@/data/mappings/clannad.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -415,6 +416,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ highSchoolDxd, rentAGirlfriend, godOfHighSchool, + clannad, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/clannad.json b/src/data/mappings/clannad.json new file mode 100644 index 0000000..4707a55 --- /dev/null +++ b/src/data/mappings/clannad.json @@ -0,0 +1,63 @@ +{ + "anilistAnimeId": 2167, + "anilistMangaId": 32598, + "title": "CLANNAD", + "sourceNotes": "Cumulative episodes span both seasons: CLANNAD S1 (23 broadcast eps) + CLANNAD: After Story (24 eps) = 47 total, so After Story E1 = episode 24 and the finale E24 = episode 47 (the BD/DVD OVAs 'Another World: Tomoyo Chapter' and 'Another World: Kyou Chapter' are alternate-timeline extras and are not counted). The anime adapts Key's visual novel and is organized by character routes: S1 covers the common/school-life intro plus the Fuko, Kotomi, Tomoyo/Sunohara side routes and Nagisa's Theater Club main route; After Story opens with the Sunohara/Mei, Misae and Yukine side arcs before the main After Story scenario (graduation, work, marriage, Nagisa's death, and the Tomoya/Ushio finale). Mapped to CLANNAD: Official Comic (manga by Juri Misaki), 45 chapters across 8 volumes, complete. IMPORTANT: this manga adaptation primarily follows the main Nagisa/Theater Club scenario and After Story and does NOT adapt the side character routes in the depth the anime does, so the chapter ranges aligned to the side-route episodes (Fuko, Kotomi, Tomoyo, Sunohara, Misae, Yukine) are APPROXIMATE; only the cumulative endpoints (last entry reaches ch. 45) are reliable. The 2007 theatrical film (AniList 1723) is an alternate-continuity retelling and is excluded, so no movies are listed.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 4], + "arc": "Common route / School life - meeting Nagisa & forming the Theater Club" + }, + { + "episodes": [5, 9], + "chapters": [5, 7], + "arc": "Fuko Ibuki route (approximate - condensed in manga)" + }, + { + "episodes": [10, 14], + "chapters": [8, 10], + "arc": "Kotomi Ichinose route (approximate - condensed in manga)" + }, + { + "episodes": [15, 16], + "chapters": [11, 12], + "arc": "Tomoyo Sakagami & Sunohara - student council & 3-on-3 (approximate - condensed in manga)" + }, + { + "episodes": [17, 23], + "chapters": [13, 20], + "arc": "Nagisa Furukawa main route - Theater Club & school festival" + }, + { + "episodes": [24, 26], + "chapters": [21, 22], + "arc": "After Story: Youhei Sunohara & Mei (approximate - condensed in manga)" + }, + { + "episodes": [27, 28], + "chapters": [23, 24], + "arc": "After Story: Misae Sagara (approximate - condensed in manga)" + }, + { + "episodes": [29, 30], + "chapters": [25, 26], + "arc": "After Story: Yukine Miyazawa (approximate - condensed in manga)" + }, + { + "episodes": [31, 38], + "chapters": [27, 34], + "arc": "After Story: graduation, work & marriage (Okazaki & Furukawa families)" + }, + { + "episodes": [39, 44], + "chapters": [35, 42], + "arc": "After Story: Nagisa's death & the Tomoya/Ushio journey" + }, + { + "episodes": [45, 47], + "chapters": [43, 45], + "arc": "After Story finale - the illusionary world & resolution" + } + ] +} From a55659293b4fedb6016fa9b147e2033a76b04627 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:26 -0400 Subject: [PATCH 15/46] KSN: add `maid-sama.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs: 26-ep adaptation + unadapted tail to ch 99 - anime `7054` → manga `32921` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/maid-sama.json | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/maid-sama.json diff --git a/src/data/index.ts b/src/data/index.ts index 666dc03..bf27a1a 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -174,6 +174,7 @@ import highSchoolDxd from "@/data/mappings/high-school-dxd.json"; import rentAGirlfriend from "@/data/mappings/rent-a-girlfriend.json"; import godOfHighSchool from "@/data/mappings/god-of-high-school.json"; import clannad from "@/data/mappings/clannad.json"; +import maidSama from "@/data/mappings/maid-sama.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -417,6 +418,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ rentAGirlfriend, godOfHighSchool, clannad, + maidSama, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/maid-sama.json b/src/data/mappings/maid-sama.json new file mode 100644 index 0000000..8dc4ae4 --- /dev/null +++ b/src/data/mappings/maid-sama.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 7054, + "anilistMangaId": 32921, + "title": "Maid Sama!", + "sourceNotes": "Single 26-episode TV anime (J.C.Staff, 2010). Manga by Hiro Fujiwara is complete: AniList lists 99 chapters across 18 volumes, but the main run is 85 numbered story chapters (ending with ch. 85, where Misaki and Usui marry); AniList's higher total counts side-story/extra chapters. Final chapter count uses AniList's 99 per convention. The anime adapts only the early manga, roughly the first 8 tankobon volumes (about chapters 1-36), stopping around the Hinata Shintani / Seika student-council-election material. The series is largely episodic slice-of-life romance, and the anime reorders events and pads its second cour (eps 14-26) with anime-original content (the Soutarou Kano hypnotism arc, Maid Latte beach/footman events), so episode-to-chapter boundaries are approximate volume-aligned groupings. The large unadapted tail (ch. 37-99) covers the Igarashi/Walker and England (Britain) arcs and the finale. No theatrical films exist (the only Maid-sama film is a 2018 live-action movie, excluded), so the movies key is omitted.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 9], + "arc": "Introduction: Maid-Sama! & Aoi Hyoudou (Vols 1-2)" + }, + { + "episodes": [5, 9], + "chapters": [10, 19], + "arc": "Igarashi Tora / Miyabigaoka & Cultural Festival (Vols 3-4)" + }, + { + "episodes": [10, 11], + "chapters": [20, 24], + "arc": "Sakura's Band & Usui's Past (Vol 5)" + }, + { + "episodes": [12, 13], + "chapters": [25, 28], + "arc": "Sports Festival (Vol 6; first-cour finale)" + }, + { + "episodes": [14, 20], + "chapters": [29, 32], + "arc": "Kano Hypnotism, Beach & Footman Events (Vol 7; anime expands with filler)" + }, + { + "episodes": [21, 26], + "chapters": [33, 36], + "arc": "Hinata Shintani & Student-Council Election (Vol 8; anime ends here)" + }, + { + "chapters": [37, 99], + "arc": "Unadapted Tail: Igarashi/Walker & England (Britain) arcs through the finale (unadapted)" + } + ] +} From 9eba59eae505e4698496c8cdcd853d286825e942 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:26 -0400 Subject: [PATCH 16/46] KSN: add `highschool-of-the-dead.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: Acts 1-18 (manga vols 1-4) + unadapted tail (manga unfinished) - anime `8074` → manga `30669` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/highschool-of-the-dead.json | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/highschool-of-the-dead.json diff --git a/src/data/index.ts b/src/data/index.ts index bf27a1a..d4e479f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -175,6 +175,7 @@ import rentAGirlfriend from "@/data/mappings/rent-a-girlfriend.json"; import godOfHighSchool from "@/data/mappings/god-of-high-school.json"; import clannad from "@/data/mappings/clannad.json"; import maidSama from "@/data/mappings/maid-sama.json"; +import highschoolOfTheDead from "@/data/mappings/highschool-of-the-dead.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -419,6 +420,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ godOfHighSchool, clannad, maidSama, + highschoolOfTheDead, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/highschool-of-the-dead.json b/src/data/mappings/highschool-of-the-dead.json new file mode 100644 index 0000000..2af6d9d --- /dev/null +++ b/src/data/mappings/highschool-of-the-dead.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 8074, + "anilistMangaId": 30669, + "title": "Highschool of the Dead", + "sourceNotes": "S1 anime (12 eps, 2010, Madhouse) faithfully adapts the manga's first ~18 Acts (tankobon vols 1-4) but reorders events from Episode 9 onward, ending at the very start of the 'Mall of the Dead' arc. The manga (chapters are called 'Acts') is permanently unfinished: 29 Acts collected across 7 volumes plus an uncollected Act.30 (May 2013); serialization stalled and writer Daisuke Sato died in 2017. AniList lists 30 chapters. Act boundaries follow the tankobon volumes; the anime's late-episode ordering diverges from the manga, so those ranges are approximate.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 3], + "arc": "Spring of the Dead (Fujimi Academy Outbreak)" + }, + { + "episodes": [3, 5], + "chapters": [4, 9], + "arc": "Escape Through the City" + }, + { + "episodes": [6, 8], + "chapters": [10, 14], + "arc": "Saya's Home & Takagi Estate" + }, + { + "episodes": [9, 12], + "chapters": [15, 18], + "arc": "Takagi Estate Defense & Mall Approach (anime-reordered finale)" + }, + { + "chapters": [19, 30], + "arc": "Unadapted (Mall of the Dead onward; manga left unfinished)" + } + ] +} From f4052dd14cb6db1d3a71132f3da04ef134e6cbd4 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:27 -0400 Subject: [PATCH 17/46] KSN: add `beyond-the-boundary.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: 12-ep run + unadapted tail; mapped to the light novel (no manga on AniList) - 1 movie: Beyond the Boundary -I'LL BE HERE-: Future - anime `18153` → manga `80117` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/beyond-the-boundary.json | 27 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/beyond-the-boundary.json diff --git a/src/data/index.ts b/src/data/index.ts index d4e479f..789c5a1 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -176,6 +176,7 @@ import godOfHighSchool from "@/data/mappings/god-of-high-school.json"; import clannad from "@/data/mappings/clannad.json"; import maidSama from "@/data/mappings/maid-sama.json"; import highschoolOfTheDead from "@/data/mappings/highschool-of-the-dead.json"; +import beyondTheBoundary from "@/data/mappings/beyond-the-boundary.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -421,6 +422,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ clannad, maidSama, highschoolOfTheDead, + beyondTheBoundary, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/beyond-the-boundary.json b/src/data/mappings/beyond-the-boundary.json new file mode 100644 index 0000000..b1c038d --- /dev/null +++ b/src/data/mappings/beyond-the-boundary.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 18153, + "anilistMangaId": 80117, + "title": "Beyond the Boundary", + "sourceNotes": "S1 anime (12 eps, 2013, Kyoto Animation) adapts Nagomu Torii's light novel. AniList has no manga-adaptation entry for this series, so this maps to the light novel (id 80117), treating its 3 published volumes as 'chapters' 1-3; boundaries are approximate because KyoAni heavily reordered and added original material. The film 'I'll Be Here -Future-' (2015) is a canon sequel with new content (included below); 'I'll Be Here -Past-' (2015) is a recap re-edit of eps 1-12 and is excluded.", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 2], + "arc": "Hollow Shadow Arc (Mirai & Akihito)" + }, + { + "episodes": [8, 12], + "chapters": [3, 3], + "arc": "Beyond the Boundary Arc (climax)" + } + ], + "movies": [ + { + "anilistId": 20963, + "title": "Beyond the Boundary -I'LL BE HERE-: Future", + "year": 2015, + "afterEpisode": 12, + "note": "Canon sequel film with new content continuing after the TV series." + } + ] +} From cce1e699a4cc2293734a78fa23d54319fdcb3a74 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:27 -0400 Subject: [PATCH 18/46] KSN: add `pet-girl-of-sakurasou.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: first-cour coverage (LN vols 1-4, where the manga ends) - anime `13759` → manga `58107` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/pet-girl-of-sakurasou.json | 23 ++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/pet-girl-of-sakurasou.json diff --git a/src/data/index.ts b/src/data/index.ts index 789c5a1..2b83895 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -177,6 +177,7 @@ import clannad from "@/data/mappings/clannad.json"; import maidSama from "@/data/mappings/maid-sama.json"; import highschoolOfTheDead from "@/data/mappings/highschool-of-the-dead.json"; import beyondTheBoundary from "@/data/mappings/beyond-the-boundary.json"; +import petGirlOfSakurasou from "@/data/mappings/pet-girl-of-sakurasou.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -423,6 +424,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ maidSama, highschoolOfTheDead, beyondTheBoundary, + petGirlOfSakurasou, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/pet-girl-of-sakurasou.json b/src/data/mappings/pet-girl-of-sakurasou.json new file mode 100644 index 0000000..d48fbf2 --- /dev/null +++ b/src/data/mappings/pet-girl-of-sakurasou.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 13759, + "anilistMangaId": 58107, + "title": "The Pet Girl of Sakurasou", + "sourceNotes": "TV anime (24 eps, 2012-2013, J.C.Staff) adapts Hajime Kamoshida's light novel (13 vols). Paired with the Hoki Kusano manga adaptation (id 58107, 49 ch / 8 vols, ended 2015), which is an incomplete adaptation covering only roughly LN vols 1-4 -- about the anime's first cour (eps ~1-13). Anime eps 14-24 (LN vols 5-7: end-of-year exams, the student anime project, and the graduation finale) have no manga counterpart, so the mapping ends with the anime's first cour. Chapter boundaries are approximate.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 12], + "arc": "Mashiro Moves Into Sakura Hall (LN vol 1)" + }, + { + "episodes": [5, 9], + "chapters": [13, 30], + "arc": "Game Project & Chasing Dreams (LN vols 2-3)" + }, + { + "episodes": [10, 13], + "chapters": [31, 49], + "arc": "Sakura Hall Festival & Christmas (LN vols 3-4, first-cour climax)" + } + ] +} From ec57c5797bc5130f83fd8f44bd852e79d6251df5 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:27 -0400 Subject: [PATCH 19/46] KSN: add `elfen-lied.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: through ch 61 + anime-original ending; unadapted tail (manga complete) - anime `226` → manga `30933` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/elfen-lied.json | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/elfen-lied.json diff --git a/src/data/index.ts b/src/data/index.ts index 2b83895..e6178e2 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -178,6 +178,7 @@ import maidSama from "@/data/mappings/maid-sama.json"; import highschoolOfTheDead from "@/data/mappings/highschool-of-the-dead.json"; import beyondTheBoundary from "@/data/mappings/beyond-the-boundary.json"; import petGirlOfSakurasou from "@/data/mappings/pet-girl-of-sakurasou.json"; +import elfenLied from "@/data/mappings/elfen-lied.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -425,6 +426,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ highschoolOfTheDead, beyondTheBoundary, petGirlOfSakurasou, + elfenLied, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/elfen-lied.json b/src/data/mappings/elfen-lied.json new file mode 100644 index 0000000..b5d1bf7 --- /dev/null +++ b/src/data/mappings/elfen-lied.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 226, + "anilistMangaId": 30933, + "title": "Elfen Lied", + "sourceNotes": "TV anime (13 eps, 2004, Arms) adapts Lynn Okamoto's manga but compresses and heavily reorders the multi-chapter flashbacks, and by the finale diverges into an anime-original ending. It loosely covers roughly the first six volumes (through ch. ~61; readers are advised to continue the manga around ch. 62). The manga is complete: AniList lists 113 chapters (commonly cited as 107 numbered chapters plus extras) across 12 volumes. Per-arc chapter ranges are approximate due to the anime's reordering.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 15], + "arc": "Lucy's Escape & Maple House (Kouta, Yuka, Nyu)" + }, + { + "episodes": [5, 9], + "chapters": [16, 40], + "arc": "Nana, Bando & Mayu's Past" + }, + { + "episodes": [10, 13], + "chapters": [41, 61], + "arc": "Kakuzawa Conspiracy & Lucy's Origin (anime-original ending)" + }, + { + "chapters": [62, 113], + "arc": "Unadapted (Diclonius War & the manga's true conclusion)" + } + ] +} From 4ebd3393f3230cce95a38adbdd33c2858a0a5e26 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:28 -0400 Subject: [PATCH 20/46] KSN: add `nagatoro.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: S1 + S2 '2nd Attack' + unadapted tail (manga complete, 154 ch) - anime `120697` → manga `100664` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/nagatoro.json | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/nagatoro.json diff --git a/src/data/index.ts b/src/data/index.ts index e6178e2..e13ea20 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -179,6 +179,7 @@ import highschoolOfTheDead from "@/data/mappings/highschool-of-the-dead.json"; import beyondTheBoundary from "@/data/mappings/beyond-the-boundary.json"; import petGirlOfSakurasou from "@/data/mappings/pet-girl-of-sakurasou.json"; import elfenLied from "@/data/mappings/elfen-lied.json"; +import nagatoro from "@/data/mappings/nagatoro.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -427,6 +428,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ beyondTheBoundary, petGirlOfSakurasou, elfenLied, + nagatoro, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/nagatoro.json b/src/data/mappings/nagatoro.json new file mode 100644 index 0000000..1826142 --- /dev/null +++ b/src/data/mappings/nagatoro.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 120697, + "anilistMangaId": 100664, + "title": "Don't Toy with Me, Miss Nagatoro", + "sourceNotes": "Cumulative episodes across S1 (12, 2021) + S2 '2nd Attack' (12, 2023) = 24. S1 covers the first six volumes (~ch. 1-46); S2 continues through five chapters of vol. 12, ending around ch. 91 (read on from ch. 92). The manga is complete at 154 numbered chapters / 20 volumes (ended July 2024); AniList id 100664 lists 188 'chapters' because it counts the many '.5' bonus chapters, so this mapping uses the official numbering. Slice-of-life groupings are approximate and aligned to volume boundaries.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 23], + "arc": "Teasing Senpai (vols 1-3)" + }, + { + "episodes": [7, 12], + "chapters": [24, 46], + "arc": "Art Club & Cultural Festival (vols 4-6, S1 finale)" + }, + { + "episodes": [13, 18], + "chapters": [47, 70], + "arc": "Sports Festival & Gamo's Gang (vols 7-9)" + }, + { + "episodes": [19, 24], + "chapters": [71, 91], + "arc": "Sleepover & Deepening Bond (vols 10-12, S2 finale)" + }, + { + "chapters": [92, 154], + "arc": "Unadapted (dating & finale)" + } + ] +} From abce0b164a8e6f1aa6c238e0806c320924917bef Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:28 -0400 Subject: [PATCH 21/46] KSN: add `bunny-girl-senpai.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs: 5 TV arcs + unadapted tail; mapped to LN volumes (no unified manga) - 3 movies: Rascal Does Not Dream of a Dreaming Girl; Rascal Does Not Dream of a Sister Venturing Out; Rascal Does Not Dream of a Knapsack Kid - anime `101291` → manga `91170` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/bunny-girl-senpai.json | 63 ++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/data/mappings/bunny-girl-senpai.json diff --git a/src/data/index.ts b/src/data/index.ts index e13ea20..4facc5f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -180,6 +180,7 @@ import beyondTheBoundary from "@/data/mappings/beyond-the-boundary.json"; import petGirlOfSakurasou from "@/data/mappings/pet-girl-of-sakurasou.json"; import elfenLied from "@/data/mappings/elfen-lied.json"; import nagatoro from "@/data/mappings/nagatoro.json"; +import bunnyGirlSenpai from "@/data/mappings/bunny-girl-senpai.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -429,6 +430,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ petGirlOfSakurasou, elfenLied, nagatoro, + bunnyGirlSenpai, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/bunny-girl-senpai.json b/src/data/mappings/bunny-girl-senpai.json new file mode 100644 index 0000000..b695f1e --- /dev/null +++ b/src/data/mappings/bunny-girl-senpai.json @@ -0,0 +1,63 @@ +{ + "anilistAnimeId": 101291, + "anilistMangaId": 91170, + "title": "Rascal Does Not Dream of Bunny Girl Senpai", + "sourceNotes": "Source is Hajime Kamoshida's light novel series, which AniList splits into one media entry per volume and which has no unified manga adaptation (only fragmentary per-arc manga). This mapping therefore uses LIGHT-NOVEL VOLUME NUMBERS as the 'chapters' axis; anilistMangaId 91170 is LN vol 1 ('Bunny Girl Senpai'), the representative source entry. The 2018 TV anime (13 eps) adapts LN vols 1-5: Mai (eps 1-3, vol 1), Tomoe (4-6, vol 2), Futaba (7-8, vol 3), Nodoka (9-10, vol 4), Kaede (11-13, vol 5). Three canon films continue the story (vols 6-9). 15 main LN volumes were published through July 2025; vols 10+ are unadapted by these works (later covered by the 2025 TV continuation).", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "Bunny Girl Senpai (Mai Sakurajima) — LN vol 1" + }, + { + "episodes": [4, 6], + "chapters": [2, 2], + "arc": "Petite Devil Kohai (Tomoe Koga) — LN vol 2" + }, + { + "episodes": [7, 8], + "chapters": [3, 3], + "arc": "Logical Witch (Rio Futaba) — LN vol 3" + }, + { + "episodes": [9, 10], + "chapters": [4, 4], + "arc": "Siscon Idol (Nodoka Toyohama) — LN vol 4" + }, + { + "episodes": [11, 13], + "chapters": [5, 5], + "arc": "Sister Home Alone (Kaede Azusagawa) — LN vol 5" + }, + { + "chapters": [6, 15], + "arc": "Post-TV LN arcs (Dreaming Girl → ongoing; vols 6-9 adapted by the films, vols 10+ by the 2025 TV continuation)" + } + ], + "movies": [ + { + "anilistId": 104157, + "title": "Rascal Does Not Dream of a Dreaming Girl", + "year": 2019, + "chapters": [6, 7], + "afterEpisode": 13, + "note": "Canon sequel film adapting the Dreaming Girl arc (LN vols 6-7), resolving the Shoko Makinohara / Mai storyline." + }, + { + "anilistId": 154967, + "title": "Rascal Does Not Dream of a Sister Venturing Out", + "year": 2023, + "chapters": [8, 8], + "afterEpisode": 13, + "note": "Canon film of the University arc (LN vol 8: Odekake Sister)." + }, + { + "anilistId": 161474, + "title": "Rascal Does Not Dream of a Knapsack Kid", + "year": 2023, + "chapters": [9, 9], + "afterEpisode": 13, + "note": "Canon film of the University arc (LN vol 9: Randoseru Girl)." + } + ] +} From 3c140b91dd3c2a42bb289126b673fd23b1535ff3 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:28 -0400 Subject: [PATCH 22/46] KSN: add `toradora.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs: full 25-ep adaptation across the complete 97-chapter manga - anime `4224` → manga `34368` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/toradora.json | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/data/mappings/toradora.json diff --git a/src/data/index.ts b/src/data/index.ts index 4facc5f..7079ec4 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -181,6 +181,7 @@ import petGirlOfSakurasou from "@/data/mappings/pet-girl-of-sakurasou.json"; import elfenLied from "@/data/mappings/elfen-lied.json"; import nagatoro from "@/data/mappings/nagatoro.json"; import bunnyGirlSenpai from "@/data/mappings/bunny-girl-senpai.json"; +import toradora from "@/data/mappings/toradora.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -431,6 +432,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ elfenLied, nagatoro, bunnyGirlSenpai, + toradora, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/toradora.json b/src/data/mappings/toradora.json new file mode 100644 index 0000000..225d47d --- /dev/null +++ b/src/data/mappings/toradora.json @@ -0,0 +1,48 @@ +{ + "anilistAnimeId": 4224, + "anilistMangaId": 34368, + "title": "Toradora!", + "sourceNotes": "Single 25-episode TV anime (2008) adapting Yuyuko Takemiya's 10-volume light novel. Paired with the Zekkyo manga adaptation (97 chapters across 11 published volumes; the manga runs slowly and reaches the story's conclusion at ch 97, with a final extras volume pending). Both anime and manga adapt the same light novel. Per-arc episode/chapter boundaries are approximate (Toradora is a continuous rom-com without formal arc names); chapter groupings follow the manga's volume structure.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 14], + "arc": "The Deal: Tiger & Dragon (intro, Kitamura & Minori, Ami arrives)" + }, + { + "episodes": [7, 10], + "chapters": [15, 34], + "arc": "Ami Kawashima / the stalker & summer pool" + }, + { + "episodes": [11, 13], + "chapters": [35, 46], + "arc": "Summer Vacation (Ami's beach villa, fireworks, test of courage)" + }, + { + "episodes": [14, 16], + "chapters": [47, 55], + "arc": "Culture Festival (pro-wrestling play, Taiga's father)" + }, + { + "episodes": [17, 19], + "chapters": [56, 64], + "arc": "Festival Pageant / Student Council (Mr. & Ms. Festival, Kitamura's crisis)" + }, + { + "episodes": [20, 21], + "chapters": [65, 81], + "arc": "Christmas Eve" + }, + { + "episodes": [22, 23], + "chapters": [82, 88], + "arc": "School Ski Trip" + }, + { + "episodes": [24, 25], + "chapters": [89, 97], + "arc": "Confessions & Finale (Valentine's, the elopement)" + } + ] +} From 3118fb9193d8d1b202369da8bf83d29e3406c4d1 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:29 -0400 Subject: [PATCH 23/46] KSN: add `kakegurui.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1 + S2 (eps 1-24) + ongoing tail - anime `98314` → manga `85793` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/kakegurui.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/kakegurui.json diff --git a/src/data/index.ts b/src/data/index.ts index 7079ec4..55c41e0 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -182,6 +182,7 @@ import elfenLied from "@/data/mappings/elfen-lied.json"; import nagatoro from "@/data/mappings/nagatoro.json"; import bunnyGirlSenpai from "@/data/mappings/bunny-girl-senpai.json"; import toradora from "@/data/mappings/toradora.json"; +import kakegurui from "@/data/mappings/kakegurui.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -433,6 +434,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ nagatoro, bunnyGirlSenpai, toradora, + kakegurui, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kakegurui.json b/src/data/mappings/kakegurui.json new file mode 100644 index 0000000..8e4dff6 --- /dev/null +++ b/src/data/mappings/kakegurui.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 98314, + "anilistMangaId": 85793, + "title": "Kakegurui", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 'Kakegurui xx' (12, eps 13-24) = 24 total. Paired with the Homura Kawamoto / Toru Naomura manga 'Kakegurui - Compulsive Gambler -' (ongoing; ~121 chapters / 20+ volumes as of 2026). The anime skips some chapters: S1 covers roughly vols 1-5 (ch 1-27) and S2 the Student Council Election arc through vol 10 (ch 28-56), after which readers resume around ch 55-57. Per-arc chapter boundaries approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 27], + "arc": "S1: Student Council Gambles (Yumeko vs the council members)" + }, + { + "episodes": [13, 24], + "chapters": [28, 56], + "arc": "S2 'Kakegurui xx': Student Council Election Arc" + }, + { + "chapters": [57, 121], + "arc": "Election aftermath onward (unadapted in TV anime; manga ongoing)" + } + ] +} From d5b73a0543c21cf0440b0c0a5f80af81a3cbe613 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:29 -0400 Subject: [PATCH 24/46] KSN: add `classroom-of-the-elite.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1-S3 (eps 1-38); mapped to the Year-1 light novel - anime `98659` → manga `94970` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/classroom-of-the-elite.json | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/classroom-of-the-elite.json diff --git a/src/data/index.ts b/src/data/index.ts index 55c41e0..e8025d9 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -183,6 +183,7 @@ import nagatoro from "@/data/mappings/nagatoro.json"; import bunnyGirlSenpai from "@/data/mappings/bunny-girl-senpai.json"; import toradora from "@/data/mappings/toradora.json"; import kakegurui from "@/data/mappings/kakegurui.json"; +import classroomOfTheElite from "@/data/mappings/classroom-of-the-elite.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -435,6 +436,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ bunnyGirlSenpai, toradora, kakegurui, + classroomOfTheElite, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/classroom-of-the-elite.json b/src/data/mappings/classroom-of-the-elite.json new file mode 100644 index 0000000..8b9ead8 --- /dev/null +++ b/src/data/mappings/classroom-of-the-elite.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 98659, + "anilistMangaId": 94970, + "title": "Classroom of the Elite", + "sourceNotes": "Source is Syougo Kinugasa's light novel. The Yuyu Ichino manga adaptation (AniList id 96798) only reaches LN vol 5 and has been stalled since 2022 — far less complete than the three-season anime — so this mapping uses the 'Year 1' LIGHT NOVEL instead (AniList id 94970, which lists 110 chapters across vols 1-11.5). Cumulative episodes across S1 (12) + S2 (13, eps 13-25) + S3 (13, eps 26-38) = 38 total; together the three seasons adapt all of Year 1 (LN vols 1-11.5). Chapter boundaries are proportional to LN-volume coverage and therefore approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 43], + "arc": "Year 1, First Term: Entrance Exam → Uninhabited Island Special Exam (S1; LN vols 1-4.5)" + }, + { + "episodes": [13, 25], + "chapters": [44, 72], + "arc": "Year 1, Second Term: Sports & Cultural Festivals, Paper Shuffle (S2; LN vols 4.5-7.5)" + }, + { + "episodes": [26, 38], + "chapters": [73, 110], + "arc": "Year 1, Third Term: Mixed Training Camp → Year-End Exams (S3; LN vols 7.5-11.5)" + } + ] +} From 95ae7789040e17364150a54f8256eee648844673 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:30 -0400 Subject: [PATCH 25/46] KSN: add `future-diary.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: full 26-ep adaptation across the complete 59-chapter manga - anime `10620` → manga `30584` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/future-diary.json | 33 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/future-diary.json diff --git a/src/data/index.ts b/src/data/index.ts index e8025d9..3081246 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -184,6 +184,7 @@ import bunnyGirlSenpai from "@/data/mappings/bunny-girl-senpai.json"; import toradora from "@/data/mappings/toradora.json"; import kakegurui from "@/data/mappings/kakegurui.json"; import classroomOfTheElite from "@/data/mappings/classroom-of-the-elite.json"; +import futureDiary from "@/data/mappings/future-diary.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -437,6 +438,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ toradora, kakegurui, classroomOfTheElite, + futureDiary, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/future-diary.json b/src/data/mappings/future-diary.json new file mode 100644 index 0000000..87ee771 --- /dev/null +++ b/src/data/mappings/future-diary.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 10620, + "anilistMangaId": 30584, + "title": "The Future Diary", + "sourceNotes": "Single 26-episode TV anime (2011) faithfully adapting Sakae Esuno's complete manga (59 chapters / 12 volumes). Episode-to-chapter boundaries follow the manga's volume groupings and are approximate (the anime runs ~2.3 chapters per episode). The 'Redial' OVA is a short coda and a separate AniList entry.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 13], + "arc": "The Survival Game Begins (Yuki & Yuno; 3rd Diary Holder)" + }, + { + "episodes": [7, 10], + "chapters": [14, 23], + "arc": "6th & 9th Diary Holders (the cult, the bomber Minene) and escape" + }, + { + "episodes": [11, 15], + "chapters": [24, 33], + "arc": "4th, 7th & 8th Diary Holders (detective, the couple, the orphanage)" + }, + { + "episodes": [16, 20], + "chapters": [34, 43], + "arc": "Diary Holders Converge / Yuno's Truth" + }, + { + "episodes": [21, 26], + "chapters": [44, 59], + "arc": "Endgame & Conclusion (Final Battle, 1st vs Yuno)" + } + ] +} From ca1ecd883af492a937f681921ef65796bc7df787 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:30 -0400 Subject: [PATCH 26/46] KSN: add `danmachi.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: S1 covered by the manga adaptation; Arrow of the Orion film - 1 movie: Is It Wrong to Try to Pick Up Girls in a Dungeon?: Arrow of the Orion - anime `20920` → manga `85161` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/danmachi.json | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/danmachi.json diff --git a/src/data/index.ts b/src/data/index.ts index 3081246..cd35cde 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -185,6 +185,7 @@ import toradora from "@/data/mappings/toradora.json"; import kakegurui from "@/data/mappings/kakegurui.json"; import classroomOfTheElite from "@/data/mappings/classroom-of-the-elite.json"; import futureDiary from "@/data/mappings/future-diary.json"; +import danmachi from "@/data/mappings/danmachi.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -439,6 +440,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ kakegurui, classroomOfTheElite, futureDiary, + danmachi, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/danmachi.json b/src/data/mappings/danmachi.json new file mode 100644 index 0000000..7d9f668 --- /dev/null +++ b/src/data/mappings/danmachi.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 20920, + "anilistMangaId": 85161, + "title": "Is It Wrong to Try to Pick Up Girls in a Dungeon?", + "sourceNotes": "Cumulative episodes across S1 (13) + S2 (12, eps 14-25) + S3 (12, eps 26-37) + S4 (22, eps 38-59) = 59 total, all adapting Fujino Omori's light novels. The only main-story manga is the Kunieda adaptation (id 85161, 89 ch / 10 vols, Young Gangan), which was discontinued in 2018 partway through the Apollo Familia / War Game arc (LN vol ~1-5) and therefore covers only roughly anime Season 1. Seasons 2-4 (eps 14-59, LN vol 6-14+: Ishtar, Xenos/Knossos, etc.) have no manga counterpart and are not mapped here. S1 arc-to-chapter boundaries are approximate.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 26], + "arc": "Hestia Familia: the Minotaur & meeting Lili" + }, + { + "episodes": [5, 8], + "chapters": [27, 54], + "arc": "Soma Familia (Lili) & Bell's awakening" + }, + { + "episodes": [9, 10], + "chapters": [55, 68], + "arc": "18th-Floor expedition (the black Goliath)" + }, + { + "episodes": [11, 13], + "chapters": [69, 89], + "arc": "Apollo Familia & War Game (manga discontinued mid-arc)" + } + ], + "movies": [ + { + "anilistId": 101166, + "title": "Is It Wrong to Try to Pick Up Girls in a Dungeon?: Arrow of the Orion", + "year": 2019, + "afterEpisode": 13, + "note": "Anime-original canon side-story film (later novelized by Omori); set after Season 1, before Season 2. Not part of the manga." + } + ] +} From 1252a91a0d017dd2bbccb90dc5540cc1b281d151 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:30 -0400 Subject: [PATCH 27/46] KSN: add `another.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: full 12-ep adaptation across the complete 4-volume manga - anime `11111` → manga `54098` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/another.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/another.json diff --git a/src/data/index.ts b/src/data/index.ts index cd35cde..ad21183 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -186,6 +186,7 @@ import kakegurui from "@/data/mappings/kakegurui.json"; import classroomOfTheElite from "@/data/mappings/classroom-of-the-elite.json"; import futureDiary from "@/data/mappings/future-diary.json"; import danmachi from "@/data/mappings/danmachi.json"; +import another from "@/data/mappings/another.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -441,6 +442,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ classroomOfTheElite, futureDiary, danmachi, + another, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/another.json b/src/data/mappings/another.json new file mode 100644 index 0000000..d61dec6 --- /dev/null +++ b/src/data/mappings/another.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 11111, + "anilistMangaId": 54098, + "title": "Another", + "sourceNotes": "The 12-episode P.A. Works anime and the 4-volume / 20-chapter Hiro Kiyohara manga (id 54098, complete) both adapt Yukito Ayatsuji's 2009 horror novel. The manga is shorter and notably less deadly: it keeps several characters alive (e.g. Kazami and Ogura survive) and resolves the 'calamity' differently from the anime, which kills off most of the class and stages the climax at the burning summer resort. Endpoints (ep 1 = ch 1, ep 12 = ch 20) are firm; the finale diverges, so the ep 9-12 boundary is approximate.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 6], + "arc": "Transfer to Yomiyama North & the 'nonexistent' Mei Misaki" + }, + { + "episodes": [5, 8], + "chapters": [7, 13], + "arc": "The calamity begins & the failed countermeasure" + }, + { + "episodes": [9, 12], + "chapters": [14, 20], + "arc": "Summer camp & the 'casualty' revealed (anime finale diverges)" + } + ] +} From a846b9be27fea9e3bbfa4a0d348cde2aaa37c2c6 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:31 -0400 Subject: [PATCH 28/46] KSN: add `oregairu.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1-S3 across the complete @comic manga (LN vols 1-14) - anime `14813` → manga `92954` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/oregairu.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/oregairu.json diff --git a/src/data/index.ts b/src/data/index.ts index ad21183..e926229 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -187,6 +187,7 @@ import classroomOfTheElite from "@/data/mappings/classroom-of-the-elite.json"; import futureDiary from "@/data/mappings/future-diary.json"; import danmachi from "@/data/mappings/danmachi.json"; import another from "@/data/mappings/another.json"; +import oregairu from "@/data/mappings/oregairu.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -443,6 +444,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ futureDiary, danmachi, another, + oregairu, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/oregairu.json b/src/data/mappings/oregairu.json new file mode 100644 index 0000000..c1b6a0c --- /dev/null +++ b/src/data/mappings/oregairu.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 14813, + "anilistMangaId": 92954, + "title": "My Teen Romantic Comedy SNAFU", + "sourceNotes": "Cumulative episodes across S1 (13) + S2 'TOO' (13, eps 14-26) + S3 'Climax' (12, eps 27-38) = 38 total. Paired with the Naomichi Io manga adaptation 'My Youth Romantic Comedy Is Wrong, as I Expected @comic' (id 92954, 118 ch / 22 vols, completed Feb 2023) — a faithful, complete adaptation of Wataru Watari's 14-volume light novel. Anime season coverage by LN volume: S1 = vol 1-6, S2 = vol 7-9, S3 = vol 10-14. Manga chapter boundaries are aligned to that LN coverage and are approximate; endpoints are firm (ep 38 = ch 118, the manga's final chapter).", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 48], + "arc": "Service Club formation through the culture festival (LN vol 1-6)" + }, + { + "episodes": [14, 26], + "chapters": [49, 80], + "arc": "The 'genuine thing' through the Christmas event & student council (LN vol 7-9)" + }, + { + "episodes": [27, 38], + "chapters": [81, 118], + "arc": "Prom arc & the conclusion (LN vol 10-14)" + } + ] +} From a297085d1c449dbe8cdd585eb352f57b1d3fee0f Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:31 -0400 Subject: [PATCH 29/46] KSN: add `saiki-k.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1 + S2 + Reawakened across the complete manga - anime `21804` → manga `67755` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/saiki-k.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/saiki-k.json diff --git a/src/data/index.ts b/src/data/index.ts index e926229..e6d8bd9 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -188,6 +188,7 @@ import futureDiary from "@/data/mappings/future-diary.json"; import danmachi from "@/data/mappings/danmachi.json"; import another from "@/data/mappings/another.json"; import oregairu from "@/data/mappings/oregairu.json"; +import saikiK from "@/data/mappings/saiki-k.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -445,6 +446,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ danmachi, another, oregairu, + saikiK, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/saiki-k.json b/src/data/mappings/saiki-k.json new file mode 100644 index 0000000..e7ac9e5 --- /dev/null +++ b/src/data/mappings/saiki-k.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 21804, + "anilistMangaId": 67755, + "title": "The Disastrous Life of Saiki K.", + "sourceNotes": "Cumulative episodes across S1 (24) + S2 (24, eps 25-48) + the Netflix ONA 'Reawakened' (6, eps 49-54) = 54 total. AniList lists Season 1 (id 21804) as 120 short-form segments; this mapping uses the standard 24-episode half-hour edit. Shuichi Aso's gag manga is complete at 281 chapters (plus 2 epilogue chapters) / 26 vols (AniList counts 290, including extras). Because the series is an episodic gag comedy, each ~22-min episode adapts several short chapters and the seasons do not follow strict chapter order — 'Reawakened' in particular backfills previously skipped chapters and animates the finale plus the two epilogue chapters. Chapter boundaries are therefore coarse approximations.", + "mappings": [ + { + "episodes": [1, 24], + "chapters": [1, 130], + "arc": "Season 1 — Saiki's daily psychic disasters (assorted early chapters)" + }, + { + "episodes": [25, 48], + "chapters": [131, 245], + "arc": "Season 2 — continued misadventures" + }, + { + "episodes": [49, 54], + "chapters": [246, 281], + "arc": "Reawakened — backfilled chapters, the finale & epilogues" + } + ] +} From 8262223623c37690f3519c1ad84599f356010e9b Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:31 -0400 Subject: [PATCH 30/46] KSN: add `hyouka.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: Classic Literature Club novels 1-4 (eps 1-22) + ongoing tail - anime `12189` → manga `71629` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/hyouka.json | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/hyouka.json diff --git a/src/data/index.ts b/src/data/index.ts index e6d8bd9..596e723 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -189,6 +189,7 @@ import danmachi from "@/data/mappings/danmachi.json"; import another from "@/data/mappings/another.json"; import oregairu from "@/data/mappings/oregairu.json"; import saikiK from "@/data/mappings/saiki-k.json"; +import hyouka from "@/data/mappings/hyouka.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -447,6 +448,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ another, oregairu, saikiK, + hyouka, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/hyouka.json b/src/data/mappings/hyouka.json new file mode 100644 index 0000000..6c5db3b --- /dev/null +++ b/src/data/mappings/hyouka.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 12189, + "anilistMangaId": 71629, + "title": "Hyouka", + "sourceNotes": "The 22-episode Kyoto Animation anime adapts the first four 'Classic Literature Club' novels by Honobu Yonezawa (Hyouka; The Credit Roll of the Fool; The Kudryavka Sequence; The Doll That Took a Detour) plus short stories. Paired with Task Ohna's ongoing manga adaptation (id 71629); per Wikipedia its first twelve tankobon volumes cover the same four novels as the anime (≈ chapters 1-50). The manga is still running (~66 ch across 16 vols, with a 17th vol in 2026) and has moved into novel 5 ('Approximating the Distance Between Two People'), which the anime did not cover. AniList lists no chapter count for this manga, so chapter numbers are estimated from the tankobon volumes; per-arc boundaries are approximate while the anime endpoints (the four novels) are firm.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 12], + "arc": "Novel 1: Hyouka — reviving the Classics Club & the Sekitani Jun mystery" + }, + { + "episodes": [6, 11], + "chapters": [13, 25], + "arc": "Novel 2: The Credit Roll of the Fool — the student-film murder mystery" + }, + { + "episodes": [12, 17], + "chapters": [26, 38], + "arc": "Novel 3: The Kudryavka Sequence — the Kanya Festival & Juumonji thefts" + }, + { + "episodes": [18, 22], + "chapters": [39, 50], + "arc": "Novel 4: The Doll That Took a Detour — short stories & the Hina doll festival" + }, + { + "chapters": [51, 66], + "arc": "Novel 5: Approximating the Distance Between Two People (manga-only, ongoing)" + } + ] +} From 41008f2c1c720f165a94eaac012ef214605939ea Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:31 -0400 Subject: [PATCH 31/46] KSN: add `misfit-of-demon-king-academy.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: S1 episodes covered by the manga (cancelled at 16 ch); later seasons noted - anime `112301` → manga `106601` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/misfit-of-demon-king-academy.json | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/data/mappings/misfit-of-demon-king-academy.json diff --git a/src/data/index.ts b/src/data/index.ts index 596e723..4fd589c 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -190,6 +190,7 @@ import another from "@/data/mappings/another.json"; import oregairu from "@/data/mappings/oregairu.json"; import saikiK from "@/data/mappings/saiki-k.json"; import hyouka from "@/data/mappings/hyouka.json"; +import misfitOfDemonKingAcademy from "@/data/mappings/misfit-of-demon-king-academy.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -449,6 +450,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ oregairu, saikiK, hyouka, + misfitOfDemonKingAcademy, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/misfit-of-demon-king-academy.json b/src/data/mappings/misfit-of-demon-king-academy.json new file mode 100644 index 0000000..80c9bad --- /dev/null +++ b/src/data/mappings/misfit-of-demon-king-academy.json @@ -0,0 +1,18 @@ +{ + "anilistAnimeId": 112301, + "anilistMangaId": 106601, + "title": "The Misfit of Demon King Academy", + "sourceNotes": "Cumulative episodes across S1 (13, eps 1-13) + S2 'II' Cour 1 (12, eps 14-25) + S2 'II' Cour 2 (12, eps 26-37) = 37 total. Source is the Shu light novel; the anime adapts roughly LN volumes 1-6 (S1 = vols 1-3, S2 Cour 1 = vol 4, S2 Cour 2 = vols 5-6). The Kayaharuka manga adaptation was CANCELLED at 16 chapters / 4 volumes when the artist died (July 2021); it reaches only ~anime episode 7 (LN vol 2, ending mid-duel in the Magic Sword Tournament). Episodes 8-37 (Hero Academy / Spirit-Human Exchange, Great Spirit, and Selection Judgment arcs; LN vols 3-6) have no manga coverage and must be continued in the light novel. Mapped entries cover only the manga's actual extent. No films.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 11], + "arc": "Demon King Academy / Resurrection (LN vol 1)" + }, + { + "episodes": [6, 7], + "chapters": [12, 16], + "arc": "Magic Sword Tournament (LN vol 2; manga ends mid-arc)" + } + ] +} From b3c04ae422556debe57df1c8ea8301db6a5ec924 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:32 -0400 Subject: [PATCH 32/46] KSN: add `golden-time.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: full 24-ep adaptation across the complete 52-chapter manga - anime `17895` → manga `66873` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/golden-time.json | 33 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/golden-time.json diff --git a/src/data/index.ts b/src/data/index.ts index 4fd589c..d503cd7 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -191,6 +191,7 @@ import oregairu from "@/data/mappings/oregairu.json"; import saikiK from "@/data/mappings/saiki-k.json"; import hyouka from "@/data/mappings/hyouka.json"; import misfitOfDemonKingAcademy from "@/data/mappings/misfit-of-demon-king-academy.json"; +import goldenTime from "@/data/mappings/golden-time.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -451,6 +452,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ saikiK, hyouka, misfitOfDemonKingAcademy, + goldenTime, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/golden-time.json b/src/data/mappings/golden-time.json new file mode 100644 index 0000000..47f1c3f --- /dev/null +++ b/src/data/mappings/golden-time.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 17895, + "anilistMangaId": 66873, + "title": "Golden Time", + "sourceNotes": "Single 24-episode 2013-2014 anime. Paired with the Umechazuke manga adaptation (complete, 52 ch across 9 volumes), which adapts the full Yuyuko Takemiya light novel (8 vols) from beginning to ending. Both cover the same story, though the manga follows the light novel's ending more faithfully than the anime's eps 22-24. No per-chapter concordance exists for this continuous college romance, so chapter boundaries are proportional estimates anchored to the LN-volume structure.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 9], + "arc": "Freshman Start (college entrance / meeting Koko, Mitsuo, Linda)" + }, + { + "episodes": [5, 7], + "chapters": [10, 16], + "arc": "Becoming a Couple (ghost-Banri / Banri and Koko get together)" + }, + { + "episodes": [8, 13], + "chapters": [17, 28], + "arc": "Festival Club & Summer" + }, + { + "episodes": [14, 19], + "chapters": [29, 41], + "arc": "Linda's Past & Resurfacing Memories" + }, + { + "episodes": [20, 24], + "chapters": [42, 52], + "arc": "Climax & Resolution" + } + ] +} From 8007b892e2fae5098867210017bdc01128f1e40f Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:32 -0400 Subject: [PATCH 33/46] KSN: add `my-little-monster.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: ch 1-16 (vols 1-4) adapted + unadapted tail - anime `14227` → manga `43702` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/my-little-monster.json | 31 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/data/mappings/my-little-monster.json diff --git a/src/data/index.ts b/src/data/index.ts index d503cd7..74a00d8 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -192,6 +192,7 @@ import saikiK from "@/data/mappings/saiki-k.json"; import hyouka from "@/data/mappings/hyouka.json"; import misfitOfDemonKingAcademy from "@/data/mappings/misfit-of-demon-king-academy.json"; import goldenTime from "@/data/mappings/golden-time.json"; +import myLittleMonster from "@/data/mappings/my-little-monster.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -453,6 +454,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ hyouka, misfitOfDemonKingAcademy, goldenTime, + myLittleMonster, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/my-little-monster.json b/src/data/mappings/my-little-monster.json new file mode 100644 index 0000000..742b693 --- /dev/null +++ b/src/data/mappings/my-little-monster.json @@ -0,0 +1,31 @@ +{ + "anilistAnimeId": 14227, + "anilistMangaId": 43702, + "title": "My Little Monster", + "sourceNotes": "13-episode 2012 anime. Episodes 1-12 adapt manga chapters 1-16 (volumes 1-4) closely, with episode titles matching chapter titles; episode 13 ('Spring Is Near') is anime-original filler with no manga equivalent. The Robico manga is complete: 48 main numbered chapters (vols 1-12, ending 'Graduation Ceremony') plus 4 bonus/epilogue chapters in volume 13 (ch 49-52, 'Never Ending'). AniList's 69 count is all-inclusive (also counting split/half chapters, omake and fan-book extras); the chapter ranges here use the numbered-chapter axis. The 2013 'Tonari no Gokudou-kun' is an OVA (not theatrical) and the 2018 live-action film is a separate continuity, so there are no film entries.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 4], + "arc": "Haru & Shizuku Begin (Vol 1)" + }, + { + "episodes": [4, 6], + "chapters": [5, 8], + "arc": "The Friend Group Forms - Natsume & Sasayan (Vol 2)" + }, + { + "episodes": [7, 12], + "chapters": [9, 16], + "arc": "Love Triangle, Shoyo Festival & Christmas (Vols 3-4)" + }, + { + "chapters": [17, 48], + "arc": "Post-anime main story: dating, final-year arcs & Graduation (unadapted)" + }, + { + "chapters": [49, 52], + "arc": "Volume 13 bonus/epilogue chapters (unadapted)" + } + ] +} From 9e45fdf2a90c2600a6f6225072363d00963d2232 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:32 -0400 Subject: [PATCH 34/46] KSN: add `irregular-at-magic-high-school.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs: S1-S3 (eps 1-52); mapped to LN volumes; The Girl Who Summons the Stars film - 1 movie: The Irregular at Magic High School: The Movie - The Girl Who Summons the Stars - anime `20458` → manga `64127` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../irregular-at-magic-high-school.json | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/data/mappings/irregular-at-magic-high-school.json diff --git a/src/data/index.ts b/src/data/index.ts index 74a00d8..e80c991 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -193,6 +193,7 @@ import hyouka from "@/data/mappings/hyouka.json"; import misfitOfDemonKingAcademy from "@/data/mappings/misfit-of-demon-king-academy.json"; import goldenTime from "@/data/mappings/golden-time.json"; import myLittleMonster from "@/data/mappings/my-little-monster.json"; +import irregularAtMagicHighSchool from "@/data/mappings/irregular-at-magic-high-school.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -455,6 +456,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ misfitOfDemonKingAcademy, goldenTime, myLittleMonster, + irregularAtMagicHighSchool, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/irregular-at-magic-high-school.json b/src/data/mappings/irregular-at-magic-high-school.json new file mode 100644 index 0000000..46b8fd6 --- /dev/null +++ b/src/data/mappings/irregular-at-magic-high-school.json @@ -0,0 +1,56 @@ +{ + "anilistAnimeId": 20458, + "anilistMangaId": 64127, + "title": "The Irregular at Magic High School", + "sourceNotes": "Cumulative episodes across S1 (26) + S2 'Visitor Arc' (13, eps 27-39) + S3 (13, eps 40-52) = 52 total. The manga adaptation is fragmented into many separate per-arc manga (Enrollment, Nine School Competition, Yokohama Disturbance, Visitor, Double Seven, Steeplechase, etc.) with no single unified entry, so this maps to the Tsutomu Sato light novel (32 main volumes, complete) and the 'chapters' ranges below are LIGHT-NOVEL VOLUME numbers. S1 adapts vols 1-4 and 6-7 (vol 5, a short-story interstitial, is skipped); S2 adapts vols 9-11; S3 adapts vols 12-15. LN vols 16-32 (Yotsuba Succession through Graduation) are unadapted. Vol 8 (Reminiscence) was adapted separately as the 2021 TV special, not the main series.", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 2], + "arc": "Enrollment Arc (S1)" + }, + { + "episodes": [8, 18], + "chapters": [3, 4], + "arc": "Nine School Competition Arc (S1)" + }, + { + "episodes": [19, 26], + "chapters": [6, 7], + "arc": "Yokohama Disturbance Arc (S1)" + }, + { + "episodes": [27, 39], + "chapters": [9, 11], + "arc": "Visitor Arc (S2)" + }, + { + "episodes": [40, 43], + "chapters": [12, 12], + "arc": "Double Seven Arc (S3)" + }, + { + "episodes": [44, 47], + "chapters": [13, 13], + "arc": "Steeplechase Arc (S3)" + }, + { + "episodes": [48, 52], + "chapters": [14, 15], + "arc": "Ancient City Insurrection (Koto Nairan) Arc (S3)" + }, + { + "chapters": [16, 32], + "arc": "Yotsuba Succession -> Master Clans Council -> Graduation (unadapted)" + } + ], + "movies": [ + { + "anilistId": 21684, + "title": "The Irregular at Magic High School: The Movie - The Girl Who Summons the Stars", + "year": 2017, + "afterEpisode": 39, + "note": "Canon original side-story film written by Tsutomu Sato, set after LN vol 11 (the Visitor Arc). Released June 2017, between S1 and S2 in broadcast order." + } + ] +} From d8ca6dc80831b3540e233a60a1f33c593b235099 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:33 -0400 Subject: [PATCH 35/46] KSN: add `relife.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: TV + 2018 OVA finale across the complete manga - anime `21049` → manga `85849` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/relife.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/relife.json diff --git a/src/data/index.ts b/src/data/index.ts index e80c991..b951117 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -194,6 +194,7 @@ import misfitOfDemonKingAcademy from "@/data/mappings/misfit-of-demon-king-acade import goldenTime from "@/data/mappings/golden-time.json"; import myLittleMonster from "@/data/mappings/my-little-monster.json"; import irregularAtMagicHighSchool from "@/data/mappings/irregular-at-magic-high-school.json"; +import relife from "@/data/mappings/relife.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -457,6 +458,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ goldenTime, myLittleMonster, irregularAtMagicHighSchool, + relife, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/relife.json b/src/data/mappings/relife.json new file mode 100644 index 0000000..68b174b --- /dev/null +++ b/src/data/mappings/relife.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 21049, + "anilistMangaId": 85849, + "title": "ReLIFE", + "sourceNotes": "Cumulative episodes across the 2016 ONA series (13) + the 2018 OVA finale 'Kanketsu-hen / Final Arc' (4, eps 14-17) = 17 total, one continuous story. Manga complete: 222 numbered chapters ('Reports') by Yayoiso; AniList's 238 count includes the volume 15 epilogue and bonus chapters. The TV/ONA series ends at roughly chapter 108 (the school-festival 'Confession'); the four-episode OVA compresses the entire remainder (ch 109 to the ending). The internal eps 7/8 chapter split is approximate. No theatrical anime film exists (the 2017 live-action film is a separate continuity).", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 70], + "arc": "First Semester & Midterm Exams (the experiment begins)" + }, + { + "episodes": [8, 13], + "chapters": [71, 108], + "arc": "Volleyball Tournament, Summer & School Festival" + }, + { + "episodes": [14, 17], + "chapters": [109, 238], + "arc": "Final Arc (OVA): Second Semester, Hishiro Resolution, Graduation & Finale" + } + ] +} From 2b2da06a765066fb2b0c98690ec292024e41c686 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:33 -0400 Subject: [PATCH 36/46] KSN: add `orange.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: full 13-ep main story (Letters 1-22) + side-story tail - 1 movie: Orange: Future - anime `21647` → manga `65573` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/orange.json | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/orange.json diff --git a/src/data/index.ts b/src/data/index.ts index b951117..13b1ebf 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -195,6 +195,7 @@ import goldenTime from "@/data/mappings/golden-time.json"; import myLittleMonster from "@/data/mappings/my-little-monster.json"; import irregularAtMagicHighSchool from "@/data/mappings/irregular-at-magic-high-school.json"; import relife from "@/data/mappings/relife.json"; +import orange from "@/data/mappings/orange.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -459,6 +460,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ myLittleMonster, irregularAtMagicHighSchool, relife, + orange, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/orange.json b/src/data/mappings/orange.json new file mode 100644 index 0000000..b8fccd1 --- /dev/null +++ b/src/data/mappings/orange.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 21647, + "anilistMangaId": 65573, + "title": "Orange", + "sourceNotes": "13-episode 2016 TV anime; every episode is titled 'LETTER 01'-'LETTER 13', mirroring the manga's 'Letter' chapters. The anime adapts the COMPLETE main story: Letters 1-22 across volumes 1-5 (Ichigo Takano). AniList id 65573 lists 39 chapters spanning all 7 volumes; the material past Letter 22 (chapters 23-39, vols 6-7) is post-series side-story content NOT covered by the TV series — vol 6 'orange -future-' (Suwa's POV, ~ch 23-26, which the film adapts) and vol 7 'to you, dear one' POV shorts (~ch 27-33 + bonuses). Volume/Letter boundaries are high-confidence; exact episode cut-points within the main story are approximate (the relay race is ep 10, ch 19 falls in ep 12).", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 8], + "arc": "Receiving the letters / meeting Kakeru (vols 1-2)" + }, + { + "episodes": [6, 10], + "chapters": [9, 16], + "arc": "Growing closer / the athletic festival relay (vols 3-4)" + }, + { + "episodes": [11, 13], + "chapters": [17, 22], + "arc": "Saving Kakeru / the future timeline & ending (vol 5)" + }, + { + "chapters": [23, 39], + "arc": "Side stories: 'orange -future-' (Suwa's POV, vol 6) & 'to you, dear one' POV shorts (vol 7) — unadapted by the TV series" + } + ], + "movies": [ + { + "anilistId": 97669, + "title": "Orange: Future", + "year": 2016, + "chapters": [23, 26], + "afterEpisode": 13, + "note": "Sequel film: retells the story from Hiroto Suwa's POV and adds new Ichigo Takano content set after the series (vol 6 'orange -future-'). Recap layer plus genuinely new post-series footage." + } + ] +} From ed5ed5f06c4307920072741cd5ddf0d4ca022ad8 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:34 -0400 Subject: [PATCH 37/46] KSN: add `blood-blockade-battlefront.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs: S1 + S2 '& Beyond' (eps 1-24) - anime `20727` → manga `42994` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/blood-blockade-battlefront.json | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/data/mappings/blood-blockade-battlefront.json diff --git a/src/data/index.ts b/src/data/index.ts index 13b1ebf..b4b550b 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -196,6 +196,7 @@ import myLittleMonster from "@/data/mappings/my-little-monster.json"; import irregularAtMagicHighSchool from "@/data/mappings/irregular-at-magic-high-school.json"; import relife from "@/data/mappings/relife.json"; import orange from "@/data/mappings/orange.json"; +import bloodBlockadeBattlefront from "@/data/mappings/blood-blockade-battlefront.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -461,6 +462,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ irregularAtMagicHighSchool, relife, orange, + bloodBlockadeBattlefront, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/blood-blockade-battlefront.json b/src/data/mappings/blood-blockade-battlefront.json new file mode 100644 index 0000000..99bca2e --- /dev/null +++ b/src/data/mappings/blood-blockade-battlefront.json @@ -0,0 +1,18 @@ +{ + "anilistAnimeId": 20727, + "anilistMangaId": 42994, + "title": "Blood Blockade Battlefront", + "sourceNotes": "Cumulative episodes across S1 'Blood Blockade Battlefront' (12) + S2 'Kekkai Sensen & Beyond' (12, eps 13-24) = 24 total. Paired with Yasuhiro Nightow's original manga (AniList id 42994), complete at 10 volumes (AniList lists 33 chapters, including .5 interstitials; Wikipedia counts 30 numbered chapters). The anime adapts the episodic manga NON-LINEARLY and wraps it in heavy anime-original framing (the Black & White twins, Femt, and the Blood Breed / King of Despair throughline of the S1 finale are largely anime-original); per-arc chapter boundaries are therefore approximate. S2 is more faithful and ends on the manga's actual finale, 'Spectral Eyes, Phantom Vision' (vol 10).", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 14], + "arc": "Season 1 (Libra / Leonardo & the All-Seeing Eyes) — manga vols 1-6, non-linear + anime-original" + }, + { + "episodes": [13, 24], + "chapters": [15, 33], + "arc": "Season 2 '& Beyond' (vols 6-10) incl. 'Spectral Eyes, Phantom Vision' finale" + } + ] +} From dafc0d2c699580b9ec06b196b66917d80452d3cc Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:34 -0400 Subject: [PATCH 38/46] KSN: add `arifureta.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: S1-S3 (eps 1-41); mapped to LN volumes 1-10 + unadapted tail - anime `100668` → manga `96834` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/arifureta.json | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/arifureta.json diff --git a/src/data/index.ts b/src/data/index.ts index b4b550b..41d7889 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -197,6 +197,7 @@ import irregularAtMagicHighSchool from "@/data/mappings/irregular-at-magic-high- import relife from "@/data/mappings/relife.json"; import orange from "@/data/mappings/orange.json"; import bloodBlockadeBattlefront from "@/data/mappings/blood-blockade-battlefront.json"; +import arifureta from "@/data/mappings/arifureta.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -463,6 +464,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ relife, orange, bloodBlockadeBattlefront, + arifureta, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/arifureta.json b/src/data/mappings/arifureta.json new file mode 100644 index 0000000..ee2df6e --- /dev/null +++ b/src/data/mappings/arifureta.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 100668, + "anilistMangaId": 96834, + "title": "Arifureta: From Commonplace to World's Strongest", + "sourceNotes": "Cumulative episodes across S1 (13) + S2 (12, eps 14-25) + S3 (16, eps 26-41) = 41 total (AniList numbering; Wikipedia/fandom insert a recap special and run +1 from S2E1 onward). The source is Ryo Shirakome's light novel. The RoGa manga adaptation (AniList id 96834) is the linked manga, but it lags FAR behind the anime — at ~ch 92 it has only reached LN vol. 6 (roughly the end of S2) and AniList lists no chapter count — so this mapping uses LIGHT-NOVEL VOLUME numbers as the 'chapters' unit instead. The main LN ran 13 volumes (concluded 2022) plus a vol. 14 epilogue; the anime adapts vols. 1-10. Per-volume arc boundaries within each season are approximate. No theatrical films.", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 4], + "arc": "S1: Great Orcus Labyrinth (the Abyss) / Reisen Gorge / Grun Desert / Heiligh Kingdom defense (LN vols 1-4)" + }, + { + "episodes": [14, 25], + "chapters": [5, 6], + "arc": "S2: next labyrinth / Divine Mountain (Noint, Eri's betrayal, Kaori's death & resurrection) (LN vols 5-6)" + }, + { + "episodes": [26, 41], + "chapters": [7, 10], + "arc": "S3: Hoelscher Empire / Haltina Woods (Sea of Trees) / Frost Caverns — the seven labyrinths conquered (LN vols 7-10)" + }, + { + "chapters": [11, 14], + "arc": "March on the Demon Lord's castle & finale + epilogue (LN vols 11-14), unadapted" + } + ] +} From 8e0d274beb5fb52190733bf439fa3a6697518364 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:34 -0400 Subject: [PATCH 39/46] KSN: add `nozaki-kun.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: 12-ep adaptation (~ch 1-38) + ongoing tail (approximate, 4-koma) - anime `20668` → manga `59211` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/nozaki-kun.json | 32 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/nozaki-kun.json diff --git a/src/data/index.ts b/src/data/index.ts index 41d7889..c4b2901 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -198,6 +198,7 @@ import relife from "@/data/mappings/relife.json"; import orange from "@/data/mappings/orange.json"; import bloodBlockadeBattlefront from "@/data/mappings/blood-blockade-battlefront.json"; import arifureta from "@/data/mappings/arifureta.json"; +import nozakiKun from "@/data/mappings/nozaki-kun.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -465,6 +466,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ orange, bloodBlockadeBattlefront, arifureta, + nozakiKun, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/nozaki-kun.json b/src/data/mappings/nozaki-kun.json new file mode 100644 index 0000000..bd276cd --- /dev/null +++ b/src/data/mappings/nozaki-kun.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 20668, + "anilistMangaId": 59211, + "title": "Monthly Girls' Nozaki-kun", + "sourceNotes": "12-episode 2014 TV anime (Doga Kobo). The source is an ongoing 4-koma (yonkoma) gag manga by Izumi Tsubaki; AniList lists no chapter count, and the anime adapts strips NON-SEQUENTIALLY, so every chapter boundary below is APPROXIMATE (the 4-koma runs ~10 chapters per volume, and 5 volumes existed when the anime aired in 2014). The TV series draws from roughly chapters 1-38 (vols 1-4), sampling material out of order; the 6 home-video specials reach ~ch 48. The manga continues well past the anime (~17 volumes / ~160 chapters as of 2025); that later material is unadapted.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 10], + "arc": "Sakura & Nozaki / Mikoshiba introduced (approx.)" + }, + { + "episodes": [3, 5], + "chapters": [11, 20], + "arc": "Kashima & Hori introduced (approx.)" + }, + { + "episodes": [6, 9], + "chapters": [21, 32], + "arc": "Seo & Wakamatsu (approx.)" + }, + { + "episodes": [10, 12], + "chapters": [33, 38], + "arc": "Ensemble / culture-festival finale (approx.)" + }, + { + "chapters": [39, 160], + "arc": "Ongoing serialization, unadapted (~vols 5-17)" + } + ] +} From 1348b99123e0005a91c41e77fc840e4f7398fd99 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:35 -0400 Subject: [PATCH 40/46] KSN: add `delicious-in-dungeon.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs: S1 (eps 1-24, ch 1-52) + unadapted tail (manga complete, 97 ch) - anime `153518` → manga `86082` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/delicious-in-dungeon.json | 48 +++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/data/mappings/delicious-in-dungeon.json diff --git a/src/data/index.ts b/src/data/index.ts index c4b2901..5460280 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -199,6 +199,7 @@ import orange from "@/data/mappings/orange.json"; import bloodBlockadeBattlefront from "@/data/mappings/blood-blockade-battlefront.json"; import arifureta from "@/data/mappings/arifureta.json"; import nozakiKun from "@/data/mappings/nozaki-kun.json"; +import deliciousInDungeon from "@/data/mappings/delicious-in-dungeon.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -467,6 +468,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ bloodBlockadeBattlefront, arifureta, nozakiKun, + deliciousInDungeon, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/delicious-in-dungeon.json b/src/data/mappings/delicious-in-dungeon.json new file mode 100644 index 0000000..d265dde --- /dev/null +++ b/src/data/mappings/delicious-in-dungeon.json @@ -0,0 +1,48 @@ +{ + "anilistAnimeId": 153518, + "anilistMangaId": 86082, + "title": "Delicious in Dungeon", + "sourceNotes": "24-episode Season 1 (2024, Trigger) adapts manga chapters 1-52, with ep 24 ending on ch 52 'Bacon and Eggs' (end of the Sixth Floor arc); new readers continue at ch 53. Ryoko Kui's manga is COMPLETE at 97 numbered chapters across 14 volumes. AniList id 86082 lists 111 chapters = the 97 numbered chapters + 14 per-volume bonus/omake side stories; this mapping uses the numbered count, so the unadapted Season 2+ tail extends to ch 97. The anime lightly reorders the manga's non-linear chapters, so a few episode boundaries (e.g. ep 14) blend adjacent floors; the ranges below reflect the dominant mapping. No theatrical films.", + "mappings": [ + { + "episodes": [1, 10], + "chapters": [1, 22], + "arc": "Upper floors: entering the dungeon to rescue Falin, learning to eat monsters (floors 1-4)" + }, + { + "episodes": [11, 13], + "chapters": [23, 30], + "arc": "Red Dragon & Falin's resurrection (Marcille's forbidden magic)" + }, + { + "episodes": [14, 17], + "chapters": [31, 38], + "arc": "Fifth Floor — Falin retaken and turned into the Chimera" + }, + { + "episodes": [18, 24], + "chapters": [39, 52], + "arc": "Sixth Floor — changelings & the cursed Golden Country" + }, + { + "chapters": [53, 62], + "arc": "Dwarf City Ruins — the Winged Lion (the Demon) appears (unadapted)" + }, + { + "chapters": [63, 72], + "arc": "Lunatic Magician (Thistle) (unadapted)" + }, + { + "chapters": [73, 85], + "arc": "New Dungeon Lord (unadapted)" + }, + { + "chapters": [86, 91], + "arc": "Winged Lion / Demon climax (unadapted)" + }, + { + "chapters": [92, 97], + "arc": "Falin & finale (unadapted)" + } + ] +} From 611d775ecf045e19bcad6f4f759be0cf832d9a0f Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:29:35 -0400 Subject: [PATCH 41/46] KSN: add `summer-time-rendering.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs: full 25-ep 1:1 adaptation across the complete 139-chapter manga - anime `129201` → manga `102989` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/summer-time-rendering.json | 38 ++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/data/mappings/summer-time-rendering.json diff --git a/src/data/index.ts b/src/data/index.ts index 5460280..04a4132 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -200,6 +200,7 @@ import bloodBlockadeBattlefront from "@/data/mappings/blood-blockade-battlefront import arifureta from "@/data/mappings/arifureta.json"; import nozakiKun from "@/data/mappings/nozaki-kun.json"; import deliciousInDungeon from "@/data/mappings/delicious-in-dungeon.json"; +import summerTimeRendering from "@/data/mappings/summer-time-rendering.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -469,6 +470,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ arifureta, nozakiKun, deliciousInDungeon, + summerTimeRendering, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/summer-time-rendering.json b/src/data/mappings/summer-time-rendering.json new file mode 100644 index 0000000..eae33ff --- /dev/null +++ b/src/data/mappings/summer-time-rendering.json @@ -0,0 +1,38 @@ +{ + "anilistAnimeId": 129201, + "anilistMangaId": 102989, + "title": "Summer Time Rendering", + "sourceNotes": "The 25-episode 2022 TV anime (OLM) is a full 1:1 adaptation of Yasuki Tanaka's COMPLETE manga: 139 chapters across 13 volumes (Shonen Jump+, 2017-2021). Episode 25 'I'm Home' ends on the manga's final chapter, 139. Cadence is ~5-6 chapters per episode; the arc boundaries below are aligned to verified per-episode chapter anchors (ep 5 ends ch 20, ep 9 ends ch 47, ep 13 ends ch 68, ep 18 ends ch 99, ep 22 ends ch 125, ep 25 ends ch 139), so the cumulative ranges are exact. No theatrical films.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 20], + "arc": "Return to Hitogashima / first loops (the funeral, the Shadow phenomenon, early deaths)" + }, + { + "episodes": [6, 9], + "chapters": [21, 47], + "arc": "The Shadow hunt (alliance with Hizuru & Ginjiro, Shadow rules uncovered, Shadow Ushio)" + }, + { + "episodes": [10, 13], + "chapters": [48, 68], + "arc": "The Hishigata Clinic (Ushio's death, the Hiruko statue / bunker, Kobayakawa raids)" + }, + { + "episodes": [14, 18], + "chapters": [69, 99], + "arc": "The Haine / Shide reveal (origin of the Shadows, Masahito unmasked as Shide)" + }, + { + "episodes": [19, 22], + "chapters": [100, 125], + "arc": "Time-loop escalation (Shadow Shinpei, Ushio's resurrection as the observer)" + }, + { + "episodes": [23, 25], + "chapters": [126, 139], + "arc": "The final confrontation (decisive battle vs. the immortal Shide; resolution)" + } + ] +} From 46553b863899206aeb337b7c9e230d3ca6db62be Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:31:15 -0400 Subject: [PATCH 42/46] KSN: add `kimi-ni-todoke.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs: S1 + S2 + S3 (eps 1-42) across the complete manga - anime `6045` → manga `33378` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/kimi-ni-todoke.json | 32 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/kimi-ni-todoke.json diff --git a/src/data/index.ts b/src/data/index.ts index 04a4132..31f71b3 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -201,6 +201,7 @@ import arifureta from "@/data/mappings/arifureta.json"; import nozakiKun from "@/data/mappings/nozaki-kun.json"; import deliciousInDungeon from "@/data/mappings/delicious-in-dungeon.json"; import summerTimeRendering from "@/data/mappings/summer-time-rendering.json"; +import kimiNiTodoke from "@/data/mappings/kimi-ni-todoke.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -471,6 +472,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ nozakiKun, deliciousInDungeon, summerTimeRendering, + kimiNiTodoke, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kimi-ni-todoke.json b/src/data/mappings/kimi-ni-todoke.json new file mode 100644 index 0000000..013feae --- /dev/null +++ b/src/data/mappings/kimi-ni-todoke.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 6045, + "anilistMangaId": 33378, + "title": "Kimi ni Todoke: From Me to You", + "sourceNotes": "Cumulative episodes across S1 (25) + S2 (12, eps 26-37) + S3 (Netflix ONA, 5 eps, eps 38-42) = 42 total. (AniList lists S2 at 13 eps incl. a recap; the broadcast/streaming season is 12.) Paired with Karuho Shiina's complete manga: 123 numbered story chapters across 30 volumes; AniList counts 127 incl. ~4 bonus/omake chapters, so the tail extends to 127. Season-end boundaries (ch 27 / 46 / 75) corroborated across episode-to-chapter guides; the internal S1 split is approximate.", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 7], + "arc": "Becoming Friends (Sawako, Ayane & Chizuru)" + }, + { + "episodes": [8, 25], + "chapters": [8, 27], + "arc": "Kurumi Rivalry → New Year (S1)" + }, + { + "episodes": [26, 37], + "chapters": [28, 46], + "arc": "Valentine's & Confession (S2)" + }, + { + "episodes": [38, 42], + "chapters": [47, 75], + "arc": "New Couple / School Trip / First Kiss (S3)" + }, + { + "chapters": [76, 127], + "arc": "Third Year & Graduation (unadapted tail; ch 124-127 are bonus chapters)" + } + ] +} From 3178781f97982bc270f3f792bb198dbdb4bb4642 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:31:15 -0400 Subject: [PATCH 43/46] KSN: add `prison-school.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs: 12-ep adaptation (ch 1-82) + unadapted tail (manga complete) - anime `20807` → manga `55297` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/prison-school.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/prison-school.json diff --git a/src/data/index.ts b/src/data/index.ts index 31f71b3..1044d5a 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -202,6 +202,7 @@ import nozakiKun from "@/data/mappings/nozaki-kun.json"; import deliciousInDungeon from "@/data/mappings/delicious-in-dungeon.json"; import summerTimeRendering from "@/data/mappings/summer-time-rendering.json"; import kimiNiTodoke from "@/data/mappings/kimi-ni-todoke.json"; +import prisonSchool from "@/data/mappings/prison-school.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -473,6 +474,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ deliciousInDungeon, summerTimeRendering, kimiNiTodoke, + prisonSchool, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/prison-school.json b/src/data/mappings/prison-school.json new file mode 100644 index 0000000..ec3985a --- /dev/null +++ b/src/data/mappings/prison-school.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 20807, + "anilistMangaId": 55297, + "title": "Prison School", + "sourceNotes": "S1 anime (12 eps, 2015) adapts manga chapters 1-82 (partway into the DTO arc; resume reading at ch 83). Paired with Akira Hiramoto's complete manga: the story ends at ch 277 with a ch 277.5 epilogue (28 vols); AniList counts 279 because it lists the '.5' interstitial half-chapters separately, so the final arc extends to 279. The 'Mad Wax' OVA (re-covers ch 82-89) and the live-action drama are excluded. Saga-level boundaries follow the fandom Story Arcs list; the ASSA/DTO sub-split is approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 82], + "arc": "Underground Student Council Saga (Peeping → ASSA → DTO; anime portion)" + }, + { + "chapters": [83, 165], + "arc": "DTO Finale → Aboveground Student Council Saga" + }, + { "chapters": [166, 241], "arc": "Sports Festival Saga" }, + { + "chapters": [242, 279], + "arc": "Tanabata Saga (Yakiniku Party & Epilogue)" + } + ] +} From 7f5e8096edcc2b023b18c43470d20afb99230ed9 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:31:15 -0400 Subject: [PATCH 44/46] KSN: add `date-a-live.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs: S1-S5 (LN vols 1-19); mapped to the light novel; Mayuri Judgment film - 1 movie: Date A Live: Mayuri Judgment - anime `15583` → manga `67523` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/date-a-live.json | 46 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/data/mappings/date-a-live.json diff --git a/src/data/index.ts b/src/data/index.ts index 1044d5a..8f33348 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -203,6 +203,7 @@ import deliciousInDungeon from "@/data/mappings/delicious-in-dungeon.json"; import summerTimeRendering from "@/data/mappings/summer-time-rendering.json"; import kimiNiTodoke from "@/data/mappings/kimi-ni-todoke.json"; import prisonSchool from "@/data/mappings/prison-school.json"; +import dateALive from "@/data/mappings/date-a-live.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -475,6 +476,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ summerTimeRendering, kimiNiTodoke, prisonSchool, + dateALive, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/date-a-live.json b/src/data/mappings/date-a-live.json new file mode 100644 index 0000000..bee8e7c --- /dev/null +++ b/src/data/mappings/date-a-live.json @@ -0,0 +1,46 @@ +{ + "anilistAnimeId": 15583, + "anilistMangaId": 67523, + "title": "Date A Live", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 (10, eps 13-22) + S3 (12, eps 23-34) + S4 (12, eps 35-46) + S5 (12, eps 47-58) = 58 total. The Date A Live manga adaptation (id 67163) was discontinued in 2013 after ~6 chapters covering only the start of S1, so this maps to Koushi Tachibana's light novel instead (AniList id 67523, type MANGA, 146 chapters across 22 volumes). The anime adapts LN vols 1-19 by season — S1 vols 1-4, S2 vols 5-7, S3 vols 8-12, S4 vols 13-16, S5 vols 17-19 — leaving vols 20-22 (the Tohka finale) unadapted. Chapter ranges are proportional estimates converting those volume boundaries onto AniList's 146-chapter count, so they are approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 27], + "arc": "Tohka / Yoshino / Kurumi / Kotori (S1, LN vols 1-4)" + }, + { + "episodes": [13, 22], + "chapters": [28, 46], + "arc": "Yamai Twins / Miku (S2, LN vols 5-7)" + }, + { + "episodes": [23, 34], + "chapters": [47, 80], + "arc": "Natsumi / Origami (S3, LN vols 8-12)" + }, + { + "episodes": [35, 46], + "chapters": [81, 106], + "arc": "Nia / Mukuro (S4, LN vols 13-16)" + }, + { + "episodes": [47, 58], + "chapters": [107, 126], + "arc": "Kurumi Ragnarok / Mio Finale (S5, LN vols 17-19)" + }, + { + "chapters": [127, 146], + "arc": "Tohka World / Tohka Good End (LN vols 20-22, unadapted)" + } + ], + "movies": [ + { + "anilistId": 20741, + "title": "Date A Live: Mayuri Judgment", + "year": 2015, + "afterEpisode": 22, + "note": "Author-supervised original film (not from the light novel) introducing the spirit Mayuri; set after S2." + } + ] +} From 45150fd9144c0a17262a59cb4ec4dd803d501c78 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:31:16 -0400 Subject: [PATCH 45/46] KSN: add `ao-haru-ride.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: near 1:1 adaptation (ch 1-13) + unadapted tail (manga complete) - anime `20596` → manga `54294` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/ao-haru-ride.json | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/data/mappings/ao-haru-ride.json diff --git a/src/data/index.ts b/src/data/index.ts index 8f33348..672b798 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -204,6 +204,7 @@ import summerTimeRendering from "@/data/mappings/summer-time-rendering.json"; import kimiNiTodoke from "@/data/mappings/kimi-ni-todoke.json"; import prisonSchool from "@/data/mappings/prison-school.json"; import dateALive from "@/data/mappings/date-a-live.json"; +import aoHaruRide from "@/data/mappings/ao-haru-ride.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -477,6 +478,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ kimiNiTodoke, prisonSchool, dateALive, + aoHaruRide, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/ao-haru-ride.json b/src/data/mappings/ao-haru-ride.json new file mode 100644 index 0000000..f878911 --- /dev/null +++ b/src/data/mappings/ao-haru-ride.json @@ -0,0 +1,15 @@ +{ + "anilistAnimeId": 20596, + "anilistMangaId": 54294, + "title": "Blue Spring Ride", + "sourceNotes": "S1 anime (12 eps, 2014) is a near chapter-per-episode adaptation covering roughly the first four volumes; the two OVAs ('unwritten' = the PAGE.0 prologue, and 'PAGE.13') extend it to about ch 13, so a viewer resumes reading around ch 14. Paired with Io Sakisaka's complete manga: 49 numbered story chapters across 13 volumes; AniList counts 53 incl. extras, so the final arc extends to 53. Post-anime arc boundaries are approximate. The 2014 live-action film is excluded.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 13], + "arc": "Reawakening: Futaba & Kou Reunite (Class 2-3 friend group; incl. OVAs)" + }, + { "chapters": [14, 32], "arc": "Kou's Past & the Love Rivals" }, + { "chapters": [33, 53], "arc": "Touma Arc & Futaba's Choice (Final)" } + ] +} From 11ed589adf48ac9c59fe9f831c72f646275f48e9 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Mon, 29 Jun 2026 11:31:16 -0400 Subject: [PATCH 46/46] KSN: add `tonikawa.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs: S1 + S2 (ch 1-106) + ongoing tail - anime `116267` → manga `101177` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/tonikawa.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/tonikawa.json diff --git a/src/data/index.ts b/src/data/index.ts index 672b798..00a9bf5 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -205,6 +205,7 @@ import kimiNiTodoke from "@/data/mappings/kimi-ni-todoke.json"; import prisonSchool from "@/data/mappings/prison-school.json"; import dateALive from "@/data/mappings/date-a-live.json"; import aoHaruRide from "@/data/mappings/ao-haru-ride.json"; +import tonikawa from "@/data/mappings/tonikawa.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -479,6 +480,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ prisonSchool, dateALive, aoHaruRide, + tonikawa, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/tonikawa.json b/src/data/mappings/tonikawa.json new file mode 100644 index 0000000..49c9cfb --- /dev/null +++ b/src/data/mappings/tonikawa.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 116267, + "anilistMangaId": 101177, + "title": "TONIKAWA: Over The Moon For You", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 (12, eps 13-24) = 24 total. Paired with Kenjiro Hata's manga 'Fly Me to the Moon' (Tonikaku Kawaii), ongoing (~ch. 351 / 36 vols as of mid-2026 per MangaDex). S1 adapts ch 1-46; S2 adapts ch 47-106, so a viewer resumes reading at ch 107. This slice-of-life romance is episodic, so groupings are coarse and boundaries approximate. The SNS OVA, Uniform special, and High School Days ONA are separate side entries; there are no theatrical films.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 46], + "arc": "Newlywed Life (Marriage & Arisugawa Bathhouse)" + }, + { + "episodes": [13, 24], + "chapters": [47, 106], + "arc": "Family & School Life (incl. School Trip)" + }, + { + "chapters": [107, 351], + "arc": "Married Life Continues (ongoing, unadapted)" + } + ] +}