From 7e9aff1d4f579406e2ea98ea27acb499122b9db3 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:07 -0400 Subject: [PATCH 001/100] KSN: add `gun-gale-online-alternative.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–24 ↔ chapters 1–14 - anime `100183` → manga `100858` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../mappings/gun-gale-online-alternative.json | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/data/mappings/gun-gale-online-alternative.json diff --git a/src/data/index.ts b/src/data/index.ts index fc4f54b..6a52908 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -306,6 +306,7 @@ import highRiseInvasion from "@/data/mappings/high-rise-invasion.json"; import katanagatari from "@/data/mappings/katanagatari.json"; import worldGodOnlyKnows from "@/data/mappings/world-god-only-knows.json"; import recordOfRagnarok from "@/data/mappings/record-of-ragnarok.json"; +import gunGaleOnlineAlternative from "@/data/mappings/gun-gale-online-alternative.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -681,6 +682,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ katanagatari, worldGodOnlyKnows, recordOfRagnarok, + gunGaleOnlineAlternative, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/gun-gale-online-alternative.json b/src/data/mappings/gun-gale-online-alternative.json new file mode 100644 index 0000000..b66671c --- /dev/null +++ b/src/data/mappings/gun-gale-online-alternative.json @@ -0,0 +1,44 @@ +{ + "anilistAnimeId": 100183, + "anilistMangaId": 100858, + "title": "Sword Art Online Alternative: Gun Gale Online", + "sourceNotes": "LN-based spin-off; ranges are by light novel VOLUME (Keiichi Sigsawa's \"GGO Alternative\" novels, AniList id 100858, chapters null there), not chapter numbers — the community maps this series volume-to-episode. GGO Alternative is its own franchise, so episode numbering starts at S1E1 (the SAO II \"parent\" relation is franchise-level only). Cumulative episodes across S1 (12, studio 3Hz, 2018; a mid-season recap ep 5.5 is not counted) + S2 \"GGO Alternative II\" (12, A-1 Pictures, 2024) = 24. S1 adapts Vol 1-3 (First & Second Squad Jam); S2 adapts Vol 4-5 (Third Squad Jam, ~8 eps) plus Vol 6 \"One Summer Day / Test Play\" (~4 eps). Source novels ongoing at 14 volumes (Vol 14 \"Invitation from Vivi\", Oct 2024); Vol 7-14 remain unadapted.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 1], + "arc": "First Squad Jam" + }, + { + "episodes": [6, 12], + "chapters": [2, 3], + "arc": "Second Squad Jam" + }, + { + "episodes": [13, 20], + "chapters": [4, 5], + "arc": "Third Squad Jam (Betrayers' Choice)" + }, + { + "episodes": [21, 24], + "chapters": [6, 6], + "arc": "One Summer Day / Test Play" + }, + { + "chapters": [7, 9], + "arc": "Fourth Squad Jam" + }, + { + "chapters": [10, 10], + "arc": "Five Ordeals" + }, + { + "chapters": [11, 13], + "arc": "Fifth Squad Jam" + }, + { + "chapters": [14, 14], + "arc": "Invitation from Vivi" + } + ] +} From 6a4474fe73fce64c30d66eb0e1bcbed72e76db6e Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:10 -0400 Subject: [PATCH 002/100] KSN: add `a-certain-scientific-railgun.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–73 ↔ chapters 1–180 - anime `6213` → manga `37776` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../a-certain-scientific-railgun.json | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/data/mappings/a-certain-scientific-railgun.json diff --git a/src/data/index.ts b/src/data/index.ts index 6a52908..e62bbbc 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -307,6 +307,7 @@ import katanagatari from "@/data/mappings/katanagatari.json"; import worldGodOnlyKnows from "@/data/mappings/world-god-only-knows.json"; import recordOfRagnarok from "@/data/mappings/record-of-ragnarok.json"; import gunGaleOnlineAlternative from "@/data/mappings/gun-gale-online-alternative.json"; +import aCertainScientificRailgun from "@/data/mappings/a-certain-scientific-railgun.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -683,6 +684,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ worldGodOnlyKnows, recordOfRagnarok, gunGaleOnlineAlternative, + aCertainScientificRailgun, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/a-certain-scientific-railgun.json b/src/data/mappings/a-certain-scientific-railgun.json new file mode 100644 index 0000000..e5a1e2f --- /dev/null +++ b/src/data/mappings/a-certain-scientific-railgun.json @@ -0,0 +1,46 @@ +{ + "anilistAnimeId": 6213, + "anilistMangaId": 37776, + "title": "A Certain Scientific Railgun", + "sourceNotes": "Cumulative episodes across 3 TV seasons: Railgun S1 (24, 2009) + Railgun S (24, 2013) + Railgun T (25, 2020) = 73 eps. anilistMangaId 37776 is Kazuma Kamachi & Motoi Fuyukawa's Toaru Kagaku no Railgun manga (AniList lists 180 chapters; manga is actually still ongoing, ~180+ chapters / 20+ volumes as of 2025 — last entry extends to AniList's 180). Roughly half the anime is adaptation and half is anime-original: S1 adapts the Level Upper arc (eps 1-14) then invents the Poltergeist arc (eps 15-24, Big Spider woven in); Railgun S adapts the Sisters arc (eps 1-16) then invents the Silent Party arc (eps 17-24); Railgun T adapts the Daihaseisai/Daihasei Festival arc (eps 1-15) and the Dream Ranker arc (eps 16-25, covering the Indian Poker/Dream Ranker and Doppelganger/Kuriba Ryouko manga chapters with anime-original Scavenger/Kihara additions). Per-arc chapter boundaries are approximate (sources disagree by a chapter or two at arc seams). Anime-original arcs are anchored to their surrounding chapter as a placeholder and adapt no source. Unadapted manga tail: Jailbreaker arc (ch 97-127) and later school-life storylines (ch 128-180). Railgun has no theatrical film (the franchise's Endymion movie belongs to the sister series A Certain Magical Index).", + "mappings": [ + { + "episodes": [1, 14], + "chapters": [1, 17], + "arc": "Level Upper Arc" + }, + { + "episodes": [15, 24], + "chapters": [17, 17], + "arc": "Poltergeist Arc (anime-original; Big Spider woven in)" + }, + { + "episodes": [25, 40], + "chapters": [18, 39], + "arc": "Sisters Arc" + }, + { + "episodes": [41, 48], + "chapters": [39, 39], + "arc": "Silent Party Arc (anime-original)" + }, + { + "episodes": [49, 63], + "chapters": [40, 70], + "arc": "Daihaseisai (Daihasei Festival) Arc" + }, + { + "episodes": [64, 73], + "chapters": [71, 96], + "arc": "Dream Ranker Arc (Indian Poker + Doppelganger; anime-original Scavenger/Kihara additions)" + }, + { + "chapters": [97, 127], + "arc": "Jailbreaker Arc (unadapted)" + }, + { + "chapters": [128, 180], + "arc": "Post-Jailbreaker school-life storylines (unadapted; manga ongoing)" + } + ] +} From ddb6990066716d0b7422cfdf687f77209ba929c0 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:13 -0400 Subject: [PATCH 003/100] KSN: add `sentenced-to-be-a-hero.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–8 - anime `167152` → manga `142687` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/sentenced-to-be-a-hero.json | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/sentenced-to-be-a-hero.json diff --git a/src/data/index.ts b/src/data/index.ts index e62bbbc..83c6e77 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -308,6 +308,7 @@ import worldGodOnlyKnows from "@/data/mappings/world-god-only-knows.json"; import recordOfRagnarok from "@/data/mappings/record-of-ragnarok.json"; import gunGaleOnlineAlternative from "@/data/mappings/gun-gale-online-alternative.json"; import aCertainScientificRailgun from "@/data/mappings/a-certain-scientific-railgun.json"; +import sentencedToBeAHero from "@/data/mappings/sentenced-to-be-a-hero.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -685,6 +686,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ recordOfRagnarok, gunGaleOnlineAlternative, aCertainScientificRailgun, + sentencedToBeAHero, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/sentenced-to-be-a-hero.json b/src/data/mappings/sentenced-to-be-a-hero.json new file mode 100644 index 0000000..674050d --- /dev/null +++ b/src/data/mappings/sentenced-to-be-a-hero.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 167152, + "anilistMangaId": 142687, + "title": "Sentenced to Be a Hero", + "sourceNotes": "Source is Rocket Shokai's light novel \"Sentenced to Be a Hero: The Prison Records of Penal Hero Unit 9004\" (AniList id 142687, format NOVEL); AniList lists no chapter count for the novel, and the separate manga adaptation (id 164543) lags far behind (it had only reached ch. 14, ~episode 5, at the anime's end), so this mapping uses LIGHT-NOVEL VOLUME numbers as the \"chapters\" unit. Studio Kai's 12-episode Season 1 (Jan-Mar 2026) adapts LN volumes 1-2; readers are advised to continue at volume 3. The LN is ongoing at 8 volumes (as of Jan 2026). The episode 1-6 / 7-12 split between vols 1 and 2 is approximate (vol 1's Mureed Fortress defense reached ~episode 5-6 per manga-chapter cross-check). Season 2 was announced March 2026. No theatrical films.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 1], + "arc": "Defense of Mureed Fortress — Xylo's pact with Teoritta, the Holy Sword, defeat of demon lord Iblis (LN vol 1)" + }, + { + "episodes": [7, 12], + "chapters": [2, 2], + "arc": "Port City of Ioff / Loff Port Cheg — assassins targeting Teoritta, new Penal Hero recruits, Rhyno revealed as a Demon Lord (LN vol 2)" + }, + { + "chapters": [3, 8], + "arc": "Reclaiming captured territories & military/temple conspiracy arcs (LN vols 3-8), unadapted" + } + ] +} From 96f60a434978826abffc461c8e590542bd5840d7 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:16 -0400 Subject: [PATCH 004/100] KSN: add `the-fruit-of-grisaia.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–13 ↔ chapters 1–24 - anime `17729` → manga `79051` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/the-fruit-of-grisaia.json | 33 +++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/the-fruit-of-grisaia.json diff --git a/src/data/index.ts b/src/data/index.ts index 83c6e77..97c994d 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -309,6 +309,7 @@ import recordOfRagnarok from "@/data/mappings/record-of-ragnarok.json"; import gunGaleOnlineAlternative from "@/data/mappings/gun-gale-online-alternative.json"; import aCertainScientificRailgun from "@/data/mappings/a-certain-scientific-railgun.json"; import sentencedToBeAHero from "@/data/mappings/sentenced-to-be-a-hero.json"; +import theFruitOfGrisaia from "@/data/mappings/the-fruit-of-grisaia.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -687,6 +688,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ gunGaleOnlineAlternative, aCertainScientificRailgun, sentencedToBeAHero, + theFruitOfGrisaia, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/the-fruit-of-grisaia.json b/src/data/mappings/the-fruit-of-grisaia.json new file mode 100644 index 0000000..a2dbf7d --- /dev/null +++ b/src/data/mappings/the-fruit-of-grisaia.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 17729, + "anilistMangaId": 79051, + "title": "The Fruit of Grisaia", + "sourceNotes": "The 13-episode 2014 anime adapts Front Wing's visual novel Grisaia no Kajitsu, organized by heroine routes: a common-route/Yumiko intro, then the Michiru, Sachi, Makina and Amane routes as the climax. Paired here with the Grisaia no Kajitsu: Sanctuary Fellows manga (AniList 79051, 24 chapters / 4 volumes, 2013-2014, complete), which retells the same common route plus the five heroines. Because the manga compresses the individual routes differently than the anime, the per-route chapter ranges are APPROXIMATE; only the cumulative endpoint (last entry reaching ch. 24) is reliable. Scope is limited to this first installment: The Labyrinth of Grisaia (2015, 47-min TV special) and The Eden of Grisaia (2015, 10-ep TV) adapt the later VNs Meikyuu and Rakuen and have their own AniList entries; the Grisaia: Phantom Trigger films are a separate spin-off franchise and are excluded, so no movies are listed.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 6], + "arc": "Common route - Yuuji arrives at Mihama Academy & Yumiko intro" + }, + { + "episodes": [3, 4], + "chapters": [7, 10], + "arc": "Michiru Matsushima route (approximate - condensed in manga)" + }, + { + "episodes": [5, 7], + "chapters": [11, 15], + "arc": "Sachi Komine route (approximate - condensed in manga)" + }, + { + "episodes": [8, 9], + "chapters": [16, 19], + "arc": "Makina Irisu route (approximate - condensed in manga)" + }, + { + "episodes": [10, 13], + "chapters": [20, 24], + "arc": "Amane Suou route - backstory & climax" + } + ] +} From 2a41979176b10fa98e440eaa2abdf566f1a61d07 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:19 -0400 Subject: [PATCH 005/100] KSN: add `hellsing-2001.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–6 ↔ chapters 1–92 - anime `270` → manga `30267` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/hellsing-2001.json | 32 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/hellsing-2001.json diff --git a/src/data/index.ts b/src/data/index.ts index 97c994d..380710a 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -310,6 +310,7 @@ import gunGaleOnlineAlternative from "@/data/mappings/gun-gale-online-alternativ import aCertainScientificRailgun from "@/data/mappings/a-certain-scientific-railgun.json"; import sentencedToBeAHero from "@/data/mappings/sentenced-to-be-a-hero.json"; import theFruitOfGrisaia from "@/data/mappings/the-fruit-of-grisaia.json"; +import hellsing2001 from "@/data/mappings/hellsing-2001.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -689,6 +690,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ aCertainScientificRailgun, sentencedToBeAHero, theFruitOfGrisaia, + hellsing2001, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/hellsing-2001.json b/src/data/mappings/hellsing-2001.json new file mode 100644 index 0000000..e11d6fe --- /dev/null +++ b/src/data/mappings/hellsing-2001.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 270, + "anilistMangaId": 30267, + "title": "Hellsing", + "sourceNotes": "The 2001 Gonzo TV series (13 episodes) only loosely adapts Kouta Hirano's manga through roughly episode 6, then diverges into a wholly anime-original storyline (the vampire Incognito) with no manga basis — episodes 7-13 (Duel, Kill House, Red Rose Vertigo, Master of Monster, Transcend Force, Total Destruction, Hellfire) are original and are not mapped to chapters here. The early episodes compress Volume 1 material (Cheddar incident and Seras being turned, the Murder Club vampire pair, and Alexander Anderson's Sword Dancer introduction) plus the Valentine Brothers' assault on Hellsing HQ (Dead Zone), diverging around chapter 12. Chapter ranges are approximate because the adaptation reorders and abridges the source. Manga complete at 92 chapters / 10 volumes (per AniList). The faithful full-manga adaptation is Hellsing Ultimate (OVA, id 777), mapped separately as hellsing-ultimate.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 2], + "arc": "The Undead (Cheddar Incident)" + }, + { + "episodes": [2, 2], + "chapters": [3, 3], + "arc": "Murder Club (Club M)" + }, + { + "episodes": [3, 4], + "chapters": [4, 6], + "arc": "Sword Dancer (Anderson & Iscariot)" + }, + { + "episodes": [5, 6], + "chapters": [7, 12], + "arc": "Dead Zone (Valentine Brothers' Attack)" + }, + { + "chapters": [13, 92], + "arc": "Millennium War & Final Battle (unadapted — 2001 anime goes original with Incognito; see Hellsing Ultimate)" + } + ] +} From 14ffb6727242388af951aa8aa1e8509068a01eee Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:22 -0400 Subject: [PATCH 006/100] KSN: add `the-summer-hikaru-died.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–46 - anime `177689` → manga `138603` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/the-summer-hikaru-died.json | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/the-summer-hikaru-died.json diff --git a/src/data/index.ts b/src/data/index.ts index 380710a..d4f0f0f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -311,6 +311,7 @@ import aCertainScientificRailgun from "@/data/mappings/a-certain-scientific-rail import sentencedToBeAHero from "@/data/mappings/sentenced-to-be-a-hero.json"; import theFruitOfGrisaia from "@/data/mappings/the-fruit-of-grisaia.json"; import hellsing2001 from "@/data/mappings/hellsing-2001.json"; +import theSummerHikaruDied from "@/data/mappings/the-summer-hikaru-died.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -691,6 +692,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ sentencedToBeAHero, theFruitOfGrisaia, hellsing2001, + theSummerHikaruDied, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/the-summer-hikaru-died.json b/src/data/mappings/the-summer-hikaru-died.json new file mode 100644 index 0000000..2b70ae5 --- /dev/null +++ b/src/data/mappings/the-summer-hikaru-died.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 177689, + "anilistMangaId": 138603, + "title": "The Summer Hikaru Died", + "sourceNotes": "Single 12-episode TV season (2025) adapting the manga by Mokumokuren; episodes are cumulative 1-12 (no prior seasons). The anime reorders/interleaves some chapters but covers manga chapters 1-26 in full, ending just shy of the end of ch. 26. The fandom wiki names two adapted arcs: Daily Life Arc (ch. 1-16) and the Mystery Solving Arc, aka the Village arc (ch. 17-26); episode boundaries mapped via the anime-filler episode-to-chapter guide, so per-arc episode ranges are approximate given the non-linear adaptation. Manga is ongoing: 9 tankobon volumes / through chapter 46 published as of June 2026. Chapters 27+ (Hole Closing Arc) are unadapted. A 2nd season was announced in Sept 2025 (release TBA). No theatrical films exist (a stage play ran Jan 2026, excluded).", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 16], + "arc": "Daily Life Arc" + }, + { + "episodes": [8, 12], + "chapters": [17, 26], + "arc": "Mystery Solving Arc (Village)" + }, + { + "chapters": [27, 46], + "arc": "Hole Closing Arc" + } + ] +} From 716f2d2357030363cdfbebdafd175e07c78f77bb Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:25 -0400 Subject: [PATCH 007/100] KSN: add `takopis-original-sin.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–6 ↔ chapters 1–16 - anime `185407` → manga `142568` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/takopis-original-sin.json | 38 +++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/data/mappings/takopis-original-sin.json diff --git a/src/data/index.ts b/src/data/index.ts index d4f0f0f..9469201 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -312,6 +312,7 @@ import sentencedToBeAHero from "@/data/mappings/sentenced-to-be-a-hero.json"; import theFruitOfGrisaia from "@/data/mappings/the-fruit-of-grisaia.json"; import hellsing2001 from "@/data/mappings/hellsing-2001.json"; import theSummerHikaruDied from "@/data/mappings/the-summer-hikaru-died.json"; +import takopisOriginalSin from "@/data/mappings/takopis-original-sin.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -693,6 +694,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ theFruitOfGrisaia, hellsing2001, theSummerHikaruDied, + takopisOriginalSin, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/takopis-original-sin.json b/src/data/mappings/takopis-original-sin.json new file mode 100644 index 0000000..1797013 --- /dev/null +++ b/src/data/mappings/takopis-original-sin.json @@ -0,0 +1,38 @@ +{ + "anilistAnimeId": 185407, + "anilistMangaId": 142568, + "title": "Takopi's Original Sin", + "sourceNotes": "Single-season 6-episode ONA that adapts the complete 16-chapter manga by Taizan5 (2 tankobon volumes; vol.1 = ch1-7, vol.2 = ch8-16). Manga is complete at 16 chapters. Episode 1 adapts chapters 1-2 (confirmed by reviews); episodes 2-6 are each titled after their final adapted chapter (\"Takopi's Salvation\" = ch4, \"Takopi's Confession\" = ch7, \"Azuma-kun's Salvation\" = ch10 \"Naoki's Salvation\" since the boy is Naoki Azuma, \"To You in 2022\" = ch12, \"To All of You in 2016\" = ch16). Single cour, so episode numbers are non-cumulative. The only related film is an unreleased recap/compilation (\"Arigatou, Mata Ashita\"), excluded.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 2], + "arc": "To You in 2016" + }, + { + "episodes": [2, 2], + "chapters": [3, 4], + "arc": "Takopi's Salvation" + }, + { + "episodes": [3, 3], + "chapters": [5, 7], + "arc": "Takopi's Confession" + }, + { + "episodes": [4, 4], + "chapters": [8, 10], + "arc": "Azuma-kun's Salvation" + }, + { + "episodes": [5, 5], + "chapters": [11, 12], + "arc": "To You in 2022" + }, + { + "episodes": [6, 6], + "chapters": [13, 16], + "arc": "To All of You in 2016" + } + ] +} From 7b6c2efbb50e1fd13170472c12cdad088812f574 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:28 -0400 Subject: [PATCH 008/100] KSN: add `lovely-complex.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–24 ↔ chapters 1–72 - anime `2034` → manga `30031` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/lovely-complex.json | 36 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/data/mappings/lovely-complex.json diff --git a/src/data/index.ts b/src/data/index.ts index 9469201..bad804e 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -313,6 +313,7 @@ import theFruitOfGrisaia from "@/data/mappings/the-fruit-of-grisaia.json"; import hellsing2001 from "@/data/mappings/hellsing-2001.json"; import theSummerHikaruDied from "@/data/mappings/the-summer-hikaru-died.json"; import takopisOriginalSin from "@/data/mappings/takopis-original-sin.json"; +import lovelyComplex from "@/data/mappings/lovely-complex.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -695,6 +696,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ hellsing2001, theSummerHikaruDied, takopisOriginalSin, + lovelyComplex, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/lovely-complex.json b/src/data/mappings/lovely-complex.json new file mode 100644 index 0000000..6ea9218 --- /dev/null +++ b/src/data/mappings/lovely-complex.json @@ -0,0 +1,36 @@ +{ + "anilistAnimeId": 2034, + "anilistMangaId": 30031, + "title": "Lovely Complex", + "sourceNotes": "Single-cour adaptation: 24 episodes covering roughly the first half of the 72-chapter manga (17 volumes, completed 2007, including the Love Com Final one-shot). Source is Aya Nakahara's Lovely★Complex / Love★Com (AniList manga id 30031). The anime tracks the manga closely and roughly one chapter per episode through the first two-thirds, then condenses; episode 24 ends around chapter 47, leaving the later dating/graduation half unadapted. This romcom has no official arc names, so arc labels are descriptive of narrative beats and chapter boundaries are approximate — refine via PR.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 8], + "arc": "Comedy Duo / Failed Matchmaking" + }, + { + "episodes": [5, 10], + "chapters": [9, 18], + "arc": "Risa Falls / Umibozu Concert" + }, + { + "episodes": [11, 17], + "chapters": [19, 32], + "arc": "Confession & Haruka Rivalry" + }, + { + "episodes": [18, 24], + "chapters": [33, 47], + "arc": "Becoming a Couple" + }, + { + "chapters": [48, 58], + "arc": "Kohori & Relationship Trials" + }, + { + "chapters": [59, 72], + "arc": "Graduation & Love Com Final" + } + ] +} From 1297c9bb3b0d4713ce291ddf1c7964750e8a01a1 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:31 -0400 Subject: [PATCH 009/100] KSN: add `rokka-braves-of-the-six-flowers.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–12 ↔ chapters 1–6 - anime `20955` → manga `86037` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../rokka-braves-of-the-six-flowers.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/rokka-braves-of-the-six-flowers.json diff --git a/src/data/index.ts b/src/data/index.ts index bad804e..cc68805 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -314,6 +314,7 @@ import hellsing2001 from "@/data/mappings/hellsing-2001.json"; import theSummerHikaruDied from "@/data/mappings/the-summer-hikaru-died.json"; import takopisOriginalSin from "@/data/mappings/takopis-original-sin.json"; import lovelyComplex from "@/data/mappings/lovely-complex.json"; +import rokkaBravesOfTheSixFlowers from "@/data/mappings/rokka-braves-of-the-six-flowers.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -697,6 +698,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ theSummerHikaruDied, takopisOriginalSin, lovelyComplex, + rokkaBravesOfTheSixFlowers, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/rokka-braves-of-the-six-flowers.json b/src/data/mappings/rokka-braves-of-the-six-flowers.json new file mode 100644 index 0000000..b17e375 --- /dev/null +++ b/src/data/mappings/rokka-braves-of-the-six-flowers.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 20955, + "anilistMangaId": 86037, + "title": "Rokka -Braves of the Six Flowers-", + "sourceNotes": "Source is Ishio Yamagata's light novel (AniList id 86037, format NOVEL; AniList lists no chapter count), so this mapping uses LIGHT-NOVEL VOLUME numbers as the \"chapters\" unit. The linked manga (id 86038, 16 chapters / 4 tankobon, finished 2015) is a minor side-adaptation of volume 1 only, not the primary source. The single 12-episode TV series (id 20955, 2015) adapts the ENTIRETY of LN volume 1 as one continuous locked-room mystery — the six chosen Braves discover a seventh among them and Adlet must expose the impostor (vol 1 = Prologue, chapters 1-5, Epilogue). The LN ran 6 volumes (final volume released July 2015) and has been on indefinite hiatus since; volumes 2-6 (the march through the Howling Vilelands — the second fake, Tgurneu, Chamo's parasite, the Dead Host, and the Black Barrenbloom) are entirely unadapted. No theatrical films (a 3-episode \"Picture Drama\" short exists but is not a feature).", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 1], + "arc": "The Search for the Seventh / The Fake Brave - the six Braves of the Six Flowers gather, find a seventh impostor among them, and Adlet is accused; he must uncover the true fake (LN vol 1, the entire anime)" + }, + { + "chapters": [2, 6], + "arc": "March through the Howling Vilelands - the second fake, Tgurneu and the fiend commanders, Chamo's parasite, the Dead Host, and the Black Barrenbloom (LN vols 2-6, unadapted; series on hiatus)" + } + ] +} From 18e722ffd89ae205eb809b8fd962bf8fc0ed8769 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:34 -0400 Subject: [PATCH 010/100] KSN: add `sankarea.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs covering episodes 1–12 ↔ chapters 1–59 - anime `11499` → manga `48597` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/sankarea.json | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/data/mappings/sankarea.json diff --git a/src/data/index.ts b/src/data/index.ts index cc68805..c05ad84 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -315,6 +315,7 @@ import theSummerHikaruDied from "@/data/mappings/the-summer-hikaru-died.json"; import takopisOriginalSin from "@/data/mappings/takopis-original-sin.json"; import lovelyComplex from "@/data/mappings/lovely-complex.json"; import rokkaBravesOfTheSixFlowers from "@/data/mappings/rokka-braves-of-the-six-flowers.json"; +import sankarea from "@/data/mappings/sankarea.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -699,6 +700,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ takopisOriginalSin, lovelyComplex, rokkaBravesOfTheSixFlowers, + sankarea, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/sankarea.json b/src/data/mappings/sankarea.json new file mode 100644 index 0000000..1f171b1 --- /dev/null +++ b/src/data/mappings/sankarea.json @@ -0,0 +1,40 @@ +{ + "anilistAnimeId": 11499, + "anilistMangaId": 48597, + "title": "Sankarea: Undying Love", + "sourceNotes": "Single 12-episode TV season (2012) adapting manga chapters 1-21 (roughly volumes 1-4); the anime's final episode adds an anime-original cliffhanger not in the manga. Manga complete at 59 chapters across 11 volumes. Adaptation runs ~1.75 chapters/episode, so chapter boundaries are approximate and follow narrative beats. Two OVAs adapt side chapters out of sequence (a prequel from ch. 2 and a comedic side-story around ch. 29) and are excluded from the sequential mapping. Unadapted tail (ch. 22-59) grouped into broad chapter-only entries.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 4], + "arc": "Reviving Babu" + }, + { + "episodes": [3, 5], + "chapters": [5, 9], + "arc": "Rea Becomes a Zombie" + }, + { + "episodes": [6, 8], + "chapters": [10, 14], + "arc": "A New Life Together" + }, + { + "episodes": [9, 12], + "chapters": [15, 21], + "arc": "Confronting the Sanka Family" + }, + { + "chapters": [22, 34], + "arc": "Searching for a Cure" + }, + { + "chapters": [35, 47], + "arc": "Zombie Outbreak" + }, + { + "chapters": [48, 59], + "arc": "Final Arc" + } + ] +} From 9c5ba5d95902e1a84b99f5729f8c14f5e8bd80b3 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:36 -0400 Subject: [PATCH 011/100] KSN: add `accel-world.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs covering episodes 1–24 ↔ chapters 1–28 - anime `11759` → manga `53116` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/accel-world.json | 42 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/accel-world.json diff --git a/src/data/index.ts b/src/data/index.ts index c05ad84..70010e6 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -316,6 +316,7 @@ import takopisOriginalSin from "@/data/mappings/takopis-original-sin.json"; import lovelyComplex from "@/data/mappings/lovely-complex.json"; import rokkaBravesOfTheSixFlowers from "@/data/mappings/rokka-braves-of-the-six-flowers.json"; import sankarea from "@/data/mappings/sankarea.json"; +import accelWorld from "@/data/mappings/accel-world.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -701,6 +702,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ lovelyComplex, rokkaBravesOfTheSixFlowers, sankarea, + accelWorld, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/accel-world.json b/src/data/mappings/accel-world.json new file mode 100644 index 0000000..bbadde1 --- /dev/null +++ b/src/data/mappings/accel-world.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 11759, + "anilistMangaId": 53116, + "title": "Accel World", + "sourceNotes": "LN-based mapping: AniList has no manga source, so ranges use the light-novel VOLUME numbering (AniList novel id 53116, chapters/volumes null there). The 24-episode Sunrise TV series (single cour-pair, only season) adapts LN volumes 1-4 in chronological order and interleaves two short stories from the Vol 10 \"Elements\" collection: eps 6-7 (Aqua Current) and eps 18-19 (Snow Fairy / Okinawa trip). Volume-to-episode splits: Vol 1 = eps 1-5, Vol 10 short = eps 6-7, Vol 2 = eps 8-12, Vol 3 = eps 13-17, Vol 10 short = eps 18-19, Vol 4 = eps 20-24. The two OVA episodes (Accel World EX) are anime-original and not mapped. Light novel is ongoing at 28 volumes (Vol 28 \"Goddess of the Night\", Aug 2025; Vol 29 due Dec 2026). \"chapters\" ranges here denote VOLUME numbers, not chapter numbers.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 1], + "arc": "Kuroyukihime's Return (Vol 1)" + }, + { + "episodes": [6, 7], + "chapters": [10, 10], + "arc": "Aqua Current (Elements side story, Vol 10)" + }, + { + "episodes": [8, 12], + "chapters": [2, 2], + "arc": "The Red Storm Princess (Vol 2)" + }, + { + "episodes": [13, 17], + "chapters": [3, 3], + "arc": "The Twilight Marauder (Vol 3)" + }, + { + "episodes": [18, 19], + "chapters": [10, 10], + "arc": "Snow Fairy / Okinawa (Elements side story, Vol 10)" + }, + { + "episodes": [20, 24], + "chapters": [4, 4], + "arc": "Flight Toward a Blue Sky (Vol 4)" + }, + { + "chapters": [5, 28], + "arc": "The Floating Starlight Bridge onward (unadapted, Vol 5-28)" + } + ] +} From 1fc48a2b5ceb86baf23c21249b9324cefff28aeb Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:39 -0400 Subject: [PATCH 012/100] KSN: add `infinite-stratos.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs covering episodes 1–24 ↔ chapters 1–13 - anime `9041` → manga `53881` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/infinite-stratos.json | 42 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/infinite-stratos.json diff --git a/src/data/index.ts b/src/data/index.ts index 70010e6..a6fe3a0 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -317,6 +317,7 @@ import lovelyComplex from "@/data/mappings/lovely-complex.json"; import rokkaBravesOfTheSixFlowers from "@/data/mappings/rokka-braves-of-the-six-flowers.json"; import sankarea from "@/data/mappings/sankarea.json"; import accelWorld from "@/data/mappings/accel-world.json"; +import infiniteStratos from "@/data/mappings/infinite-stratos.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -703,6 +704,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ rokkaBravesOfTheSixFlowers, sankarea, accelWorld, + infiniteStratos, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/infinite-stratos.json b/src/data/mappings/infinite-stratos.json new file mode 100644 index 0000000..921bade --- /dev/null +++ b/src/data/mappings/infinite-stratos.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 9041, + "anilistMangaId": 53881, + "title": "Infinite Stratos", + "sourceNotes": "LN-based; ranges are by light novel volume (Izuru Yumizuru's novels; AniList lists the source as a NOVEL with null chapter counts, so \"chapters\" here are volume numbers). Cumulative episodes across S1 (12 eps, 2011) + S2/Infinite Stratos 2 (12 eps, 2013) = 24. Season 1 adapts volumes 1-3 (plus a little of 4); Season 2 adapts volumes 5-8 (the short-story vol 4 is largely skipped). The novel finished at 13 volumes (final volume Oct 2018), so volumes 9-13 are unadapted by the TV anime. Volume boundaries are approximate; the community episode↔source guide aligns roughly one story volume per ~4 episodes.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "IS Academy / Class Representative (Vol 1)" + }, + { + "episodes": [5, 8], + "chapters": [2, 2], + "arc": "Transfer Students / Interhigh (Vol 2)" + }, + { + "episodes": [9, 12], + "chapters": [3, 3], + "arc": "Silver Gospel (Vol 3)" + }, + { + "episodes": [13, 16], + "chapters": [5, 5], + "arc": "Phantom Task Awakens (Vol 5)" + }, + { + "episodes": [17, 20], + "chapters": [6, 7], + "arc": "School Festival / Tag Tournament (Vols 6-7)" + }, + { + "episodes": [21, 24], + "chapters": [8, 8], + "arc": "Kyoto Field Trip / World Purge (Vol 8)" + }, + { + "chapters": [9, 13], + "arc": "Post-anime Volumes (Unadapted)" + } + ] +} From fa7d4c5046cfb97394df16ed6ac0136826fb9871 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:43 -0400 Subject: [PATCH 013/100] KSN: add `fate-apocrypha.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–25 ↔ chapters 1–5 - anime `98035` → manga `63005` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/fate-apocrypha.json | 33 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/fate-apocrypha.json diff --git a/src/data/index.ts b/src/data/index.ts index a6fe3a0..3fef3c9 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -318,6 +318,7 @@ import rokkaBravesOfTheSixFlowers from "@/data/mappings/rokka-braves-of-the-six- import sankarea from "@/data/mappings/sankarea.json"; import accelWorld from "@/data/mappings/accel-world.json"; import infiniteStratos from "@/data/mappings/infinite-stratos.json"; +import fateApocrypha from "@/data/mappings/fate-apocrypha.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -705,6 +706,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ sankarea, accelWorld, infiniteStratos, + fateApocrypha, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/fate-apocrypha.json b/src/data/mappings/fate-apocrypha.json new file mode 100644 index 0000000..020a0b8 --- /dev/null +++ b/src/data/mappings/fate-apocrypha.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 98035, + "anilistMangaId": 63005, + "title": "Fate/Apocrypha", + "sourceNotes": "Single 25-episode, 2-cour TV series (no multiple seasons), so episode numbers are absolute. Based on Yuuichirou Higashide's 5-volume light novel (complete; AniList novel entry 63005). Chapter ranges here are by LN VOLUME (1-5) — the numbering fan/episode guides use — not AniList's flat 26-\"chapter\" count. First cour (eps 1-12) adapts vols 1-3: ep 12 \"The Holy Man Returns Triumphant\" matches vol 3's title \"Triumphal Return of the Saint.\" Second cour (eps 13-25) covers vols 4-5 but diverges heavily with anime-original material, so back-half volume boundaries are approximate. Two recap episodes (12.5, 19.5) are excluded from the counts.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "Great Holy Grail War" + }, + { + "episodes": [5, 8], + "chapters": [2, 2], + "arc": "Round Dance of Black / Festival of Red" + }, + { + "episodes": [9, 12], + "chapters": [3, 3], + "arc": "Triumphal Return of the Saint" + }, + { + "episodes": [13, 19], + "chapters": [4, 4], + "arc": "Cup of Purgatory" + }, + { + "episodes": [20, 25], + "chapters": [5, 5], + "arc": "Evil Dragon and the Holy Woman" + } + ] +} From 82c50a8f97af68c74264a791aca8c9b69ff04dfc Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:46 -0400 Subject: [PATCH 014/100] KSN: add `oreshura.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–13 ↔ chapters 1–18 - anime `14749` → manga `56613` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/oreshura.json | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/oreshura.json diff --git a/src/data/index.ts b/src/data/index.ts index 3fef3c9..d7f4331 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -319,6 +319,7 @@ import sankarea from "@/data/mappings/sankarea.json"; import accelWorld from "@/data/mappings/accel-world.json"; import infiniteStratos from "@/data/mappings/infinite-stratos.json"; import fateApocrypha from "@/data/mappings/fate-apocrypha.json"; +import oreshura from "@/data/mappings/oreshura.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -707,6 +708,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ accelWorld, infiniteStratos, fateApocrypha, + oreshura, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/oreshura.json b/src/data/mappings/oreshura.json new file mode 100644 index 0000000..731e1d3 --- /dev/null +++ b/src/data/mappings/oreshura.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 14749, + "anilistMangaId": 56613, + "title": "Oreshura", + "sourceNotes": "Single 13-episode A-1 Pictures TV series (2013); no prequel/sequel seasons, so episodes are non-cumulative 1-13. Source is Yuuji Yuuji's GA Bunko light novel (AniList id 56613, NOVEL format, FINISHED at 18 main volumes + 1 after-story; AniList lists 248 total chapters, but chapter numbering resets each volume, e.g. Vol. 2 runs #0-#7). Because per-volume chapters reset and don't form a clean cumulative sequence, the chapters[] ranges here are LIGHT-NOVEL VOLUME numbers, which is the basis community guides use for this show. The anime adapts Volumes 1-4; Volumes 5-18 are unadapted. Arc/volume boundaries inferred from episode titles matched against the published volume tables of contents (e.g. Vol. 2's \"The Truth About the Love Letter\" = ep 5; Vol. 4's \"Summer Training Meeting\" / disciplinary-committee chapters = eps 10-13).", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 1], + "arc": "Masuzu's Fake Girlfriend (Vol. 1)" + }, + { + "episodes": [3, 5], + "chapters": [2, 2], + "arc": "Chiwa's Love Letter (Vol. 2)" + }, + { + "episodes": [6, 8], + "chapters": [3, 3], + "arc": "Himeka Akishino / Gray World (Vol. 3)" + }, + { + "episodes": [9, 13], + "chapters": [4, 4], + "arc": "Ai Fuyuumi & Summer Training Camp (Vol. 4)" + }, + { + "chapters": [5, 18], + "arc": "Unadapted (Vols. 5-18)" + } + ] +} From 38f625eaf52587e10e0f044447524ffaad765563 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:49 -0400 Subject: [PATCH 015/100] KSN: add `uncle-from-another-world.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs covering episodes 1–13 ↔ chapters 1–74 - anime `135806` → manga `104617` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../mappings/uncle-from-another-world.json | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/uncle-from-another-world.json diff --git a/src/data/index.ts b/src/data/index.ts index d7f4331..b957566 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -320,6 +320,7 @@ import accelWorld from "@/data/mappings/accel-world.json"; import infiniteStratos from "@/data/mappings/infinite-stratos.json"; import fateApocrypha from "@/data/mappings/fate-apocrypha.json"; import oreshura from "@/data/mappings/oreshura.json"; +import uncleFromAnotherWorld from "@/data/mappings/uncle-from-another-world.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -709,6 +710,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ infiniteStratos, fateApocrypha, oreshura, + uncleFromAnotherWorld, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/uncle-from-another-world.json b/src/data/mappings/uncle-from-another-world.json new file mode 100644 index 0000000..25b1141 --- /dev/null +++ b/src/data/mappings/uncle-from-another-world.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 135806, + "anilistMangaId": 104617, + "title": "Uncle from Another World", + "sourceNotes": "Single 13-episode TV season (Atelier Pontdarc, 2022-2023); no sequel season, so cumulative episodes equal S1 episodes. Source is Hotondoshindeiru's ongoing episodic web manga (AniList id 104617), which is gag/slice-of-life with no official arc names, so groupings are labeled by episode-title storyline threads and chapter ranges are approximate. The adaptation is non-linear (each episode pulls ~2-3 chapters, sometimes out of order); it covers roughly chapters 1-33, with Ep13's epilogue teasing scattered later chapters (34, 36). Manga ongoing (~ch. 74 / 15 volumes as of 2026).", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 7], + "arc": "Homecoming & Guardian Heroes" + }, + { + "episodes": [3, 4], + "chapters": [8, 12], + "arc": "The Tsundere Elf" + }, + { + "episodes": [5, 6], + "chapters": [13, 18], + "arc": "Assassination & the Freak Show" + }, + { + "episodes": [7, 8], + "chapters": [19, 22], + "arc": "SEGA Wisdom & the Strongest Form" + }, + { + "episodes": [9, 11], + "chapters": [23, 29], + "arc": "The Ice Spirit" + }, + { + "episodes": [12, 13], + "chapters": [30, 33], + "arc": "The Singing Demon" + }, + { + "chapters": [34, 74], + "arc": "Continued Adventures (Unadapted)" + } + ] +} From 078c9ece4fc687aa16da967ae918bb53293006c6 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:52 -0400 Subject: [PATCH 016/100] KSN: add `girlfriend-girlfriend.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 arcs covering episodes 1–24 ↔ chapters 1–144 - anime `126192` → manga `116266` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/girlfriend-girlfriend.json | 42 ++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/girlfriend-girlfriend.json diff --git a/src/data/index.ts b/src/data/index.ts index b957566..13e724c 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -321,6 +321,7 @@ import infiniteStratos from "@/data/mappings/infinite-stratos.json"; import fateApocrypha from "@/data/mappings/fate-apocrypha.json"; import oreshura from "@/data/mappings/oreshura.json"; import uncleFromAnotherWorld from "@/data/mappings/uncle-from-another-world.json"; +import girlfriendGirlfriend from "@/data/mappings/girlfriend-girlfriend.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -711,6 +712,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ fateApocrypha, oreshura, uncleFromAnotherWorld, + girlfriendGirlfriend, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/girlfriend-girlfriend.json b/src/data/mappings/girlfriend-girlfriend.json new file mode 100644 index 0000000..d83aa3f --- /dev/null +++ b/src/data/mappings/girlfriend-girlfriend.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 126192, + "anilistMangaId": 116266, + "title": "Girlfriend, Girlfriend", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 (eps 13-24). Manga complete at 144 chapters (16 volumes). S1 adapts ch 1-36 (vols 1-4); S2 adapts ch 37-91; ch 92-144 are unadapted. This is an episodic shonen gag-romcom with no formal arc names in the source (the manga is organized only by volume), so arcs below are named descriptively by story beat. The anime reorders a few chapters (e.g. ep 5 pulls ch 19, ep 7 pulls ch 37-38 early), so per-arc chapter ranges are contiguous approximations of each block's dominant span. Roughly 3-4 chapters per episode. Per-episode chapter boundaries sourced from the Kanojo mo Kanojo Fandom wiki episode pages.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 13], + "arc": "Nagisa's Confession (The Second Girlfriend)" + }, + { + "episodes": [5, 9], + "chapters": [14, 26], + "arc": "Rika's Challenge (The Third Girlfriend)" + }, + { + "episodes": [10, 12], + "chapters": [27, 36], + "arc": "Hot Springs Trip" + }, + { + "episodes": [13, 16], + "chapters": [37, 54], + "arc": "Summer Break & Shino" + }, + { + "episodes": [17, 20], + "chapters": [55, 73], + "arc": "Culture Festival" + }, + { + "episodes": [21, 24], + "chapters": [74, 91], + "arc": "The Girlfriends' Getaway" + }, + { + "chapters": [92, 144], + "arc": "Mirika's Resolve & Finale (unadapted)" + } + ] +} From afed7e6249c8a5a7e4e4d58135ad7b9df54770cf Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:54 -0400 Subject: [PATCH 017/100] KSN: add `we-never-learn.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–26 ↔ chapters 1–187 - anime `103900` → manga `98235` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/we-never-learn.json | 42 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/data/mappings/we-never-learn.json diff --git a/src/data/index.ts b/src/data/index.ts index 13e724c..f6df863 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -322,6 +322,7 @@ import fateApocrypha from "@/data/mappings/fate-apocrypha.json"; import oreshura from "@/data/mappings/oreshura.json"; import uncleFromAnotherWorld from "@/data/mappings/uncle-from-another-world.json"; import girlfriendGirlfriend from "@/data/mappings/girlfriend-girlfriend.json"; +import weNeverLearn from "@/data/mappings/we-never-learn.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -713,6 +714,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ oreshura, uncleFromAnotherWorld, girlfriendGirlfriend, + weNeverLearn, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/we-never-learn.json b/src/data/mappings/we-never-learn.json new file mode 100644 index 0000000..64b3543 --- /dev/null +++ b/src/data/mappings/we-never-learn.json @@ -0,0 +1,42 @@ +{ + "anilistAnimeId": 103900, + "anilistMangaId": 98235, + "title": "We Never Learn: BOKUBEN", + "sourceNotes": "Cumulative episodes across S1 (13) + S2 (13) = 26 TV episodes. The anime adapts roughly manga Questions 1-69 (through Volume 8's Cultural Festival arc), but Silver/Arvo reorder chapters non-linearly across episodes to feature all heroines evenly, so per-episode boundaries are approximate — ranges are given at the season-block level. Manga complete at 187 chapters / 21 volumes (Taishi Tsutsui, Weekly Shonen Jump). Volumes 9-16 (Questions ~70-141) continue the unadapted common route building to the fireworks confession. The final five volumes (17-21, Questions 142-187) form the famous \"Route:if\" branch — five parallel alternate endings, one per heroine, presented here in publication order: Uruka (Mermaid Princess), Rizu (Thumbelina), Fumino (Sleeping Beauty of the Literary Forest), Asumi (Pixie), and Mafuyu Kirisu (Queen of Thin Ice), the last also containing a harem omake. Two OVAs (side stories adapting beach/wedding chapters, bundled with manga volumes) are not part of the TV episode count. No theatrical films.", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 43], + "arc": "Season 1: The Genius Tutees (Fumino, Rizu, Uruka)" + }, + { + "episodes": [14, 26], + "chapters": [44, 69], + "arc": "Season 2: Deepening Bonds (Hot Spring & Cultural Festival)" + }, + { + "chapters": [70, 141], + "arc": "Common Route: The Path to the Fireworks (unadapted)" + }, + { + "chapters": [142, 150], + "arc": "Route:if — Uruka (Mermaid Princess)" + }, + { + "chapters": [151, 159], + "arc": "Route:if — Rizu (Thumbelina)" + }, + { + "chapters": [160, 168], + "arc": "Route:if — Fumino (Sleeping Beauty of the Literary Forest)" + }, + { + "chapters": [169, 177], + "arc": "Route:if — Asumi (Pixie)" + }, + { + "chapters": [178, 187], + "arc": "Route:if — Mafuyu Kirisu (Queen of Thin Ice) & Harem Ending" + } + ] +} From 8fd096956d838c625075e74b6a4dd511870a215d Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:15:58 -0400 Subject: [PATCH 018/100] KSN: add `gabriel-dropout.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 13 arcs covering episodes 1–11 ↔ chapters 1–122 - anime `21878` → manga `86864` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/gabriel-dropout.json | 61 ++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/data/mappings/gabriel-dropout.json diff --git a/src/data/index.ts b/src/data/index.ts index f6df863..7638deb 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -323,6 +323,7 @@ import oreshura from "@/data/mappings/oreshura.json"; import uncleFromAnotherWorld from "@/data/mappings/uncle-from-another-world.json"; import girlfriendGirlfriend from "@/data/mappings/girlfriend-girlfriend.json"; import weNeverLearn from "@/data/mappings/we-never-learn.json"; +import gabrielDropout from "@/data/mappings/gabriel-dropout.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -715,6 +716,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ uncleFromAnotherWorld, girlfriendGirlfriend, weNeverLearn, + gabrielDropout, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/gabriel-dropout.json b/src/data/mappings/gabriel-dropout.json new file mode 100644 index 0000000..3a15b8c --- /dev/null +++ b/src/data/mappings/gabriel-dropout.json @@ -0,0 +1,61 @@ +{ + "anilistAnimeId": 21878, + "anilistMangaId": 86864, + "title": "Gabriel DropOut", + "sourceNotes": "Single 12-episode TV season (Doga Kobo, 2017). Adapts Ukami's 4-koma manga non-linearly (shuffled) across volumes 1-4, roughly chapters 1-38, skipping only two chapters plus a few minor gags; episode 12 is anime-original, so the adapted range is mapped to episodes 1-11. Because the source is a 4-koma with a shuffled adaptation order, the single adapted entry covers volumes 1-4 rather than a per-episode split, and the unadapted tail is broken out by volume for reading reference. Readers should continue from chapter 39. AniList lists no chapter count on the manga entry; per MangaDex the manga is ongoing (16 volumes, current ~ch. 122). A separate 2-episode OVA exists but is not theatrical; the series has no theatrical films.", + "mappings": [ + { + "episodes": [1, 11], + "chapters": [1, 38], + "arc": "Volumes 1-4 (anime-adapted, non-linear)" + }, + { + "chapters": [39, 44], + "arc": "Volume 5" + }, + { + "chapters": [45, 51], + "arc": "Volume 6" + }, + { + "chapters": [52, 57], + "arc": "Volume 7" + }, + { + "chapters": [58, 63], + "arc": "Volume 8" + }, + { + "chapters": [64, 71], + "arc": "Volume 9" + }, + { + "chapters": [72, 77], + "arc": "Volume 10" + }, + { + "chapters": [78, 83], + "arc": "Volume 11" + }, + { + "chapters": [84, 89], + "arc": "Volume 12" + }, + { + "chapters": [90, 97], + "arc": "Volume 13" + }, + { + "chapters": [98, 106], + "arc": "Volume 14" + }, + { + "chapters": [107, 116], + "arc": "Volume 15" + }, + { + "chapters": [117, 122], + "arc": "Volume 16" + } + ] +} From c9ba0b7410f994aa4790615980e0e8b37679f895 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:00 -0400 Subject: [PATCH 019/100] KSN: add `platinum-end.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–24 ↔ chapters 1–58 - anime `127401` → manga `86526` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/platinum-end.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/platinum-end.json diff --git a/src/data/index.ts b/src/data/index.ts index 7638deb..0e62b98 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -324,6 +324,7 @@ import uncleFromAnotherWorld from "@/data/mappings/uncle-from-another-world.json import girlfriendGirlfriend from "@/data/mappings/girlfriend-girlfriend.json"; import weNeverLearn from "@/data/mappings/we-never-learn.json"; import gabrielDropout from "@/data/mappings/gabriel-dropout.json"; +import platinumEnd from "@/data/mappings/platinum-end.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -717,6 +718,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ girlfriendGirlfriend, weNeverLearn, gabrielDropout, + platinumEnd, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/platinum-end.json b/src/data/mappings/platinum-end.json new file mode 100644 index 0000000..506dc2e --- /dev/null +++ b/src/data/mappings/platinum-end.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 127401, + "anilistMangaId": 86526, + "title": "Platinum End", + "sourceNotes": "Single-cour 24-episode TV anime (no season split) that adapts the complete manga by Tsugumi Ohba and Takeshi Obata. Manga is complete at 58 chapters across 14 volumes; the anime covers all of it (roughly 2 chapters/episode in the first half, then ~3.4 chapters/episode as the second half is compressed). Cumulative episodes are simply 1-24 since there is only one season. Chapter boundaries follow the tankobon volumes: the Metropoliman arc concludes with Kanade Uryu's defeat at the end of volume 8 (ch 27, ~episode 15), Professor Gaku Yoneda (the final antagonist) formally debuts in volume 10 (ch 32). Arc-to-episode boundaries in the compressed second half are approximate.", + "mappings": [ + { + "episodes": [1, 15], + "chapters": [1, 27], + "arc": "Metropoliman Arc" + }, + { + "episodes": [16, 17], + "chapters": [28, 31], + "arc": "New God Candidates Arc" + }, + { + "episodes": [18, 24], + "chapters": [32, 58], + "arc": "Professor Yoneda Arc" + } + ] +} From ed2002d111fa8c39b5f573e8fbbde56061ee62a3 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:03 -0400 Subject: [PATCH 020/100] KSN: add `strike-the-blood.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 19 arcs covering episodes 1–60 ↔ chapters 1–157 - anime `18277` → manga `71021` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/strike-the-blood.json | 103 ++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/data/mappings/strike-the-blood.json diff --git a/src/data/index.ts b/src/data/index.ts index 0e62b98..e6046ff 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -325,6 +325,7 @@ import girlfriendGirlfriend from "@/data/mappings/girlfriend-girlfriend.json"; import weNeverLearn from "@/data/mappings/we-never-learn.json"; import gabrielDropout from "@/data/mappings/gabriel-dropout.json"; import platinumEnd from "@/data/mappings/platinum-end.json"; +import strikeTheBlood from "@/data/mappings/strike-the-blood.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -719,6 +720,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ weNeverLearn, gabrielDropout, platinumEnd, + strikeTheBlood, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/strike-the-blood.json b/src/data/mappings/strike-the-blood.json new file mode 100644 index 0000000..bea4543 --- /dev/null +++ b/src/data/mappings/strike-the-blood.json @@ -0,0 +1,103 @@ +{ + "anilistAnimeId": 18277, + "anilistMangaId": 71021, + "title": "Strike the Blood", + "sourceNotes": "Source is Gakuto Mikumo's light novel (AniList id 71021, format NOVEL, 157 parts across 22 main volumes; series complete, ended 2020 with vol 22). Chapter ranges are proportional volume estimates mapped onto AniList's 157-part count (~7 parts/vol), so they are approximate. Cumulative episodes span the full sequel/OVA chain: TV Season 1 (id 18277, 24 eps) + Kingdom of the Valkyria side-story OVA (id 21098, 2 eps) + Strike the Blood II (id 21815, 8 eps) + Strike the Blood III (10 eps) + Strike the Blood IV (12 eps) + Strike the Blood Final (4 eps) = 60 episodes. The adaptation is deliberately OUT of volume order, so chapter ranges are non-monotonic: S1 adapts vols 1-6, with eps 23-24 an anime-original finale loosely based on vol 17; the Kingdom of the Valkyria OVA covers side-story vol 18; STB II adapts vols 9, 11, 12 (skipping vol 10); STB III adapts vols 13-15; STB IV adapts vols 16, 19, 20, 21; STB Final adapts vol 22. LN vols 7, 8, and 10 were never adapted. Within-OVA per-volume episode splits are evenly estimated. No theatrical films exist.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 7], + "arc": "The Right Arm of the Saint (LN vol 1)" + }, + { + "episodes": [5, 8], + "chapters": [8, 14], + "arc": "From the Warlord's Empire (LN vol 2)" + }, + { + "episodes": [9, 12], + "chapters": [15, 21], + "arc": "The Amphisbaena (LN vol 3)" + }, + { + "episodes": [13, 15], + "chapters": [22, 29], + "arc": "Labyrinth of the Blue Witch (LN vol 4)" + }, + { + "episodes": [16, 19], + "chapters": [30, 36], + "arc": "Fiesta for the Observers (LN vol 5)" + }, + { + "episodes": [20, 22], + "chapters": [37, 43], + "arc": "Return of the Alchemist (LN vol 6)" + }, + { + "episodes": [23, 24], + "chapters": [115, 121], + "arc": "Empire of the Dawn (S1 anime-original finale, loosely LN vol 17)" + }, + { + "episodes": [25, 26], + "chapters": [122, 128], + "arc": "Kingdom of the Valkyria OVA (side story, LN vol 18)" + }, + { + "episodes": [27, 29], + "chapters": [58, 64], + "arc": "Strike the Blood II - Third Progenitor arc (LN vol 9)" + }, + { + "episodes": [30, 32], + "chapters": [72, 79], + "arc": "Strike the Blood II (LN vol 11, skips vol 10)" + }, + { + "episodes": [33, 34], + "chapters": [80, 86], + "arc": "Strike the Blood II (LN vol 12)" + }, + { + "episodes": [35, 38], + "chapters": [87, 93], + "arc": "Strike the Blood III (LN vol 13)" + }, + { + "episodes": [39, 41], + "chapters": [94, 100], + "arc": "Strike the Blood III (LN vol 14)" + }, + { + "episodes": [42, 44], + "chapters": [101, 107], + "arc": "Strike the Blood III (LN vol 15)" + }, + { + "episodes": [45, 47], + "chapters": [108, 114], + "arc": "Strike the Blood IV (LN vol 16)" + }, + { + "episodes": [48, 50], + "chapters": [129, 136], + "arc": "Strike the Blood IV (LN vol 19)" + }, + { + "episodes": [51, 53], + "chapters": [137, 143], + "arc": "Strike the Blood IV (LN vol 20)" + }, + { + "episodes": [54, 56], + "chapters": [144, 150], + "arc": "Strike the Blood IV (LN vol 21)" + }, + { + "episodes": [57, 60], + "chapters": [151, 157], + "arc": "Strike the Blood Final (LN vol 22)" + } + ] +} From 92a50807e8ad90528801551a64c63a550dc7d844 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:07 -0400 Subject: [PATCH 021/100] KSN: add `natsume-yuujinchou.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–86 ↔ chapters 1–135 - 2 movies - anime `4081` → manga `31859` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/natsume-yuujinchou.json | 63 +++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/data/mappings/natsume-yuujinchou.json diff --git a/src/data/index.ts b/src/data/index.ts index e6046ff..5c17533 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -326,6 +326,7 @@ import weNeverLearn from "@/data/mappings/we-never-learn.json"; import gabrielDropout from "@/data/mappings/gabriel-dropout.json"; import platinumEnd from "@/data/mappings/platinum-end.json"; import strikeTheBlood from "@/data/mappings/strike-the-blood.json"; +import natsumeYuujinchou from "@/data/mappings/natsume-yuujinchou.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -721,6 +722,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ gabrielDropout, platinumEnd, strikeTheBlood, + natsumeYuujinchou, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/natsume-yuujinchou.json b/src/data/mappings/natsume-yuujinchou.json new file mode 100644 index 0000000..8463f9b --- /dev/null +++ b/src/data/mappings/natsume-yuujinchou.json @@ -0,0 +1,63 @@ +{ + "anilistAnimeId": 4081, + "anilistMangaId": 31859, + "title": "Natsume's Book of Friends", + "sourceNotes": "Source is the ongoing Natsume Yuujinchou manga by Yuki Midorikawa (AniList 31859; ~33 volumes / ~135 chapters as of 2026, still RELEASING — AniList lists no chapter count). The anime is a highly episodic, largely one-story-per-episode adaptation that pulls chapters OUT OF ORDER and interleaves LaLa specials (numbered as .5 chapters), so chapter boundaries are approximate spans, NOT contiguous 1:1 ranges — later seasons revisit earlier chapters and overlap. Because the show has no named story arcs, mappings are given per TV season using each season's title as the arc label. Cumulative episodes across S1 (13) + S2/Zoku (13) + S3/San (13) + S4/Shi (13) + S5/Go (11) + S6/Roku (11) + S7/Shichi (12) = 86 episodes. Per-season chapter spans derived from fan chapter↔episode masterlists (aislinceivun, treecakes); S7 (2024) adapted roughly manga volumes 20-27. Final chapters-only entry covers the unadapted ongoing tail.", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 10], + "arc": "Season 1 (Natsume Yuujinchou)" + }, + { + "episodes": [14, 26], + "chapters": [4, 22], + "arc": "Season 2 (Zoku Natsume Yuujinchou)" + }, + { + "episodes": [27, 39], + "chapters": [23, 48], + "arc": "Season 3 (Natsume Yuujinchou San)" + }, + { + "episodes": [40, 52], + "chapters": [34, 51], + "arc": "Season 4 (Natsume Yuujinchou Shi)" + }, + { + "episodes": [53, 63], + "chapters": [52, 67], + "arc": "Season 5 (Natsume Yuujinchou Go)" + }, + { + "episodes": [64, 74], + "chapters": [60, 79], + "arc": "Season 6 (Natsume Yuujinchou Roku)" + }, + { + "episodes": [75, 86], + "chapters": [80, 112], + "arc": "Season 7 (Natsume Yuujinchou Shichi)" + }, + { + "chapters": [113, 135], + "arc": "Ongoing (unadapted)" + } + ], + "movies": [ + { + "anilistId": 100268, + "title": "Natsume's Book of Friends: The Waking of the Ephemeral", + "year": 2018, + "afterEpisode": 74, + "note": "Canon theatrical feature (Utsusemi ni Musubu) with an original in-continuity story following Natsume and Nyanko-sensei; new animation, released after the TV run." + }, + { + "anilistId": 124132, + "title": "Natsume Yuujinchou: Ishi Okoshi to Ayashiki Raihousha", + "year": 2021, + "afterEpisode": 74, + "note": "Canon theatrical release of new-animation Natsume stories (The Waking of Stone and the Suspicious Visitor) in the same continuity." + } + ] +} From 5059def3955eb42aad2cb020d54403c1adf10057 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:09 -0400 Subject: [PATCH 022/100] KSN: add `makeine-too-many-losing-heroines.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–11 ↔ chapters 1–8 - anime `171457` → manga `135276` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../makeine-too-many-losing-heroines.json | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/data/mappings/makeine-too-many-losing-heroines.json diff --git a/src/data/index.ts b/src/data/index.ts index 5c17533..813d3c5 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -327,6 +327,7 @@ import gabrielDropout from "@/data/mappings/gabriel-dropout.json"; import platinumEnd from "@/data/mappings/platinum-end.json"; import strikeTheBlood from "@/data/mappings/strike-the-blood.json"; import natsumeYuujinchou from "@/data/mappings/natsume-yuujinchou.json"; +import makeineTooManyLosingHeroines from "@/data/mappings/makeine-too-many-losing-heroines.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -723,6 +724,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ platinumEnd, strikeTheBlood, natsumeYuujinchou, + makeineTooManyLosingHeroines, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/makeine-too-many-losing-heroines.json b/src/data/mappings/makeine-too-many-losing-heroines.json new file mode 100644 index 0000000..19b588c --- /dev/null +++ b/src/data/mappings/makeine-too-many-losing-heroines.json @@ -0,0 +1,43 @@ +{ + "anilistAnimeId": 171457, + "anilistMangaId": 135276, + "title": "Makeine: Too Many Losing Heroines!", + "sourceNotes": "LN-based (Gagaga Bunko, by Takibi Amamori), so ranges are by light-novel VOLUME — the \"chapters\" numbers here denote LN volume numbers, which is what community episode-to-source guides use (a tie-in @comic manga exists but is the minor adaptation). Cumulative episodes cover S1 only (12 eps); S1 adapts LN volumes 1-3, one volume per heroine arc. Episode 12 is an anime-original finale written by the author and does not correspond to an LN volume. LN ongoing at 8 volumes (as of May 2025); volumes 4-8 are unadapted (S2 is expected to begin from volume 4). Per-volume arc names follow the fandom wiki's Losing Heroine arc labels.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "Anna Yanami's Losing Heroine Arc" + }, + { + "episodes": [5, 7], + "chapters": [2, 2], + "arc": "Lemon Yakishio's Losing Heroine Arc" + }, + { + "episodes": [8, 11], + "chapters": [3, 3], + "arc": "Chika Komari's Losing Heroine Arc" + }, + { + "chapters": [4, 4], + "arc": "Koto Tsukinoki / BL Fanfiction Arc" + }, + { + "chapters": [5, 5], + "arc": "Kaju's Valentine's Arc" + }, + { + "chapters": [6, 6], + "arc": "Aquarium Date / Graduation Arc" + }, + { + "chapters": [7, 7], + "arc": "Riko Shiratama Arc (Second Year Begins)" + }, + { + "chapters": [8, 8], + "arc": "Student Council Election Arc" + } + ] +} From 7a30b79ffba824c7eff3168508a6ea7da69a783c Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:12 -0400 Subject: [PATCH 023/100] KSN: add `the-detective-is-already-dead.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–12 ↔ chapters 1–13 - anime `128712` → manga `114202` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/the-detective-is-already-dead.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/the-detective-is-already-dead.json diff --git a/src/data/index.ts b/src/data/index.ts index 813d3c5..64174f3 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -328,6 +328,7 @@ import platinumEnd from "@/data/mappings/platinum-end.json"; import strikeTheBlood from "@/data/mappings/strike-the-blood.json"; import natsumeYuujinchou from "@/data/mappings/natsume-yuujinchou.json"; import makeineTooManyLosingHeroines from "@/data/mappings/makeine-too-many-losing-heroines.json"; +import theDetectiveIsAlreadyDead from "@/data/mappings/the-detective-is-already-dead.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -725,6 +726,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ strikeTheBlood, natsumeYuujinchou, makeineTooManyLosingHeroines, + theDetectiveIsAlreadyDead, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/the-detective-is-already-dead.json b/src/data/mappings/the-detective-is-already-dead.json new file mode 100644 index 0000000..3eb9110 --- /dev/null +++ b/src/data/mappings/the-detective-is-already-dead.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 128712, + "anilistMangaId": 114202, + "title": "The Detective Is Already Dead", + "sourceNotes": "Source is nigozyu's light novel (AniList id 114202, format NOVEL, ongoing). Media Factory has published 13 volumes under MF Bunko J as of mid-2026 (vol 1 in Nov 2019; vol 14 announced). A separate manga adaptation exists (id 119752, 29 ch, finished) but it is a minor early-arc side adaptation that ends far short of the anime, so this maps by LIGHT NOVEL VOLUME numbers instead — the `chapters` tuples below hold LN VOLUME numbers, NOT chapter numbers (AniList lists no chapter count). The 2021 TV anime (id 128712, 12 eps, single cour) adapts LN vols 1-2, but does so NON-LINEARLY: per the community/Wikipedia breakdown, the first part of ep 1, eps 2-4, ep 10 and parts of eps 11-12 cover vol 1, while the second part of ep 1, eps 5-9 and parts of eps 11-12 cover vol 2. Because the two volumes are interwoven across the cour rather than run in sequence, the adapted span is given as a single episodes[1,12]→vols[1,2] block. A Season 2 (id 152677) is scheduled but is a separate AniList entry not included here. No theatrical films.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 2], + "arc": "Siesta, SPES & the Hijacking — the pair's three years together and Siesta's death, through the Nagisa/Hel confrontation (S1; LN vols 1-2, adapted non-linearly)" + }, + { + "chapters": [3, 13], + "arc": "Post-Siesta mysteries: Nagisa as the new detective and the wider SPES/Sinner conflict (LN vols 3-13, unadapted by this anime)" + } + ] +} From 8d7e9b37a1a330e2b78ef3967c010dfbebacfd9b Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:15 -0400 Subject: [PATCH 024/100] KSN: add `aho-girl.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–12 ↔ chapters 1–155 - anime `98251` → manga `77102` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/aho-girl.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/aho-girl.json diff --git a/src/data/index.ts b/src/data/index.ts index 64174f3..39a26c4 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -329,6 +329,7 @@ import strikeTheBlood from "@/data/mappings/strike-the-blood.json"; import natsumeYuujinchou from "@/data/mappings/natsume-yuujinchou.json"; import makeineTooManyLosingHeroines from "@/data/mappings/makeine-too-many-losing-heroines.json"; import theDetectiveIsAlreadyDead from "@/data/mappings/the-detective-is-already-dead.json"; +import ahoGirl from "@/data/mappings/aho-girl.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -727,6 +728,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ natsumeYuujinchou, makeineTooManyLosingHeroines, theDetectiveIsAlreadyDead, + ahoGirl, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/aho-girl.json b/src/data/mappings/aho-girl.json new file mode 100644 index 0000000..59530ad --- /dev/null +++ b/src/data/mappings/aho-girl.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 98251, + "anilistMangaId": 77102, + "title": "AHO-GIRL", + "sourceNotes": "Single-cour 12-episode TV_SHORT (Diomedéa, 2017), ~15 min episodes; anilistAnimeId 98251 is the only season. Sourced from the completed 4-koma-style gag manga (AniList 77102), collected in 12 tankobon; AniList counts 155 chapters (split/extra chapters), while Wikipedia lists the run ending at ch. 130 — chapter numbering is fuzzy on this title. This is episodic gag comedy with no real story arcs, and the anime adapts chapters NON-sequentially as a \"best-of\": it pulls scattered gags from roughly ch. 1-85 (furthest adapted is ch. 85.5, Dog's walk in ep. 11), so per-episode chapter ranges cannot be pinned down. Continue-reading guides tell anime finishers to start at Vol. 6 / ch. 86. Chapter ranges below are approximate. No theatrical films exist.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 85], + "arc": "Yoshiko & A-kun (episodic gags)" + }, + { + "chapters": [86, 155], + "arc": "Remaining manga chapters (unadapted)" + } + ] +} From 9dc05ec91d12baeade7d9c2f43eb85f8278cdd52 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:18 -0400 Subject: [PATCH 025/100] KSN: add `hidden-dungeon.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–111 - anime `118375` → manga `103850` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/hidden-dungeon.json | 32 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/hidden-dungeon.json diff --git a/src/data/index.ts b/src/data/index.ts index 39a26c4..af7e537 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -330,6 +330,7 @@ import natsumeYuujinchou from "@/data/mappings/natsume-yuujinchou.json"; import makeineTooManyLosingHeroines from "@/data/mappings/makeine-too-many-losing-heroines.json"; import theDetectiveIsAlreadyDead from "@/data/mappings/the-detective-is-already-dead.json"; import ahoGirl from "@/data/mappings/aho-girl.json"; +import hiddenDungeon from "@/data/mappings/hidden-dungeon.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -729,6 +730,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ makeineTooManyLosingHeroines, theDetectiveIsAlreadyDead, ahoGirl, + hiddenDungeon, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/hidden-dungeon.json b/src/data/mappings/hidden-dungeon.json new file mode 100644 index 0000000..0f2f5cc --- /dev/null +++ b/src/data/mappings/hidden-dungeon.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 118375, + "anilistMangaId": 103850, + "title": "The Hidden Dungeon Only I Can Enter", + "sourceNotes": "Single 12-episode season (2021); episodes are non-cumulative. Based on Meguru Seto's light novel, but mapped against the Tomoyuki Hino manga (AniList id 103850), the source community guides use for episode-to-chapter tracking; the LN itself has no per-chapter numbering. The anime adapts manga chapters 1-38 (the end of Volume 5, the Phantom/Olivia arc), skipping a handful of chapters (12, 16, 24-25, 36) along the way, so ranges are approximate and volume-anchored. Manga complete at 111 chapters per AniList (Vol 1 = ch 1-7, Vol 2 = ch 8-14, Vol 3 = ch 15-22, Vol 4 ~ch 23-30, Vol 5 ~ch 31-38). Everything past ch 38 is unadapted. No theatrical films.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 7], + "arc": "Hidden Dungeon & Hero Academy" + }, + { + "episodes": [3, 6], + "chapters": [8, 22], + "arc": "Maria's Curse" + }, + { + "episodes": [7, 10], + "chapters": [23, 30], + "arc": "Academy Life & the Dryad" + }, + { + "episodes": [11, 12], + "chapters": [31, 38], + "arc": "The Phantom / Olivia's Liberation" + }, + { + "chapters": [39, 111], + "arc": "Beyond the Anime (unadapted manga)" + } + ] +} From 5154cf14f535e538a4ba5e34b21dcab6170f43b5 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:21 -0400 Subject: [PATCH 026/100] KSN: add `100-girlfriends.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 12 arcs covering episodes 1–24 ↔ chapters 1–250 - anime `162694` → manga `114416` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/100-girlfriends.json | 66 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/data/mappings/100-girlfriends.json diff --git a/src/data/index.ts b/src/data/index.ts index af7e537..9c8e62c 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -331,6 +331,7 @@ import makeineTooManyLosingHeroines from "@/data/mappings/makeine-too-many-losin import theDetectiveIsAlreadyDead from "@/data/mappings/the-detective-is-already-dead.json"; import ahoGirl from "@/data/mappings/aho-girl.json"; import hiddenDungeon from "@/data/mappings/hidden-dungeon.json"; +import hundredGirlfriends from "@/data/mappings/100-girlfriends.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -731,6 +732,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ theDetectiveIsAlreadyDead, ahoGirl, hiddenDungeon, + hundredGirlfriends, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/100-girlfriends.json b/src/data/mappings/100-girlfriends.json new file mode 100644 index 0000000..daab90f --- /dev/null +++ b/src/data/mappings/100-girlfriends.json @@ -0,0 +1,66 @@ +{ + "anilistAnimeId": 162694, + "anilistMangaId": 114416, + "title": "The 100 Girlfriends Who Really, Really, Really, Really, REALLY Love You", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 (12) = 24. Manga ongoing in Weekly Young Jump (approx. ch. 250 / 25 volumes as of mid-2026; AniList reports null chapter count). S1 adapts ch. 1-22 (continue at Vol. 3 ch. 23); S2 adapts ch. 23-50 (continue at Vol. 7 ch. 51); zero filler. This is a gag romcom structured around introducing one soulmate at a time, so arcs are named for the girlfriend introduced. Girlfriend-intro chapters are anchored where known (Hakari ch.1, Karane ch.2, Shizuka ch.3, Kurumi ch.24, Mei ch.30, Meme ch.45) and volume boundaries (V4 24-32, V5 33-41, V6 42-50, V7 51-59); intermediate episode/chapter splits are approximate. Season 3 premiered July 2026 and is not yet mapped; post-S2 chapters are listed source-only.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 4], + "arc": "Hakari Hanazono & Karane Inda" + }, + { + "episodes": [3, 4], + "chapters": [5, 7], + "arc": "Shizuka Yoshimoto" + }, + { + "episodes": [5, 6], + "chapters": [8, 10], + "arc": "Nano Eiai" + }, + { + "episodes": [7, 9], + "chapters": [11, 16], + "arc": "Kusuri Yakuzen" + }, + { + "episodes": [10, 12], + "chapters": [17, 22], + "arc": "Hahari Hanazono" + }, + { + "episodes": [13, 15], + "chapters": [23, 29], + "arc": "Kurumi Haraga" + }, + { + "episodes": [16, 17], + "chapters": [30, 35], + "arc": "Mei Meido" + }, + { + "episodes": [18, 20], + "chapters": [36, 40], + "arc": "Iku Sutou" + }, + { + "episodes": [21, 22], + "chapters": [41, 44], + "arc": "Mimimi Utsukushisugi" + }, + { + "episodes": [23, 24], + "chapters": [45, 50], + "arc": "Meme Kakure" + }, + { + "chapters": [51, 59], + "arc": "Chiyo & Naddy (Vol. 7)" + }, + { + "chapters": [60, 250], + "arc": "Ongoing manga (Vol. 8+)" + } + ] +} From 566c692b5f9a8407c851ce7e30493415cdea6723 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:24 -0400 Subject: [PATCH 027/100] KSN: add `kemono-jihen.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–12 ↔ chapters 1–105 - anime `114085` → manga `98466` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/kemono-jihen.json | 47 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/data/mappings/kemono-jihen.json diff --git a/src/data/index.ts b/src/data/index.ts index 9c8e62c..da556b1 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -332,6 +332,7 @@ import theDetectiveIsAlreadyDead from "@/data/mappings/the-detective-is-already- import ahoGirl from "@/data/mappings/aho-girl.json"; import hiddenDungeon from "@/data/mappings/hidden-dungeon.json"; import hundredGirlfriends from "@/data/mappings/100-girlfriends.json"; +import kemonoJihen from "@/data/mappings/kemono-jihen.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -733,6 +734,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ ahoGirl, hiddenDungeon, hundredGirlfriends, + kemonoJihen, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kemono-jihen.json b/src/data/mappings/kemono-jihen.json new file mode 100644 index 0000000..25083b9 --- /dev/null +++ b/src/data/mappings/kemono-jihen.json @@ -0,0 +1,47 @@ +{ + "anilistAnimeId": 114085, + "anilistMangaId": 98466, + "title": "Kemono Jihen", + "sourceNotes": "Single 12-episode TV season (2021, Ajia-do). Episodes are single-season, so cumulative episode numbers equal broadcast numbers. The anime adapts manga chapters 1-21 at a fairly fast pace (not panel-by-panel); episode 9 also wraps the brief 2-chapter Intermission Arc (ch 15-16), which is bundled into the Shiki Arc entry here. Source manga by Shou Aimoto, serialized in Jump Square, is ongoing: 24 tankobon volumes through ch. 105 as of December 2025. Chapter boundaries per the Kemono Jihen Fandom wiki's Story Arcs page. Everything from the Shikoku Arc (ch 22) onward is unadapted, so those entries are chapters-only; the final entry extends to the latest published chapter (105).", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 10], + "arc": "Introduction Arc" + }, + { + "episodes": [7, 9], + "chapters": [11, 16], + "arc": "Shiki Arc" + }, + { + "episodes": [10, 12], + "chapters": [17, 21], + "arc": "Snow Village Arc" + }, + { + "chapters": [22, 27], + "arc": "Shikoku Arc" + }, + { + "chapters": [28, 34], + "arc": "Shimane-Amagafuchi Arc" + }, + { + "chapters": [35, 43], + "arc": "Ogreham Factory Arc" + }, + { + "chapters": [44, 58], + "arc": "Gourd Training Arc" + }, + { + "chapters": [59, 79], + "arc": "Kyoto Arc" + }, + { + "chapters": [80, 105], + "arc": "Time Skip Arc" + } + ] +} From 5782ac9f8c2682749f7b735d7a958b5ec806f3cc Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:28 -0400 Subject: [PATCH 028/100] KSN: add `aharen-san-wa-hakarenai.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–24 ↔ chapters 1–167 - anime `137281` → manga `98686` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/aharen-san-wa-hakarenai.json | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/data/mappings/aharen-san-wa-hakarenai.json diff --git a/src/data/index.ts b/src/data/index.ts index da556b1..8e4eaed 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -333,6 +333,7 @@ import ahoGirl from "@/data/mappings/aho-girl.json"; import hiddenDungeon from "@/data/mappings/hidden-dungeon.json"; import hundredGirlfriends from "@/data/mappings/100-girlfriends.json"; import kemonoJihen from "@/data/mappings/kemono-jihen.json"; +import aharenSanWaHakarenai from "@/data/mappings/aharen-san-wa-hakarenai.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -735,6 +736,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ hiddenDungeon, hundredGirlfriends, kemonoJihen, + aharenSanWaHakarenai, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/aharen-san-wa-hakarenai.json b/src/data/mappings/aharen-san-wa-hakarenai.json new file mode 100644 index 0000000..1c6edb0 --- /dev/null +++ b/src/data/mappings/aharen-san-wa-hakarenai.json @@ -0,0 +1,18 @@ +{ + "anilistAnimeId": 137281, + "anilistMangaId": 98686, + "title": "Aharen-san wa Hakarenai", + "sourceNotes": "Source is Asato Mizu's manga (AniList 98686), complete at 167 chapters across 17 volumes. Cumulative episodes across S1 (12) + S2 (12) = 24. This is an episodic gag/romantic-comedy manga with no canonical named story arcs, so ranges are grouped by season/cumulative-chapter blocks rather than plot arcs. Season 1 (ep 1-12) adapted ch 1-67 (through vol 7); Season 2 (ep 13-24) adapted ch 68-167, running through the manga's finale (which covers the flash-forward marriage epilogue). Roughly 5-6 chapters per episode in S1 and ~8 per episode in S2; per-episode boundaries are approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 67], + "arc": "Season 1" + }, + { + "episodes": [13, 24], + "chapters": [68, 167], + "arc": "Season 2" + } + ] +} From 872686fbfbcd29aef07aaf910ed5697e859d6237 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:31 -0400 Subject: [PATCH 029/100] KSN: add `tanaka-kun-is-always-listless.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 13 arcs covering episodes 1–12 ↔ chapters 1–140 - anime `21495` → manga `85898` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../tanaka-kun-is-always-listless.json | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/data/mappings/tanaka-kun-is-always-listless.json diff --git a/src/data/index.ts b/src/data/index.ts index 8e4eaed..927c447 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -334,6 +334,7 @@ import hiddenDungeon from "@/data/mappings/hidden-dungeon.json"; import hundredGirlfriends from "@/data/mappings/100-girlfriends.json"; import kemonoJihen from "@/data/mappings/kemono-jihen.json"; import aharenSanWaHakarenai from "@/data/mappings/aharen-san-wa-hakarenai.json"; +import tanakaKunIsAlwaysListless from "@/data/mappings/tanaka-kun-is-always-listless.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -737,6 +738,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ hundredGirlfriends, kemonoJihen, aharenSanWaHakarenai, + tanakaKunIsAlwaysListless, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/tanaka-kun-is-always-listless.json b/src/data/mappings/tanaka-kun-is-always-listless.json new file mode 100644 index 0000000..970864d --- /dev/null +++ b/src/data/mappings/tanaka-kun-is-always-listless.json @@ -0,0 +1,72 @@ +{ + "anilistAnimeId": 21495, + "anilistMangaId": 85898, + "title": "Tanaka-kun is Always Listless", + "sourceNotes": "Single 12-episode TV season (2016) adapting the manga by Nozomi Uda. Manga complete at 140 chapters (13 volumes plus a 13.5 supplement), serialized 2013-2019 on Gangan Online. This is a plotless, episodic slice-of-life comedy with NO named story arcs; the anime cherry-picks and partially adapts chapters, jumping around and skipping heavily, but overall draws from roughly chapters 1-40. Chapter ranges below are approximate, using the official episode titles as segment labels and dividing the adapted material proportionally (~3 chapters/episode) rather than as exact boundaries. The final entry is a chapters-only tail covering the large unadapted remainder of the manga.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 4], + "arc": "Tanaka-kun and Ohta-kun" + }, + { + "episodes": [2, 2], + "chapters": [5, 7], + "arc": "Apprenticeship Application" + }, + { + "episodes": [3, 3], + "chapters": [8, 11], + "arc": "Girl of Contrast, Echizen-san" + }, + { + "episodes": [4, 4], + "chapters": [12, 14], + "arc": "Shiraishi-san's Secret" + }, + { + "episodes": [5, 5], + "chapters": [15, 17], + "arc": "Tanaka-kun's Day" + }, + { + "episodes": [6, 6], + "chapters": [18, 20], + "arc": "The Sick Tanaka-kun" + }, + { + "episodes": [7, 7], + "chapters": [21, 24], + "arc": "Tanaka-kun's Valentine" + }, + { + "episodes": [8, 8], + "chapters": [25, 27], + "arc": "Ohta-kun's Ordeal" + }, + { + "episodes": [9, 9], + "chapters": [28, 31], + "arc": "Welcome to Wac" + }, + { + "episodes": [10, 10], + "chapters": [32, 34], + "arc": "Tanaka-kun's Summer" + }, + { + "episodes": [11, 11], + "chapters": [35, 37], + "arc": "Tanaka-kun's Culture Festival" + }, + { + "episodes": [12, 12], + "chapters": [38, 40], + "arc": "Tanaka-kun's Happiness" + }, + { + "chapters": [41, 140], + "arc": "Unadapted manga chapters" + } + ] +} From b9d25c46d4da6789c13106d5f46a87f3ba1c56e3 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:34 -0400 Subject: [PATCH 030/100] KSN: add `how-heavy-dumbbells.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–200 - anime `107226` → manga `97626` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/how-heavy-dumbbells.json | 32 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/how-heavy-dumbbells.json diff --git a/src/data/index.ts b/src/data/index.ts index 927c447..91c9a33 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -335,6 +335,7 @@ import hundredGirlfriends from "@/data/mappings/100-girlfriends.json"; import kemonoJihen from "@/data/mappings/kemono-jihen.json"; import aharenSanWaHakarenai from "@/data/mappings/aharen-san-wa-hakarenai.json"; import tanakaKunIsAlwaysListless from "@/data/mappings/tanaka-kun-is-always-listless.json"; +import howHeavyDumbbells from "@/data/mappings/how-heavy-dumbbells.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -739,6 +740,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ kemonoJihen, aharenSanWaHakarenai, tanakaKunIsAlwaysListless, + howHeavyDumbbells, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/how-heavy-dumbbells.json b/src/data/mappings/how-heavy-dumbbells.json new file mode 100644 index 0000000..9a53efb --- /dev/null +++ b/src/data/mappings/how-heavy-dumbbells.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 107226, + "anilistMangaId": 97626, + "title": "How Heavy Are the Dumbbells You Lift?", + "sourceNotes": "Single 12-episode TV season (2019, Doga Kobo). Source is Yabako Sandrovich & MAAM's ongoing fitness-comedy manga (id 97626), serialized on Ura Sunday / MangaONE since 2016 and still RELEASING (AniList lists no chapter/volume totals; the Japanese serial is past ch. 189 as of late 2024, ~200 and counting). The show is an episodic gag/how-to-train comedy with no continuous story arcs — each episode strings together several short chapters and ends on a workout-instruction segment — so it adapts the early manga roughly in publication order. Per multiple episode guides the anime covers up to chapter 54 (episode 12 = chapters 52-54); readers are told to continue from chapter 55. Chapter ranges below are coarse ~4-5-chapters-per-episode approximations. No theatrical films exist (only a 2-episode \"Silverman Gym Intense Training Course\" special), so no movies are listed.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 13], + "arc": "Hibiki joins Silverman Gym & meets trainer Machio (approx.)" + }, + { + "episodes": [4, 6], + "chapters": [14, 27], + "arc": "Building the cast — Gina, boxing, and gym regulars (approx.)" + }, + { + "episodes": [7, 9], + "chapters": [28, 40], + "arc": "Summer, sports and escalating training antics (approx.)" + }, + { + "episodes": [10, 12], + "chapters": [41, 54], + "arc": "Muscle Beach finale & full-body workout send-off (approx.)" + }, + { + "chapters": [55, 200], + "arc": "Later gym vignettes — manga only, ongoing (approx.)" + } + ] +} From 44a8848d01c8c6b2b35037dca20afb1c5ed62d03 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:38 -0400 Subject: [PATCH 031/100] KSN: add `rosario-vampire.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–13 ↔ chapters 1–40 - anime `2993` → manga `30894` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/rosario-vampire.json | 32 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/rosario-vampire.json diff --git a/src/data/index.ts b/src/data/index.ts index 91c9a33..c078d5f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -336,6 +336,7 @@ import kemonoJihen from "@/data/mappings/kemono-jihen.json"; import aharenSanWaHakarenai from "@/data/mappings/aharen-san-wa-hakarenai.json"; import tanakaKunIsAlwaysListless from "@/data/mappings/tanaka-kun-is-always-listless.json"; import howHeavyDumbbells from "@/data/mappings/how-heavy-dumbbells.json"; +import rosarioVampire from "@/data/mappings/rosario-vampire.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -741,6 +742,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ aharenSanWaHakarenai, tanakaKunIsAlwaysListless, howHeavyDumbbells, + rosarioVampire, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/rosario-vampire.json b/src/data/mappings/rosario-vampire.json new file mode 100644 index 0000000..287baf7 --- /dev/null +++ b/src/data/mappings/rosario-vampire.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 2993, + "anilistMangaId": 30894, + "title": "Rosario + Vampire", + "sourceNotes": "Source is the first Rosario+Vampire manga (\"Season I\", AniList 30894), complete at 40 chapters / 10 volumes; the story then continues in a separate sequel manga, Rosario+Vampire: Season II (AniList 33403, 67 more chapters, completed 2014), which the anime never reaches. The Gonzo TV adaptation is only 26 episodes across two 13-episode cours (S1: Rosario+Vampire, 2008; S2: Capu2, 2008). S1 loosely adapts roughly chapters 1-20 of the manga but freely REORDERS the arcs and inserts original filler, so chapter ranges here reflect the arc each episode block draws from, not strict linear progression (e.g. Mizore ch19-20 airs before the Witch's Knoll and Kuyo arcs). Episode 8 (\"Mathematics\") is largely anime-original. Capu2 (cumulative episodes 14-26) is almost entirely anime-original / non-canon and adapts essentially no manga chapters, so it is not mapped; the manga's ghoul crisis and the whole of Season II remain unadapted. No theatrical films exist.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 8], + "arc": "Enrollment: Moka, Kurumu, Swim Club, Newspaper Club & Yukari" + }, + { + "episodes": [7, 8], + "chapters": [19, 20], + "arc": "Mizore the Snow Woman" + }, + { + "episodes": [9, 11], + "chapters": [13, 18], + "arc": "Summer & Witch's Knoll (Ruby)" + }, + { + "episodes": [12, 13], + "chapters": [9, 12], + "arc": "Public Safety Commission (Kuyo)" + }, + { + "chapters": [21, 40], + "arc": "Ghoul Crisis & Anti-Thesis onward (unadapted; continues in Season II manga)" + } + ] +} From fe868c45b902bdbba01ceaff39ac202137fe50f0 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:42 -0400 Subject: [PATCH 032/100] KSN: add `school-live.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–78 - anime `20754` → manga `85235` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/school-live.json | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/data/mappings/school-live.json diff --git a/src/data/index.ts b/src/data/index.ts index c078d5f..ad11720 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -337,6 +337,7 @@ import aharenSanWaHakarenai from "@/data/mappings/aharen-san-wa-hakarenai.json"; import tanakaKunIsAlwaysListless from "@/data/mappings/tanaka-kun-is-always-listless.json"; import howHeavyDumbbells from "@/data/mappings/how-heavy-dumbbells.json"; import rosarioVampire from "@/data/mappings/rosario-vampire.json"; +import schoolLive from "@/data/mappings/school-live.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -743,6 +744,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ tanakaKunIsAlwaysListless, howHeavyDumbbells, rosarioVampire, + schoolLive, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/school-live.json b/src/data/mappings/school-live.json new file mode 100644 index 0000000..24a0a29 --- /dev/null +++ b/src/data/mappings/school-live.json @@ -0,0 +1,26 @@ +{ + "anilistAnimeId": 20754, + "anilistMangaId": 85235, + "title": "SCHOOL-LIVE!", + "sourceNotes": "Single 12-episode TV season (2015, Lerche) adapting Norimitsu Kaihou & Sadoru Chiba's School-Live! manga (AniList id 85235), which is complete at 78 chapters across 12 volumes. The anime covers only the school-set portion — the manga's volumes 1-5 (chapters 1-31), ending precisely at Volume 5's final chapter \"Graduation\" (ch 31) as the School Living Club leaves Megurigaoka High for the university on Megumi's map. IMPORTANT CAVEAT: the anime heavily REORDERS the manga's non-linear, flashback-driven chapters into a more chronological mystery-reveal structure (e.g., ch 19 \"Scar\" surfaces late as ep 11, and Miki/Kurumi backstories are redistributed), so per-episode chapter boundaries are approximate — the two anime entries below reflect overall volume coverage, not a 1:1 chapter order. Volume boundaries: v1 ch1-6, v2 7-12, v3 13-18, v4 19-25, v5 26-31, v6 32-37, v7 38-43, v8 44-49, v9 50-55, v10 56-63, v11 64-70, v12 71-78. Everything from ch 32 onward (the journey to and survival at the Randall Corporation university, then the final arc) is unadapted. The only feature film is a 2019 live-action adaptation (alternate continuity, non-animation) and is excluded; no theatrical anime films exist, so no movies are listed.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 18], + "arc": "School Living Club — daily life and the truth (Miki joins; Megu-nee revealed as delusion) — vols 1-3, anime reorders these chapters" + }, + { + "episodes": [7, 12], + "chapters": [19, 31], + "arc": "The hidden shelter, the infection crisis, and Graduation — vols 4-5, anime reorders these chapters" + }, + { + "chapters": [32, 49], + "arc": "Randall Corporation university — setting off and the campus survivors (manga only) — vols 6-8" + }, + { + "chapters": [50, 78], + "arc": "Final arc — the outbreak's origin, the cure, and the club's last days (manga only) — vols 9-12" + } + ] +} From ba2ac72d6b1c4dd21c72504930c7f3aaae289431 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:45 -0400 Subject: [PATCH 033/100] KSN: add `ping-pong-the-animation.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–11 ↔ chapters 1–55 - anime `20607` → manga `35744` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/ping-pong-the-animation.json | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/ping-pong-the-animation.json diff --git a/src/data/index.ts b/src/data/index.ts index ad11720..445440a 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -338,6 +338,7 @@ import tanakaKunIsAlwaysListless from "@/data/mappings/tanaka-kun-is-always-list import howHeavyDumbbells from "@/data/mappings/how-heavy-dumbbells.json"; import rosarioVampire from "@/data/mappings/rosario-vampire.json"; import schoolLive from "@/data/mappings/school-live.json"; +import pingPongTheAnimation from "@/data/mappings/ping-pong-the-animation.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -745,6 +746,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ howHeavyDumbbells, rosarioVampire, schoolLive, + pingPongTheAnimation, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/ping-pong-the-animation.json b/src/data/mappings/ping-pong-the-animation.json new file mode 100644 index 0000000..e99faab --- /dev/null +++ b/src/data/mappings/ping-pong-the-animation.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 20607, + "anilistMangaId": 35744, + "title": "Ping Pong the Animation", + "sourceNotes": "Single-cour 11-episode Masaaki Yuasa adaptation of Taiyo Matsumoto's Ping Pong manga (complete at 55 chapters across 5 volumes, exactly 11 chapters per volume). The anime is a faithful, near-complete adaptation of the entire manga, so ranges track the source's 5 volumes at roughly one volume per two episodes; chapter boundaries are approximate since the show reorders some beats within its continuous single-story narrative (no named shounen-style arcs — divisions follow the two Inter-High tournaments). No animated theatrical films exist (the 2002 live-action film is excluded).", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 11], + "arc": "Introduction / Kong Wenge Arrives" + }, + { + "episodes": [3, 4], + "chapters": [12, 22], + "arc": "First Inter-High Preliminaries" + }, + { + "episodes": [5, 6], + "chapters": [23, 33], + "arc": "Aftermath / Peco's Fall, Smile's Rise" + }, + { + "episodes": [7, 8], + "chapters": [34, 44], + "arc": "Peco's Return / Training" + }, + { + "episodes": [9, 11], + "chapters": [45, 55], + "arc": "Second Inter-High Tournament / Final" + } + ] +} From 8324e539f668fe42fae4bcc8b844d11867804922 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:48 -0400 Subject: [PATCH 034/100] KSN: add `gosick.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 10 arcs covering episodes 1–24 ↔ chapters 1–9 - anime `8425` → manga `31313` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/gosick.json | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/data/mappings/gosick.json diff --git a/src/data/index.ts b/src/data/index.ts index 445440a..e3f1081 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -339,6 +339,7 @@ import howHeavyDumbbells from "@/data/mappings/how-heavy-dumbbells.json"; import rosarioVampire from "@/data/mappings/rosario-vampire.json"; import schoolLive from "@/data/mappings/school-live.json"; import pingPongTheAnimation from "@/data/mappings/ping-pong-the-animation.json"; +import gosick from "@/data/mappings/gosick.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -747,6 +748,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ rosarioVampire, schoolLive, pingPongTheAnimation, + gosick, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/gosick.json b/src/data/mappings/gosick.json new file mode 100644 index 0000000..3b50c85 --- /dev/null +++ b/src/data/mappings/gosick.json @@ -0,0 +1,58 @@ +{ + "anilistAnimeId": 8425, + "anilistMangaId": 31313, + "title": "Gosick", + "sourceNotes": "Source is Kazuki Sakuraba's LIGHT NOVEL (AniList id 31313, format NOVEL); the minor 29-chapter manga adaptation (id 36248) is deliberately ignored. IMPORTANT: the units below are LN VOLUME numbers, not chapters - AniList exposes no count for the novel. The main series is 9 volumes (I-VII plus VIII split into VIII(1) and VIII(2), counted here as vols 8-9); four additional \"GosickS\" short-story collections sit between the main volumes. The single 24-episode Bones anime (2011) adapts main volumes 1-8 in near-linear order and weaves GosickS side stories into the interstitial episodes (eps 4-5 Cuiaran/false Avril; eps 11-12 Jacqueline's past and Kujo's flashback). LN complete at 9 main volumes (VIII(2), Jul 2011); the anime covers the whole main story through the \"Twilight of the Gods\" finale, so there is no meaningful unadapted tail. Per-arc boundaries are approximate, sourced from Wikipedia's episode list and fandom guides. No theatrical films exist.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "The Queen Berry (LN vol 1)" + }, + { + "episodes": [4, 5], + "chapters": [1, 1], + "arc": "Cuiaran / the false Avril (GosickS side-story material, woven in)" + }, + { + "episodes": [6, 8], + "chapters": [2, 2], + "arc": "The Crime That Has No Name / Village of the Grey Wolves (LN vol 2)" + }, + { + "episodes": [9, 10], + "chapters": [3, 3], + "arc": "Beneath the Blue Rose (LN vol 3)" + }, + { + "episodes": [11, 12], + "chapters": [4, 4], + "arc": "GosickS interludes - Jacqueline's past & Kujo's flashback (side stories, woven in)" + }, + { + "episodes": [13, 15], + "chapters": [4, 4], + "arc": "A Fool Represents the Case / Leviathan (LN vol 4)" + }, + { + "episodes": [16, 17], + "chapters": [5, 5], + "arc": "Beelzebub's Skull (LN vol 5)" + }, + { + "episodes": [18, 18], + "chapters": [6, 6], + "arc": "Night of the Masquerade / the return train (LN vol 6)" + }, + { + "episodes": [19, 21], + "chapters": [7, 7], + "arc": "The Rose-coloured Life / Coco Rose (LN vol 7)" + }, + { + "episodes": [22, 24], + "chapters": [8, 9], + "arc": "Twilight of the Gods (LN vol 8, published as VIII(1) & VIII(2))" + } + ] +} From 8c6e197cc1d0d79138d13fe7450fb13e5ffb17e7 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:51 -0400 Subject: [PATCH 035/100] KSN: add `twin-star-exorcists.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–20 ↔ chapters 1–142 - anime `21499` → manga `85247` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/twin-star-exorcists.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/twin-star-exorcists.json diff --git a/src/data/index.ts b/src/data/index.ts index e3f1081..26a63d4 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -340,6 +340,7 @@ import rosarioVampire from "@/data/mappings/rosario-vampire.json"; import schoolLive from "@/data/mappings/school-live.json"; import pingPongTheAnimation from "@/data/mappings/ping-pong-the-animation.json"; import gosick from "@/data/mappings/gosick.json"; +import twinStarExorcists from "@/data/mappings/twin-star-exorcists.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -749,6 +750,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ schoolLive, pingPongTheAnimation, gosick, + twinStarExorcists, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/twin-star-exorcists.json b/src/data/mappings/twin-star-exorcists.json new file mode 100644 index 0000000..1b5b1f6 --- /dev/null +++ b/src/data/mappings/twin-star-exorcists.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 21499, + "anilistMangaId": 85247, + "title": "Twin Star Exorcists", + "sourceNotes": "Single 50-episode TV series (2016-2017), so episodes are not cumulative across seasons. The anime only adapts manga chapters 1-15 (roughly volumes 1-5) and does so loosely across episodes 1-20, with heavy anime-original padding interspersed (episodes 5 and 10-16 are filler); per the community canon guide episodes 1-9 cover chapters 1-10 and episodes 17-20 cover chapters 10-15. From episode 21 onward (eps 21-50) the anime abandons the manga entirely and tells a wholly original story, so it cannot be mapped to chapters. The manga is complete: AniList lists 142 chapters, while Wikipedia counts 134 numbered chapters across 35 tankobon volumes (Jump Square, 2013-2024). Everything from chapter 16 to the end is unadapted by the anime; a precise per-arc chapter breakdown of that unadapted remainder is not reliably documented, so it is given as a single chapters-only tail entry.", + "mappings": [ + { + "episodes": [1, 9], + "chapters": [1, 10], + "arc": "Meeting & the Hiinatsuki Tragedy" + }, + { + "episodes": [17, 20], + "chapters": [11, 15], + "arc": "Yuto & Basara Confrontation" + }, + { + "chapters": [16, 142], + "arc": "Unadapted manga (post-anime divergence)" + } + ] +} From 80f5c587fa8afe339444ea5fcdf2e15ceef4bba0 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:54 -0400 Subject: [PATCH 036/100] KSN: add `banished-from-the-heros-party.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–25 ↔ chapters 1–15 - anime `126213` → manga `104475` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../banished-from-the-heros-party.json | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/data/mappings/banished-from-the-heros-party.json diff --git a/src/data/index.ts b/src/data/index.ts index 26a63d4..5a7f699 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -341,6 +341,7 @@ import schoolLive from "@/data/mappings/school-live.json"; import pingPongTheAnimation from "@/data/mappings/ping-pong-the-animation.json"; import gosick from "@/data/mappings/gosick.json"; import twinStarExorcists from "@/data/mappings/twin-star-exorcists.json"; +import banishedFromTheHerosParty from "@/data/mappings/banished-from-the-heros-party.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -751,6 +752,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ pingPongTheAnimation, gosick, twinStarExorcists, + banishedFromTheHerosParty, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/banished-from-the-heros-party.json b/src/data/mappings/banished-from-the-heros-party.json new file mode 100644 index 0000000..ed7526d --- /dev/null +++ b/src/data/mappings/banished-from-the-heros-party.json @@ -0,0 +1,51 @@ +{ + "anilistAnimeId": 126213, + "anilistMangaId": 104475, + "title": "Banished from the Hero's Party, I Decided to Live a Quiet Life in the Countryside", + "sourceNotes": "Light-novel-based; ranges are by LN VOLUME (the source, AniList id 104475), not manga chapters — AniList lists no chapter count for the source and the community episode↔source guides all track volumes. The \"chapters\" fields therefore hold volume numbers. Cumulative episodes across S1 (13) + S2 (12) = 25. S1 adapts volumes 1-4 (condensing four volumes by trimming action to keep the slow-life tone). S2 adapts volumes 5, 8 and 9, deliberately SKIPPING volumes 6 and 7 (so after S2 the LN resumes at volume 10). Within-season per-volume episode boundaries are approximate. LN complete at 15 volumes (final vol. released July 2025); volumes 10-15 are unadapted.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "Red's Apothecary in Zoltan (Vol. 1)" + }, + { + "episodes": [5, 8], + "chapters": [2, 2], + "arc": "Rit and the Bighawk Incident (Vol. 2)" + }, + { + "episodes": [9, 11], + "chapters": [3, 3], + "arc": "Ruti and the Devil's Blessing (Vol. 3)" + }, + { + "episodes": [12, 13], + "chapters": [4, 4], + "arc": "Confrontation with Ares (Vol. 4)" + }, + { + "episodes": [14, 17], + "chapters": [5, 5], + "arc": "The New Hero Van (Vol. 5)" + }, + { + "chapters": [6, 7], + "arc": "Skipped by the anime (Vol. 6-7)" + }, + { + "episodes": [18, 21], + "chapters": [8, 8], + "arc": "Zoltan in Turmoil (Vol. 8)" + }, + { + "episodes": [22, 25], + "chapters": [9, 9], + "arc": "The Contract Demon (Vol. 9)" + }, + { + "chapters": [10, 15], + "arc": "Unadapted (Vol. 10-15)" + } + ] +} From 3e26aca0da786f8cc178ebcb947162b96bcbd522 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:16:57 -0400 Subject: [PATCH 037/100] KSN: add `wrong-way-to-use-healing-magic.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–13 ↔ chapters 1–12 - anime `137908` → manga `96942` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../wrong-way-to-use-healing-magic.json | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/wrong-way-to-use-healing-magic.json diff --git a/src/data/index.ts b/src/data/index.ts index 5a7f699..61f3a57 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -342,6 +342,7 @@ import pingPongTheAnimation from "@/data/mappings/ping-pong-the-animation.json"; import gosick from "@/data/mappings/gosick.json"; import twinStarExorcists from "@/data/mappings/twin-star-exorcists.json"; import banishedFromTheHerosParty from "@/data/mappings/banished-from-the-heros-party.json"; +import wrongWayToUseHealingMagic from "@/data/mappings/wrong-way-to-use-healing-magic.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -753,6 +754,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ gosick, twinStarExorcists, banishedFromTheHerosParty, + wrongWayToUseHealingMagic, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/wrong-way-to-use-healing-magic.json b/src/data/mappings/wrong-way-to-use-healing-magic.json new file mode 100644 index 0000000..c7053dc --- /dev/null +++ b/src/data/mappings/wrong-way-to-use-healing-magic.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 137908, + "anilistMangaId": 96942, + "title": "The Wrong Way to Use Healing Magic", + "sourceNotes": "Single-cour 13-episode 2024 TV anime (Studio Add / Shin-Ei). Source is Kurokata's light novel (AniList id 96942, NOVEL format), complete at 12 volumes (2016-2020). The separate Reki Kugayama manga adaptation (AniList id 99775) lags far behind the anime and AniList lists no chapter count for it, so this mapping uses LIGHT-NOVEL VOLUME numbers as the 'chapters' unit (same approach as arifureta.json / cheat-skill.json). Community episode-to-source guides confirm the anime adapts LN vols 1-2 and a reader resumes at vol 3. Vol 1 covers the otherworld summoning and the Rescue Team's hellish training; vol 2 covers Usato's first battle in the demon-army war, culminating in the Black Knight fight. Per-volume episode boundaries are approximate. A Season 2 has been announced (AniList id 179981, not yet released) and is not mapped here. No theatrical films.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "Otherworld Summoning & the Rescue Team's Training from Hell (LN vol 1)" + }, + { + "episodes": [5, 13], + "chapters": [2, 2], + "arc": "The Demon Lord's Army Invasion & the Black Knight (LN vol 2)" + }, + { + "chapters": [3, 12], + "arc": "Beyond the Anime (unadapted LN vols 3-12)" + } + ] +} From beb702395d9c425a32d5ac54cda5564ad49d2cb5 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:00 -0400 Subject: [PATCH 038/100] KSN: add `problem-children.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–10 ↔ chapters 1–12 - anime `15315` → manga `75855` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/problem-children.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/problem-children.json diff --git a/src/data/index.ts b/src/data/index.ts index 61f3a57..6a71787 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -343,6 +343,7 @@ import gosick from "@/data/mappings/gosick.json"; import twinStarExorcists from "@/data/mappings/twin-star-exorcists.json"; import banishedFromTheHerosParty from "@/data/mappings/banished-from-the-heros-party.json"; import wrongWayToUseHealingMagic from "@/data/mappings/wrong-way-to-use-healing-magic.json"; +import problemChildren from "@/data/mappings/problem-children.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -755,6 +756,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ twinStarExorcists, banishedFromTheHerosParty, wrongWayToUseHealingMagic, + problemChildren, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/problem-children.json b/src/data/mappings/problem-children.json new file mode 100644 index 0000000..795fbd9 --- /dev/null +++ b/src/data/mappings/problem-children.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 15315, + "anilistMangaId": 75855, + "title": "Problem Children Are Coming From Another World, Aren't They?", + "sourceNotes": "Single-cour anime, 10 episodes (Diomedea, 2013); no sequel seasons, so cumulative episodes = raw episodes. The source is Tarou Tatsunoko's light novel (AniList id 75855, format NOVEL, complete at 12 volumes / listed as 125 chapters). There is no manga used for episode-to-source guides, so this mapping uses LIGHT-NOVEL VOLUME numbers as the 'chapters' unit. The anime adapts LN volumes 1-2: eps 1-5 cover Volume 1 and eps 6-10 cover Volume 2 (confirmed by Wikipedia/fandom). Volumes 3-12 (including the Ouroboros Alliance, Three-Headed Dragon and later arcs) are unadapted; the story continues in the sequel LN series Last Embryo. Per-volume arc boundaries are approximate. A single OVA (\"The Hot Spring Fun Trip\", 2013) exists but is a non-theatrical bonus episode, so no films are listed.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 1], + "arc": "Yes! Black Rabbit Called You! — arrival in Little Garden, No Names community, Fores Garo Gift Game & Thousand Eyes, rescuing Leticia from Perseus (LN vol 1)" + }, + { + "episodes": [6, 10], + "chapters": [2, 2], + "arc": "Oh dear, a Declaration of War by a Demon Lord? — Salamandra's Fire Dragon Birth Festival, the Pied Piper of Hamelin and the Demon Lord Pest (LN vol 2)" + }, + { + "chapters": [3, 12], + "arc": "Dragon Summoning through the later arcs (Ouroboros Alliance, Three-Headed Dragon, etc.) — LN vols 3-12, unadapted (continued in Last Embryo)" + } + ] +} From da4d40b603340897a560169183991d3228fb055c Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:03 -0400 Subject: [PATCH 039/100] KSN: add `combatants-will-be-dispatched.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–7 - anime `116588` → manga `101809` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../combatants-will-be-dispatched.json | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/combatants-will-be-dispatched.json diff --git a/src/data/index.ts b/src/data/index.ts index 6a71787..8b492c7 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -344,6 +344,7 @@ import twinStarExorcists from "@/data/mappings/twin-star-exorcists.json"; import banishedFromTheHerosParty from "@/data/mappings/banished-from-the-heros-party.json"; import wrongWayToUseHealingMagic from "@/data/mappings/wrong-way-to-use-healing-magic.json"; import problemChildren from "@/data/mappings/problem-children.json"; +import combatantsWillBeDispatched from "@/data/mappings/combatants-will-be-dispatched.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -757,6 +758,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ banishedFromTheHerosParty, wrongWayToUseHealingMagic, problemChildren, + combatantsWillBeDispatched, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/combatants-will-be-dispatched.json b/src/data/mappings/combatants-will-be-dispatched.json new file mode 100644 index 0000000..3d602bf --- /dev/null +++ b/src/data/mappings/combatants-will-be-dispatched.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 116588, + "anilistMangaId": 101809, + "title": "Combatants Will Be Dispatched!", + "sourceNotes": "Single cour: one 12-episode season (2021), so episodes are not cumulative across seasons. The source is Natsume Akatsuki's light novel (AniList id 101809, NOVEL, status RELEASING — 7 volumes published through 2022, ongoing). AniList lists no chapter count for the LN and its Kadokawa manga adaptation (id 101808, 73 ch, FINISHED) is a side adaptation, so — following community \"where does the anime leave off\" guides that track LIGHT-NOVEL VOLUMES — this maps by LN VOLUME: the `chapters` tuples are volume numbers (1-7), NOT manga chapters. The anime adapts LN vols 1-3 at roughly one volume per four episodes and concludes at the end of vol 3, so a reader resumes at vol 4. Per-volume episode boundaries are approximate. No theatrical films or OVAs.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "Agent Six arrives / the Kingdom of Grace vs. the Demon Lord's Army (LN vol 1)" + }, + { + "episodes": [5, 8], + "chapters": [2, 2], + "arc": "Capturing the Tower of Duster & Heine of the Flames (LN vol 2)" + }, + { + "episodes": [9, 12], + "chapters": [3, 3], + "arc": "Fortifying the base / territory expansion & the Undead Festival (LN vol 3)" + }, + { + "chapters": [4, 7], + "arc": "Continued conquest of the planet (LN vols 4-7), unadapted" + } + ] +} From a958e5c536a53d20fea2165c56cfe40450c9e391 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:06 -0400 Subject: [PATCH 040/100] KSN: add `bakuman.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–75 ↔ chapters 1–176 - anime `7674` → manga `39711` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/bakuman.json | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/data/mappings/bakuman.json diff --git a/src/data/index.ts b/src/data/index.ts index 8b492c7..888f264 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -345,6 +345,7 @@ import banishedFromTheHerosParty from "@/data/mappings/banished-from-the-heros-p import wrongWayToUseHealingMagic from "@/data/mappings/wrong-way-to-use-healing-magic.json"; import problemChildren from "@/data/mappings/problem-children.json"; import combatantsWillBeDispatched from "@/data/mappings/combatants-will-be-dispatched.json"; +import bakuman from "@/data/mappings/bakuman.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -759,6 +760,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ wrongWayToUseHealingMagic, problemChildren, combatantsWillBeDispatched, + bakuman, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/bakuman.json b/src/data/mappings/bakuman.json new file mode 100644 index 0000000..4417dca --- /dev/null +++ b/src/data/mappings/bakuman.json @@ -0,0 +1,38 @@ +{ + "anilistAnimeId": 7674, + "anilistMangaId": 39711, + "title": "Bakuman.", + "sourceNotes": "Cumulative episodes across S1 (25) + S2 (25) + S3 (25) = 75. Source manga (AniList 39711) complete at 176 chapters / 20 volumes. Per the furansujapon anime-manga correspondence, Season 1 adapts ch 1-33, Season 2 ch 34-89, and Season 3 ch 90-176. Bakuman is a continuous narrative with no formal arc titles, so arcs here are named by the successive manga Ashirogi Muto create; internal chapter/episode boundaries are approximate and season-aligned. Confirmed anchors: Detective Trap (their first serialization) is cancelled at ch 53, and Reversi (final work) prep begins around ch 152-153 and runs to the finale at ch 176.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 16], + "arc": "Dreams and Reality" + }, + { + "episodes": [13, 25], + "chapters": [17, 33], + "arc": "Debut and Serialization Bid" + }, + { + "episodes": [26, 34], + "chapters": [34, 53], + "arc": "Detective Trap" + }, + { + "episodes": [35, 50], + "chapters": [54, 89], + "arc": "Run, Daihatsu Tanto!" + }, + { + "episodes": [51, 68], + "chapters": [90, 152], + "arc": "Perfect Crime Party (PCP)" + }, + { + "episodes": [69, 75], + "chapters": [153, 176], + "arc": "Reversi" + } + ] +} From 4bca3c7496c1b437eb6985994d23fa07a9387fda Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:09 -0400 Subject: [PATCH 041/100] KSN: add `konosuba-explosion.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–20 - anime `150075` → manga `100147` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/konosuba-explosion.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/konosuba-explosion.json diff --git a/src/data/index.ts b/src/data/index.ts index 888f264..bf9dd0b 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -346,6 +346,7 @@ import wrongWayToUseHealingMagic from "@/data/mappings/wrong-way-to-use-healing- import problemChildren from "@/data/mappings/problem-children.json"; import combatantsWillBeDispatched from "@/data/mappings/combatants-will-be-dispatched.json"; import bakuman from "@/data/mappings/bakuman.json"; +import konosubaExplosion from "@/data/mappings/konosuba-explosion.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -761,6 +762,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ problemChildren, combatantsWillBeDispatched, bakuman, + konosubaExplosion, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/konosuba-explosion.json b/src/data/mappings/konosuba-explosion.json new file mode 100644 index 0000000..9883112 --- /dev/null +++ b/src/data/mappings/konosuba-explosion.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 150075, + "anilistMangaId": 100147, + "title": "KONOSUBA -An Explosion on This Wonderful World!", + "sourceNotes": "Standalone Megumin-focused spin-off: a single 12-episode 2023 anime by studio Drive that adapts the complete 3-volume \"An Explosion on This Wonderful World!\" light novel trilogy by Natsume Akatsuki. Mapped to the light novel source (AniList NOVEL entry, 20 chapters, trilogy complete); ranges are by volume since the LN uses per-volume prologue/chapter/epilogue numbering, so chapter numbers are approximate. Vol 1 = eps 1-5 (ends on \"Prelude to Explosion Madness\"), Vol 2 = eps 6-9 (ep 9 covers Vol 2's final chapter, the Destroyer), Vol 3 = eps 10-12. Distinct from the main Konosuba TV series (mapped separately as konosuba); the Legend of Crimson movie belongs to that main series, not this spin-off.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 7], + "arc": "Light Novel Volume 1 (Crimson Demon Village / Magic Academy)" + }, + { + "episodes": [6, 9], + "chapters": [8, 14], + "arc": "Light Novel Volume 2 (City of Water / The Destroyer)" + }, + { + "episodes": [10, 12], + "chapters": [15, 20], + "arc": "Light Novel Volume 3 (Town for Beginners / Explosion)" + } + ] +} From ae5921026d6052daebe25372f0076977469f4093 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:11 -0400 Subject: [PATCH 042/100] KSN: add `talentless-nana.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 25 arcs covering episodes 1–13 ↔ chapters 1–121 - anime `117343` → manga `99536` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/talentless-nana.json | 114 +++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/data/mappings/talentless-nana.json diff --git a/src/data/index.ts b/src/data/index.ts index bf9dd0b..e288b4d 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -347,6 +347,7 @@ import problemChildren from "@/data/mappings/problem-children.json"; import combatantsWillBeDispatched from "@/data/mappings/combatants-will-be-dispatched.json"; import bakuman from "@/data/mappings/bakuman.json"; import konosubaExplosion from "@/data/mappings/konosuba-explosion.json"; +import talentlessNana from "@/data/mappings/talentless-nana.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -763,6 +764,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ combatantsWillBeDispatched, bakuman, konosubaExplosion, + talentlessNana, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/talentless-nana.json b/src/data/mappings/talentless-nana.json new file mode 100644 index 0000000..6b39b24 --- /dev/null +++ b/src/data/mappings/talentless-nana.json @@ -0,0 +1,114 @@ +{ + "anilistAnimeId": 117343, + "anilistMangaId": 99536, + "title": "Talentless Nana", + "sourceNotes": "Single-cour 13-episode anime (Fall 2020) adapting the Munou na Nana manga (source id 99536) chapters 1-28, through Volume 4 (finale \"Revival\" = Ch 28). Only one anime season, so episodes are not cumulative across seasons. The manga is essentially complete: after a May 2026 announcement it concludes at Chapter 121 on July 12, 2026 (final chapter count used here). Arc names come from the Munou na Nana fandom wiki \"Story Arcs\" page, which are community/fan-made labels rather than official titles; the anime's own episode titles (\"Time Traveler\", \"Necromancer\", \"The Invisible Blade\", etc.) align with these. Confirmed anchors: Necromancer = Ch 10-14 (ep 6-7), Poison Case = Ch 15-17 (ep 8), Unknown Student = Ch 18-20 (ep 9), anime ends at Ch 28 (ep 13). Episode boundaries within the island-introduction stretch (ep 1-5, Ch 1-9) are approximate. Post-Ch-97 arc labels are derived from chapter titles and are approximate. No qualifying theatrical films.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 5], + "arc": "Assassinating Students" + }, + { + "episodes": [3, 5], + "chapters": [6, 9], + "arc": "Future Photos" + }, + { + "episodes": [6, 7], + "chapters": [10, 14], + "arc": "Necromancer" + }, + { + "episodes": [8, 8], + "chapters": [15, 17], + "arc": "Poison Case" + }, + { + "episodes": [9, 9], + "chapters": [18, 20], + "arc": "Unknown Student" + }, + { + "episodes": [10, 13], + "chapters": [21, 28], + "arc": "The Invisible Blade (Ryuuji Ishii Murder Case)" + }, + { + "chapters": [29, 30], + "arc": "Ryuuji Ishii Murder Case (Conclusion)" + }, + { + "chapters": [31, 33], + "arc": "Military Forces" + }, + { + "chapters": [34, 38], + "arc": "Moe and Nana vs Hikaru Daichi" + }, + { + "chapters": [39, 48], + "arc": "Twin Sisters" + }, + { + "chapters": [49, 52], + "arc": "The Death of Hikaru Daichi" + }, + { + "chapters": [53, 54], + "arc": "After the Fall" + }, + { + "chapters": [55, 66], + "arc": "Daisuke Souma / Takeo Saijo Car Case" + }, + { + "chapters": [67, 68], + "arc": "The Downfall of the Talented" + }, + { + "chapters": [69, 71], + "arc": "Managed Camp" + }, + { + "chapters": [72, 76], + "arc": "Time Loop" + }, + { + "chapters": [77, 78], + "arc": "Rin and Kyouya's Past" + }, + { + "chapters": [79, 80], + "arc": "Rescue Team Arrives" + }, + { + "chapters": [81, 85], + "arc": "Shadow Boy Incident" + }, + { + "chapters": [86, 91], + "arc": "Nanao and Nana Final Showdown" + }, + { + "chapters": [92, 93], + "arc": "Monster Transitioning / Escape" + }, + { + "chapters": [94, 97], + "arc": "The Talented Civil War" + }, + { + "chapters": [98, 105], + "arc": "Hostage Negotiations & Telepathy" + }, + { + "chapters": [106, 113], + "arc": "Talentless vs Talentless" + }, + { + "chapters": [114, 121], + "arc": "Mind Reading (Final Arc)" + } + ] +} From 9da47296a47615067d94da5e01e8fac5ac906d8c Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:14 -0400 Subject: [PATCH 043/100] KSN: add `new-game.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–24 ↔ chapters 1–181 - anime `21455` → manga `85697` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/new-game.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/new-game.json diff --git a/src/data/index.ts b/src/data/index.ts index e288b4d..3f5e10e 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -348,6 +348,7 @@ import combatantsWillBeDispatched from "@/data/mappings/combatants-will-be-dispa import bakuman from "@/data/mappings/bakuman.json"; import konosubaExplosion from "@/data/mappings/konosuba-explosion.json"; import talentlessNana from "@/data/mappings/talentless-nana.json"; +import newGame from "@/data/mappings/new-game.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -765,6 +766,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ bakuman, konosubaExplosion, talentlessNana, + newGame, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/new-game.json b/src/data/mappings/new-game.json new file mode 100644 index 0000000..4883c83 --- /dev/null +++ b/src/data/mappings/new-game.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 21455, + "anilistMangaId": 85697, + "title": "NEW GAME!", + "sourceNotes": "Cumulative episodes across S1 'NEW GAME!' (12) + S2 'NEW GAME!!' (eps 13-24, 12) = 24 total, paired with Shotaro Tokuno's original 4-koma manga (id 85697), complete at 13 volumes / 181 chapters (AniList count; serialized in Manga Time Kirara Carat, ended 2021). 4-koma source, so chapter ranges are approximate and assigned by volume (~14 ch/volume). S1 adapts roughly volumes 1-3 (Aoba Suzukaze joins Eagle Jump and works on the game 'Fairies Story 3' through release). S2 adapts volumes 4, 6 and 7 (new-project/new-hire era with Tsubame and Momiji) and deliberately SKIPS volume 5, a prequel side-story collection; the anime therefore ends around the close of volume 7 (community guides say resume at 'chapter 65' in the tankobon-arc numbering). Volumes 8-13 (mapped here as chapters 99-181) are unadapted. A single BD-bundled OVA (id 97637, a company trip) exists but is not theatrical.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 42], + "arc": "Fairies Story 3 (Aoba's first year at Eagle Jump) — vols 1-3" + }, + { + "episodes": [13, 24], + "chapters": [43, 98], + "arc": "New project & new hires (Tsubame, Momiji) — vols 4, 6-7 (vol 5 prequel side stories skipped)" + }, + { + "chapters": [99, 181], + "arc": "Post-anime continuation — vols 8-13 (unadapted)" + } + ] +} From 9a6cb6f809182e68156d6014c4b8dfa2b99c8ee8 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:17 -0400 Subject: [PATCH 044/100] KSN: add `absolute-duo.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–11 - anime `20785` → manga `81025` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/absolute-duo.json | 32 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/absolute-duo.json diff --git a/src/data/index.ts b/src/data/index.ts index 3f5e10e..5cfa365 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -349,6 +349,7 @@ import bakuman from "@/data/mappings/bakuman.json"; import konosubaExplosion from "@/data/mappings/konosuba-explosion.json"; import talentlessNana from "@/data/mappings/talentless-nana.json"; import newGame from "@/data/mappings/new-game.json"; +import absoluteDuo from "@/data/mappings/absolute-duo.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -767,6 +768,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ konosubaExplosion, talentlessNana, newGame, + absoluteDuo, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/absolute-duo.json b/src/data/mappings/absolute-duo.json new file mode 100644 index 0000000..e0e0d10 --- /dev/null +++ b/src/data/mappings/absolute-duo.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 20785, + "anilistMangaId": 81025, + "title": "Absolute Duo", + "sourceNotes": "LN-based mapping; ranges are by light novel VOLUME, not chapter (no per-chapter episode guide exists, so \"chapters\" here are volume numbers). Source is Takumi Hiiragiboshi's MF Bunko J light novel (AniList id 81025), complete at 11 volumes (Aug 2012 - Jul 2016). The single-cour 12-episode Eight Bit anime (2015) adapts volumes 1-4, condensing/omitting scenes to fit and closing on an anime-original resolution at the end of Vol 4. Volume boundaries are split evenly at roughly 3 episodes per volume (12 eps / 4 vols); exact per-episode volume cut points are approximate. Volumes 5-11 are unadapted. Single season, so episodes are non-cumulative.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "Volume 1: Blaze" + }, + { + "episodes": [4, 6], + "chapters": [2, 2], + "arc": "Volume 2: Survive" + }, + { + "episodes": [7, 9], + "chapters": [3, 3], + "arc": "Volume 3: Rebels" + }, + { + "episodes": [10, 12], + "chapters": [4, 4], + "arc": "Volume 4: Absolute Duo" + }, + { + "chapters": [5, 11], + "arc": "Volumes 5-11 (unadapted)" + } + ] +} From 0da0b291ac52a774451e37a2961965a9a45e65de Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:20 -0400 Subject: [PATCH 045/100] KSN: add `science-fell-in-love.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–24 ↔ chapters 1–106 - anime `107067` → manga `87377` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/science-fell-in-love.json | 52 +++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/data/mappings/science-fell-in-love.json diff --git a/src/data/index.ts b/src/data/index.ts index 5cfa365..be7eb92 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -350,6 +350,7 @@ import konosubaExplosion from "@/data/mappings/konosuba-explosion.json"; import talentlessNana from "@/data/mappings/talentless-nana.json"; import newGame from "@/data/mappings/new-game.json"; import absoluteDuo from "@/data/mappings/absolute-duo.json"; +import scienceFellInLove from "@/data/mappings/science-fell-in-love.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -769,6 +770,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ talentlessNana, newGame, absoluteDuo, + scienceFellInLove, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/science-fell-in-love.json b/src/data/mappings/science-fell-in-love.json new file mode 100644 index 0000000..f228f40 --- /dev/null +++ b/src/data/mappings/science-fell-in-love.json @@ -0,0 +1,52 @@ +{ + "anilistAnimeId": 107067, + "anilistMangaId": 87377, + "title": "Science Fell in Love, So I Tried to Prove It", + "sourceNotes": "Cumulative episodes across S1 (12) + the sequel S2 \"r=1-sinθ\" (12) = 24 episodes, adapting manga chapters 1-61 (anime ends at ch. 61; continue reading at ch. 62). Manga ongoing (latest ch. 106, vol. 21 as of 2026). Episodic romcom source — each episode adapts 2-3 self-contained \"proof\" chapters and the anime reorders a few (the S1 finale kiss is pulled from a later chapter), so chapter ranges are approximate and grouped by episode-title beats / volume clusters rather than strict 1:1 boundaries. S2 resumes around Vol. 6 / ch. 32.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 10], + "arc": "Analyzing Love / Experiments" + }, + { + "episodes": [4, 6], + "chapters": [11, 19], + "arc": "First Date & First Kiss" + }, + { + "episodes": [7, 9], + "chapters": [20, 26], + "arc": "Drinking Party & Okinawa Training Camp" + }, + { + "episodes": [10, 12], + "chapters": [27, 31], + "arc": "Presentations & Proof of Love (S1 Finale)" + }, + { + "episodes": [13, 15], + "chapters": [32, 40], + "arc": "Comparing Couples & New Theories" + }, + { + "episodes": [16, 18], + "chapters": [41, 48], + "arc": "Live Concert & Analyzing the Proof" + }, + { + "episodes": [19, 21], + "chapters": [49, 55], + "arc": "Group Date & Campus Festival Prep" + }, + { + "episodes": [22, 24], + "chapters": [56, 61], + "arc": "Campus Festival & Marriage (S2 Finale)" + }, + { + "chapters": [62, 106], + "arc": "Post-Anime Chapters (Unadapted)" + } + ] +} From 94414b13828c241400291494c066a0f01d021010 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:23 -0400 Subject: [PATCH 046/100] KSN: add `trapped-in-a-dating-sim.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–72 - anime `142074` → manga `104503` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/trapped-in-a-dating-sim.json | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/trapped-in-a-dating-sim.json diff --git a/src/data/index.ts b/src/data/index.ts index be7eb92..20369d4 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -351,6 +351,7 @@ import talentlessNana from "@/data/mappings/talentless-nana.json"; import newGame from "@/data/mappings/new-game.json"; import absoluteDuo from "@/data/mappings/absolute-duo.json"; import scienceFellInLove from "@/data/mappings/science-fell-in-love.json"; +import trappedInADatingSim from "@/data/mappings/trapped-in-a-dating-sim.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -771,6 +772,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ newGame, absoluteDuo, scienceFellInLove, + trappedInADatingSim, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/trapped-in-a-dating-sim.json b/src/data/mappings/trapped-in-a-dating-sim.json new file mode 100644 index 0000000..b6969fe --- /dev/null +++ b/src/data/mappings/trapped-in-a-dating-sim.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 142074, + "anilistMangaId": 104503, + "title": "Trapped in a Dating Sim: The World of Otome Games Is Tough for Mobs", + "sourceNotes": "Single 12-episode TV season (ENGI, 2022); the 2026 Season 2 is not yet released. Officially light-novel-sourced (LN complete at 13 volumes; AniList novel id 104504), but every community episode-to-source guide anchors the anime to the MANGA adaptation, so chapter ranges here use the manga's continuous numbering (AniList manga id 104503). The anime adapts LN volumes 1-2 = roughly manga chapters 1-38; guides tell readers to continue in the manga at Vol. 8, Ch. 39 (equivalently LN Vol. 3), which picks up right where the finale leaves off after Leon overcomes the Principality of Fanoss. The internal split between the academy/duel arc (LN vol 1) and the Fanoss war arc (LN vol 2) is approximate because the anime compressed vol 2's pacing. Manga was ongoing past the AniList snapshot of 72 chapters (13 tankobon by late 2024). No theatrical films exist.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 19], + "arc": "Academy Arc" + }, + { + "episodes": [7, 12], + "chapters": [20, 38], + "arc": "Principality of Fanoss Arc" + }, + { + "chapters": [39, 72], + "arc": "Alzer Republic Arc (unadapted in S1)" + } + ] +} From 997acf3fccffa022dbd477d98ca092412e7fafed Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:26 -0400 Subject: [PATCH 047/100] KSN: add `non-non-biyori.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–36 ↔ chapters 1–126 - 1 movie - anime `17549` → manga `47552` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/non-non-biyori.json | 36 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/data/mappings/non-non-biyori.json diff --git a/src/data/index.ts b/src/data/index.ts index 20369d4..6a67603 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -352,6 +352,7 @@ import newGame from "@/data/mappings/new-game.json"; import absoluteDuo from "@/data/mappings/absolute-duo.json"; import scienceFellInLove from "@/data/mappings/science-fell-in-love.json"; import trappedInADatingSim from "@/data/mappings/trapped-in-a-dating-sim.json"; +import nonNonBiyori from "@/data/mappings/non-non-biyori.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -773,6 +774,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ absoluteDuo, scienceFellInLove, trappedInADatingSim, + nonNonBiyori, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/non-non-biyori.json b/src/data/mappings/non-non-biyori.json new file mode 100644 index 0000000..1962a3c --- /dev/null +++ b/src/data/mappings/non-non-biyori.json @@ -0,0 +1,36 @@ +{ + "anilistAnimeId": 17549, + "anilistMangaId": 47552, + "title": "Non Non Biyori", + "sourceNotes": "Cumulative episodes across S1 Non Non Biyori (12) + S2 Repeat (12) + S3 Nonstop (12) = 36 TV episodes. Source manga by Atto ran in Comic Alive 2009-2021, complete at 16 volumes / 126 chapters on AniList (~120 numbered chapters plus extras). This is an episodic iyashikei slice-of-life series with NO named story arcs and a heavily NON-LINEAR adaptation: Silver Link reordered chapters freely and Repeat re-adapts several early-manga vignettes skipped by season 1, so exact episode-to-chapter boundaries are not published. Chapter ranges below are APPROXIMATE, presented progressively by season (~1-3 chapters per episode) purely to indicate reading progress; the practical takeaway is that the three seasons together cover roughly the first ~13-14 volumes, leaving the final volumes unadapted. Seasons are used as the arc labels since the work has no canonical arcs.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 30], + "arc": "Season 1 (Non Non Biyori)" + }, + { + "episodes": [13, 24], + "chapters": [31, 64], + "arc": "Season 2 (Repeat)" + }, + { + "episodes": [25, 36], + "chapters": [65, 108], + "arc": "Season 3 (Nonstop)" + }, + { + "chapters": [109, 126], + "arc": "Unadapted (final volumes)" + } + ], + "movies": [ + { + "anilistId": 98779, + "title": "Non Non Biyori Vacation", + "year": 2018, + "afterEpisode": 24, + "note": "Canon theatrical feature in the main continuity, released between Repeat (S2) and Nonstop (S3). Expands the girls' summer trip to Okinawa (building on the S1 'We're Going to Okinawa' OVA) with all-new animation. Largely anime-expanded original content, so chapter alignment is approximate." + } + ] +} From d40e6ecba009aeb58a5ff0e3e2b51acf27ade471 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:29 -0400 Subject: [PATCH 048/100] KSN: add `magi-adventure-of-sinbad.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 12 arcs covering episodes 1–13 ↔ chapters 1–182 - anime `21394` → manga `78025` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../mappings/magi-adventure-of-sinbad.json | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/data/mappings/magi-adventure-of-sinbad.json diff --git a/src/data/index.ts b/src/data/index.ts index 6a67603..6b7a368 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -353,6 +353,7 @@ import absoluteDuo from "@/data/mappings/absolute-duo.json"; import scienceFellInLove from "@/data/mappings/science-fell-in-love.json"; import trappedInADatingSim from "@/data/mappings/trapped-in-a-dating-sim.json"; import nonNonBiyori from "@/data/mappings/non-non-biyori.json"; +import magiAdventureOfSinbad from "@/data/mappings/magi-adventure-of-sinbad.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -775,6 +776,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ scienceFellInLove, trappedInADatingSim, nonNonBiyori, + magiAdventureOfSinbad, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/magi-adventure-of-sinbad.json b/src/data/mappings/magi-adventure-of-sinbad.json new file mode 100644 index 0000000..29b898d --- /dev/null +++ b/src/data/mappings/magi-adventure-of-sinbad.json @@ -0,0 +1,61 @@ +{ + "anilistAnimeId": 21394, + "anilistMangaId": 78025, + "title": "Magi: Adventure of Sinbad", + "sourceNotes": "Prequel spin-off to Magi (distinct source manga \"Magi: The Adventures of Sinbad\", AniList 78025). Single 13-episode TV season (Lay-duce, 2016), so episodes are non-cumulative. The anime is a compressed adaptation ending at chapter 55 (end of the Artemyra Arc) — community guides advise resuming the manga at ch. 55. Arc chapter boundaries per the Magi wiki / magimanga arc guide; per-episode assignments to those five arcs are approximate due to pacing. Manga complete at 182 chapters (19 volumes, ended 2018). Arcs from ch. 56 (Slave Arc) onward are unadapted. A separate 5-episode OVA (AniList 20609) covers the early Baal/Valefor material and is not mapped here.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 12], + "arc": "Baal" + }, + { + "episodes": [4, 6], + "chapters": [13, 29], + "arc": "Imuchakk" + }, + { + "episodes": [7, 8], + "chapters": [30, 38], + "arc": "Reim Empire" + }, + { + "episodes": [9, 10], + "chapters": [39, 45], + "arc": "Sasan" + }, + { + "episodes": [11, 13], + "chapters": [46, 55], + "arc": "Artemyra" + }, + { + "chapters": [56, 81], + "arc": "Slave" + }, + { + "chapters": [82, 111], + "arc": "Heliohapt" + }, + { + "chapters": [112, 119], + "arc": "Dark Continent" + }, + { + "chapters": [120, 129], + "arc": "Parthevia" + }, + { + "chapters": [130, 149], + "arc": "Forming of Sindria" + }, + { + "chapters": [150, 177], + "arc": "Sindrian War" + }, + { + "chapters": [178, 182], + "arc": "Epilogue" + } + ] +} From 69c397426319b37e8662f0e917db359583a3decb Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:32 -0400 Subject: [PATCH 049/100] KSN: add `baka-and-test.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–26 ↔ chapters 1–143 - anime `6347` → manga `42295` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/baka-and-test.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/baka-and-test.json diff --git a/src/data/index.ts b/src/data/index.ts index 6b7a368..98ed56c 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -354,6 +354,7 @@ import scienceFellInLove from "@/data/mappings/science-fell-in-love.json"; import trappedInADatingSim from "@/data/mappings/trapped-in-a-dating-sim.json"; import nonNonBiyori from "@/data/mappings/non-non-biyori.json"; import magiAdventureOfSinbad from "@/data/mappings/magi-adventure-of-sinbad.json"; +import bakaAndTest from "@/data/mappings/baka-and-test.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -777,6 +778,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ trappedInADatingSim, nonNonBiyori, magiAdventureOfSinbad, + bakaAndTest, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/baka-and-test.json b/src/data/mappings/baka-and-test.json new file mode 100644 index 0000000..a4a032e --- /dev/null +++ b/src/data/mappings/baka-and-test.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 6347, + "anilistMangaId": 42295, + "title": "Baka and Test - Summon the Beasts", + "sourceNotes": "LN-based; mapped to the Baka to Test to Shoukanjuu light novel (AniList id 42295), complete at 18 volumes — 12 main-story volumes plus 6 side-story/short-story volumes (3.5, 6.5, 7.5, 9.5, 10.5, 12.5). Chapter numbering here follows the main-story \"Question\" sequence (Vol 1 = ch 1-10, Vol 2 = 11-18, Vol 3 = 19-26, Vol 4 = 27-33, Vol 5 = 34-41, Vol 6 = 42-48, per the fandom volume pages). AniList's 143-chapter total additionally counts the interleaved side-story volumes, which the anime does not adapt — the unadapted tail entry extends to 143 to cover Vols 7-12 plus those side volumes. Cumulative episodes across S1 (13) + S2 \"Ni!\" (13) = 26. Ranges are APPROXIMATE: the Silver Link adaptation is non-linear and heavily filler-laden (community guides note \"much of season 1 was filler\" and advise reading the novels from the start rather than continuing from a fixed point); the two seasons together cover roughly LN volumes 1-6, with season 2 ending around the summer Test of Courage / haunted-house battle (~Vol 6). No theatrical films exist (only an OVA, \"Matsuri,\" and TV specials).", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 26], + "arc": "Exam Summoning Battles — Season 1 (Vols 1-3)" + }, + { + "episodes": [14, 26], + "chapters": [27, 48], + "arc": "Summer & Test of Courage — Season 2 \"Ni!\" (Vols 4-6)" + }, + { + "chapters": [49, 143], + "arc": "Unadapted light-novel arcs (Vols 7-12 + side-story volumes)" + } + ] +} From 956d35a342936bf60b2d337ea5483ac4a26d947a Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:36 -0400 Subject: [PATCH 050/100] KSN: add `dagashi-kashi.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–24 ↔ chapters 1–186 - anime `21365` → manga `85966` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/dagashi-kashi.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/dagashi-kashi.json diff --git a/src/data/index.ts b/src/data/index.ts index 98ed56c..56584f8 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -355,6 +355,7 @@ import trappedInADatingSim from "@/data/mappings/trapped-in-a-dating-sim.json"; import nonNonBiyori from "@/data/mappings/non-non-biyori.json"; import magiAdventureOfSinbad from "@/data/mappings/magi-adventure-of-sinbad.json"; import bakaAndTest from "@/data/mappings/baka-and-test.json"; +import dagashiKashi from "@/data/mappings/dagashi-kashi.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -779,6 +780,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ nonNonBiyori, magiAdventureOfSinbad, bakaAndTest, + dagashiKashi, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/dagashi-kashi.json b/src/data/mappings/dagashi-kashi.json new file mode 100644 index 0000000..cd6becb --- /dev/null +++ b/src/data/mappings/dagashi-kashi.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 21365, + "anilistMangaId": 85966, + "title": "Dagashi Kashi", + "sourceNotes": "Episodic gag manga — chapter ranges are approximate. Kotoyama's Dagashi Kashi ran in Weekly Shounen Sunday and is complete at 186 chapters / 11 volumes (AniList manga id 85966). Cumulative episodes across S1 (12 eps, 2016, feel.) + S2 (12 eps, 2018, TMS/Tezuka Productions, aired as ~12-min TV shorts) = 24. The adaptation samples short, self-contained candy gags out of chapter order rather than following any continuous arc: per fan episode-to-chapter guides, S1 pulls scattered chapters from roughly 1-68 (with original material) and S2 runs more linearly through the mid-80s to chapter 126-127 (partially adapting 127 for the finale), skipping many chapters along the way. Because the source is non-sequential vignette comedy, the ranges below are coarse approximations, not 1:1 matches. A reader continues past the anime from chapter 128 to the manga's conclusion at 186. No theatrical films exist, so no movies are listed.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 68], + "arc": "Season 1 — Hotaru arrives to recruit Kokonotsu for the Shikada dagashi shop (episodic candy gags; non-sequential sampling, approximate)" + }, + { + "episodes": [13, 24], + "chapters": [69, 127], + "arc": "Season 2 — the shop vs. the new convenience store; Hajime Owari joins (episodic; more linear, approximate, ends near ch. 126-127)" + }, + { + "chapters": [128, 186], + "arc": "Later chapters to the finale (unadapted; episodic, approximate)" + } + ] +} From 5e584111817869921229f3ed0f0e5dee7d81f2af Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:39 -0400 Subject: [PATCH 051/100] KSN: add `worldend-sukasuka.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–25 - anime `21860` → manga `87284` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/worldend-sukasuka.json | 31 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/data/mappings/worldend-sukasuka.json diff --git a/src/data/index.ts b/src/data/index.ts index 56584f8..108afc7 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -356,6 +356,7 @@ import nonNonBiyori from "@/data/mappings/non-non-biyori.json"; import magiAdventureOfSinbad from "@/data/mappings/magi-adventure-of-sinbad.json"; import bakaAndTest from "@/data/mappings/baka-and-test.json"; import dagashiKashi from "@/data/mappings/dagashi-kashi.json"; +import worldendSukasuka from "@/data/mappings/worldend-sukasuka.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -781,6 +782,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ magiAdventureOfSinbad, bakaAndTest, dagashiKashi, + worldendSukasuka, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/worldend-sukasuka.json b/src/data/mappings/worldend-sukasuka.json new file mode 100644 index 0000000..adf294c --- /dev/null +++ b/src/data/mappings/worldend-sukasuka.json @@ -0,0 +1,31 @@ +{ + "anilistAnimeId": 21860, + "anilistMangaId": 87284, + "title": "WorldEnd: What are you doing at the end of the world? Are you busy? Will you save us?", + "sourceNotes": "Single-cour 12-episode adaptation (Spring 2017) of Akira Kareno's light novel \"Shuumatsu Nani Shitemasu ka?\" (SukaSuka). LN-based, so ranges are mapped by volume against the source's AniList NOVEL entry (id 87284), which reports 25 chapters across 5 volumes (5 chapters/volume). The anime adapts only volumes 1-3 (chapters 1-15); volumes 4-5 (chapters 16-25) of the original series were never animated, and the sequel SukaMoka series is unadapted. Per-volume episode boundaries are approximate — the anime condenses and re-weights the source toward Chtholly's perspective, and no episode-to-chapter guide exists, so splits are estimated at ~4 episodes per volume. Original LN series complete at 5 volumes; sequel SukaMoka complete at 11 volumes.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 5], + "arc": "Volume 1" + }, + { + "episodes": [5, 8], + "chapters": [6, 10], + "arc": "Volume 2" + }, + { + "episodes": [9, 12], + "chapters": [11, 15], + "arc": "Volume 3" + }, + { + "chapters": [16, 20], + "arc": "Volume 4 (unadapted)" + }, + { + "chapters": [21, 25], + "arc": "Volume 5 (unadapted)" + } + ] +} From 7570d4caec5dbb17bfe8fc3a55ebd830fc8cdaac Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:42 -0400 Subject: [PATCH 052/100] KSN: add `ascendance-of-a-bookworm.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–36 ↔ chapters 1–33 - anime `108268` → manga `87383` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/ascendance-of-a-bookworm.json | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/data/mappings/ascendance-of-a-bookworm.json diff --git a/src/data/index.ts b/src/data/index.ts index 108afc7..49393c9 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -357,6 +357,7 @@ import magiAdventureOfSinbad from "@/data/mappings/magi-adventure-of-sinbad.json import bakaAndTest from "@/data/mappings/baka-and-test.json"; import dagashiKashi from "@/data/mappings/dagashi-kashi.json"; import worldendSukasuka from "@/data/mappings/worldend-sukasuka.json"; +import ascendanceOfABookworm from "@/data/mappings/ascendance-of-a-bookworm.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -783,6 +784,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ bakaAndTest, dagashiKashi, worldendSukasuka, + ascendanceOfABookworm, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/ascendance-of-a-bookworm.json b/src/data/mappings/ascendance-of-a-bookworm.json new file mode 100644 index 0000000..cdebeba --- /dev/null +++ b/src/data/mappings/ascendance-of-a-bookworm.json @@ -0,0 +1,35 @@ +{ + "anilistAnimeId": 108268, + "anilistMangaId": 87383, + "title": "Ascendance of a Bookworm", + "sourceNotes": "Cumulative episodes across S1 (14, 2019) + S2 \"Part 2\" (12, 2020, eps 15-26) + S3 (10, 2022, eps 27-36) = 36 total; use the S1 anime id 108268. Source is Miya Kazuki's light novel, split by AniList into per-Part entries (id 87383 is the linked Part 1 novel, \"Daughter of a Soldier\"). Because the manga adaptations lag far behind, this maps by LIGHT NOVEL VOLUME across the whole 33-volume main series: the `chapters` tuples are overall LN volume numbers (1-33), NOT manga chapters. The 5 Parts are Part 1 \"Daughter of a Soldier\" (vols 1-3), Part 2 \"Apprentice Shrine Maiden\" (vols 4-7), Part 3 \"Adopted Daughter of an Archduke\" (vols 8-12), Part 4 \"Founder of the Royal Academy's So-Called Library Committee\" (vols 13-21), and Part 5 \"Avatar of a Goddess\" (vols 22-33); the LN concluded in 2023 at 33 volumes. Seasons 1-3 adapt Parts 1-2 in full, so a reader resumes at vol 8 (Part 3 Vol 1). Season 4 \"Adopted Daughter of an Archduke\" (id 171110, Part 3) began airing April 2026 and was still releasing as of this writing, so Part 3 onward is listed as an unadapted/ongoing tail. Per-volume episode boundaries within each season are approximate. No theatrical films.", + "mappings": [ + { + "episodes": [1, 14], + "chapters": [1, 3], + "arc": "Part 1: Daughter of a Soldier (S1, LN vols 1-3)" + }, + { + "episodes": [15, 26], + "chapters": [4, 5], + "arc": "Part 2: Apprentice Shrine Maiden - first half (S2, LN vols 4-5)" + }, + { + "episodes": [27, 36], + "chapters": [6, 7], + "arc": "Part 2: Apprentice Shrine Maiden - conclusion (S3, LN vols 6-7)" + }, + { + "chapters": [8, 12], + "arc": "Part 3: Adopted Daughter of an Archduke (LN vols 8-12; Season 4 airing 2026, not yet complete)" + }, + { + "chapters": [13, 21], + "arc": "Part 4: Founder of the Royal Academy's So-Called Library Committee (LN vols 13-21, unadapted)" + }, + { + "chapters": [22, 33], + "arc": "Part 5: Avatar of a Goddess (LN vols 22-33, unadapted)" + } + ] +} From f9e37161ca04a77c764a3eab69e16d36bb788292 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:46 -0400 Subject: [PATCH 053/100] KSN: add `keep-your-hands-off-eizouken.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–74 - anime `109298` → manga `109319` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../keep-your-hands-off-eizouken.json | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/keep-your-hands-off-eizouken.json diff --git a/src/data/index.ts b/src/data/index.ts index 49393c9..ac33723 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -358,6 +358,7 @@ import bakaAndTest from "@/data/mappings/baka-and-test.json"; import dagashiKashi from "@/data/mappings/dagashi-kashi.json"; import worldendSukasuka from "@/data/mappings/worldend-sukasuka.json"; import ascendanceOfABookworm from "@/data/mappings/ascendance-of-a-bookworm.json"; +import keepYourHandsOffEizouken from "@/data/mappings/keep-your-hands-off-eizouken.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -785,6 +786,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ dagashiKashi, worldendSukasuka, ascendanceOfABookworm, + keepYourHandsOffEizouken, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/keep-your-hands-off-eizouken.json b/src/data/mappings/keep-your-hands-off-eizouken.json new file mode 100644 index 0000000..b862347 --- /dev/null +++ b/src/data/mappings/keep-your-hands-off-eizouken.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 109298, + "anilistMangaId": 109319, + "title": "Keep Your Hands Off Eizouken!", + "sourceNotes": "Single-cour 12-episode TV anime (Science SARU, 2020); cumulative episodes equal broadcast episodes since there is only one season. Source manga by Sumito Ōwara is ongoing (10 tankōbon volumes, ~74 chapters as of 2026). The anime adapts volumes 1-3 (chapters 1-23) at roughly 2 chapters per episode; arc boundaries follow the three in-story film productions and are corroborated by matching chapter/episode titles (Ch 1 \"The Greatest World!\" = Ep 1; Ch 8 \"Discovering an Iron Giant!\" = Ep 5; Ch 15 \"The Great Shibahama Festival\" = Ep 8; Ch 22 \"The Beginning of the War\" / Ch 23 = Ep 12 \"Shibahama UFO Wars!\"). Volume-to-chapter ranges per the Eizouken fandom wiki. The 2020 live-action film/TV drama is a separate live-action continuity and is excluded.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 6], + "arc": "Founding & Debut Short" + }, + { + "episodes": [4, 8], + "chapters": [7, 15], + "arc": "Robot Research Club Anime" + }, + { + "episodes": [9, 12], + "chapters": [16, 23], + "arc": "UFO Wars" + }, + { + "chapters": [24, 74], + "arc": "Post-Anime Productions (unadapted)" + } + ] +} From 4fafee56cebd3378c3bfd9fe901961696ced11c4 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:50 -0400 Subject: [PATCH 054/100] KSN: add `campfire-cooking-in-another-world.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–24 ↔ chapters 1–17 - anime `156067` → manga `99049` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../campfire-cooking-in-another-world.json | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/campfire-cooking-in-another-world.json diff --git a/src/data/index.ts b/src/data/index.ts index ac33723..09decbe 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -359,6 +359,7 @@ import dagashiKashi from "@/data/mappings/dagashi-kashi.json"; import worldendSukasuka from "@/data/mappings/worldend-sukasuka.json"; import ascendanceOfABookworm from "@/data/mappings/ascendance-of-a-bookworm.json"; import keepYourHandsOffEizouken from "@/data/mappings/keep-your-hands-off-eizouken.json"; +import campfireCookingInAnotherWorld from "@/data/mappings/campfire-cooking-in-another-world.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -787,6 +788,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ worldendSukasuka, ascendanceOfABookworm, keepYourHandsOffEizouken, + campfireCookingInAnotherWorld, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/campfire-cooking-in-another-world.json b/src/data/mappings/campfire-cooking-in-another-world.json new file mode 100644 index 0000000..2347c5e --- /dev/null +++ b/src/data/mappings/campfire-cooking-in-another-world.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 156067, + "anilistMangaId": 99049, + "title": "Campfire Cooking in Another World with my Absurd Skill", + "sourceNotes": "LN-based mapping (AniList source is the light novel, id 99049, by Ren Eguchi). Because the LN's chapters reset per volume, the chapters[] ranges here are LN VOLUME numbers, not sequential chapter numbers; within-season episode splits are approximate since the LN is episodic (cooking/travel) with no formal arc names — the dish-themed volume subtitles stand in as arc names. Cumulative episodes across S1 (12) + S2 (12) = 24. Community episode-to-source guides anchor the adaptation: Season 1 (ep 1-12) ends partway through Volume 2 (continue at Vol 2 Ch 8), and Season 2 (ep 13-24) ends at the close of Volume 5 (continue at Volume 6), so Vol 2 straddles the S1/S2 boundary. Light novel is ongoing (17 volumes as of late 2025). No theatrical films or OVAs.", + "mappings": [ + { + "episodes": [1, 7], + "chapters": [1, 1], + "arc": "Ginger-Fried Pork and the Legendary Beast (Vol. 1)" + }, + { + "episodes": [8, 14], + "chapters": [2, 2], + "arc": "Winged Gyoza and the Phantom Dragon (Vol. 2)" + }, + { + "episodes": [15, 17], + "chapters": [3, 3], + "arc": "Beef Stew and the Unexplored Labyrinth (Vol. 3)" + }, + { + "episodes": [18, 20], + "chapters": [4, 4], + "arc": "Barbeque and God's Blessings (Vol. 4)" + }, + { + "episodes": [21, 24], + "chapters": [5, 5], + "arc": "Mixed Tempura and the Sea Monster (Vol. 5)" + }, + { + "chapters": [6, 17], + "arc": "Meat Soboro Rice Bowls and the Holy Seal onward (Vol. 6+, unadapted)" + } + ] +} From 0d194b2660e490a6a41908a4592d5d97a1bfb2f6 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:53 -0400 Subject: [PATCH 055/100] KSN: add `daemons-of-the-shadow-realm.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–24 ↔ chapters 1–54 - anime `195600` → manga `136899` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/daemons-of-the-shadow-realm.json | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/data/mappings/daemons-of-the-shadow-realm.json diff --git a/src/data/index.ts b/src/data/index.ts index 09decbe..bfd6877 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -360,6 +360,7 @@ import worldendSukasuka from "@/data/mappings/worldend-sukasuka.json"; import ascendanceOfABookworm from "@/data/mappings/ascendance-of-a-bookworm.json"; import keepYourHandsOffEizouken from "@/data/mappings/keep-your-hands-off-eizouken.json"; import campfireCookingInAnotherWorld from "@/data/mappings/campfire-cooking-in-another-world.json"; +import daemonsOfTheShadowRealm from "@/data/mappings/daemons-of-the-shadow-realm.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -789,6 +790,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ ascendanceOfABookworm, keepYourHandsOffEizouken, campfireCookingInAnotherWorld, + daemonsOfTheShadowRealm, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/daemons-of-the-shadow-realm.json b/src/data/mappings/daemons-of-the-shadow-realm.json new file mode 100644 index 0000000..c7d3292 --- /dev/null +++ b/src/data/mappings/daemons-of-the-shadow-realm.json @@ -0,0 +1,36 @@ +{ + "anilistAnimeId": 195600, + "anilistMangaId": 136899, + "title": "Daemons of the Shadow Realm", + "sourceNotes": "Source is the Yomi no Tsugai manga by Hiromu Arakawa (AniList 136899), ongoing since 2021; 12 volumes / latest chapter 54 as of mid-2026. The 2026 TV anime by Bones Film is a single continuous 24-episode run billed as two cours, so episode numbers are already cumulative (no season split). Arc names come from the Yomi no Tsugai fandom wiki and are unofficial. The anime lightly condenses/reorders chapters (e.g. it drops ch. 4 \"Ai and Makoto\" and compresses the 8-chapter Kagemori arc into ~5 episodes). Episode-to-chapter alignment is confirmed on the wiki only through episode 14 (= chapter 18); the Fujimurayama Warehouse arc episode range (ep 12-24) is estimated to fill the remaining episodes, taking the arc's final chapter (31) as the projected season endpoint. The Nishino Village Investigation arc (ch. 32-50) and the current Okinawa arc (ch. 51-54) are unadapted.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 3], + "arc": "Higashi Village Raid" + }, + { + "episodes": [4, 8], + "chapters": [4, 11], + "arc": "Kagemori Mansion" + }, + { + "episodes": [9, 11], + "chapters": [12, 15], + "arc": "Tadera's Mayoiga" + }, + { + "episodes": [12, 24], + "chapters": [16, 31], + "arc": "Fujimurayama Warehouse" + }, + { + "chapters": [32, 50], + "arc": "Nishino Village Investigation" + }, + { + "chapters": [51, 54], + "arc": "Okinawa" + } + ] +} From 88733e92483f62066d2be4091835d8420d220ad7 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:56 -0400 Subject: [PATCH 056/100] KSN: add `initial-d.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–81 ↔ chapters 1–725 - 4 movies - anime `185` → manga `30375` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/initial-d.json | 84 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/data/mappings/initial-d.json diff --git a/src/data/index.ts b/src/data/index.ts index bfd6877..15f025d 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -361,6 +361,7 @@ import ascendanceOfABookworm from "@/data/mappings/ascendance-of-a-bookworm.json import keepYourHandsOffEizouken from "@/data/mappings/keep-your-hands-off-eizouken.json"; import campfireCookingInAnotherWorld from "@/data/mappings/campfire-cooking-in-another-world.json"; import daemonsOfTheShadowRealm from "@/data/mappings/daemons-of-the-shadow-realm.json"; +import initialD from "@/data/mappings/initial-d.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -791,6 +792,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ keepYourHandsOffEizouken, campfireCookingInAnotherWorld, daemonsOfTheShadowRealm, + initialD, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/initial-d.json b/src/data/mappings/initial-d.json new file mode 100644 index 0000000..d1ea31e --- /dev/null +++ b/src/data/mappings/initial-d.json @@ -0,0 +1,84 @@ +{ + "anilistAnimeId": 185, + "anilistMangaId": 30375, + "title": "Initial D", + "sourceNotes": "Cumulative episodes across the five TV \"Stages\": First Stage (26) + Second Stage (13, Acts 27-39) + Fourth Stage (24) + Fifth Stage (14) + Final Stage (4) = 81 TV episodes; the 2001 Third Stage is a theatrical film that falls between Second and Fourth Stage (listed in movies[], not a TV episode). Source is Shuichi Shigeno's Initial D manga, complete at 719 chapters / 48 volumes (AniList counts 725, likely including bonus/omake pages; the final entry is extended to that AniList count). First Stage adapts ch 1-77 (vols 1-7); the manga splits into Part 1 \"Akina's Eight-Six\" (vols 1-17, through the Third Stage film) and Part 2 \"Project D\" (ch ~199-719), whose Kanagawa Expedition (ch 444-719) is covered by Fifth + Final Stage. Episode-within-stage boundaries are approximate (races don't split cleanly on act lines); stage-to-chapter boundaries are reliable.", + "mappings": [ + { + "episodes": [1, 8], + "chapters": [1, 21], + "arc": "Akina's Eight-Six / RedSuns (Keisuke Takahashi)" + }, + { + "episodes": [9, 13], + "chapters": [22, 33], + "arc": "Myogi NightKids (Takeshi Nakazato)" + }, + { + "episodes": [14, 18], + "chapters": [34, 43], + "arc": "NightKids Tape Deathmatch (Shingo Shoji)" + }, + { + "episodes": [19, 22], + "chapters": [44, 61], + "arc": "Impact Blue (Usui Pass, Mako & Sayuki)" + }, + { + "episodes": [23, 26], + "chapters": [62, 77], + "arc": "RedSuns Leader (Ryosuke Takahashi)" + }, + { + "episodes": [27, 39], + "chapters": [78, 145], + "arc": "Second Stage: Team Emperor & Saitama (Wataru Akiyama)" + }, + { + "episodes": [40, 63], + "chapters": [199, 443], + "arc": "Fourth Stage: Project D — Kanto Expedition" + }, + { + "episodes": [64, 77], + "chapters": [444, 667], + "arc": "Fifth Stage: Project D — Kanagawa Expedition" + }, + { + "episodes": [78, 81], + "chapters": [668, 725], + "arc": "Final Stage: God Foot vs God Hand (Shinji Dan)" + } + ], + "movies": [ + { + "anilistId": 187, + "title": "Initial D Third Stage", + "year": 2001, + "chapters": [146, 198], + "afterEpisode": 39, + "note": "Canon theatrical film bridging Second and Fourth Stage; adapts the finale of Part 1 (Kai Kogashiwa's MR2 race, Takumi and Natsuki's relationship, and the formation of Project D)." + }, + { + "anilistId": 20842, + "title": "New Initial D the Movie: Legend 1 - Awakening", + "year": 2014, + "chapters": [1, 21], + "note": "First of an all-new-animation theatrical remake trilogy retelling the First Stage material — Takumi's introduction and the downhill battle against Keisuke Takahashi's RedSuns FD." + }, + { + "anilistId": 20990, + "title": "New Initial D the Movie: Legend 2 - Racer", + "year": 2015, + "chapters": [22, 43], + "note": "Second remake film, re-adapting the NightKids battles against Takeshi Nakazato (GT-R R32) and Shingo Shoji." + }, + { + "anilistId": 21289, + "title": "New Initial D the Movie: Legend 3 - Dream", + "year": 2016, + "chapters": [44, 77], + "note": "Final remake film, re-adapting the Impact Blue Usui Pass battle and the climactic race against RedSuns leader Ryosuke Takahashi." + } + ] +} From bb734719698ba95ee607dda3a247537cb8abab4b Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:17:59 -0400 Subject: [PATCH 057/100] KSN: add `is-this-a-zombie.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–22 ↔ chapters 1–19 - anime `8841` → manga `53067` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/is-this-a-zombie.json | 27 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/is-this-a-zombie.json diff --git a/src/data/index.ts b/src/data/index.ts index 15f025d..0a47b58 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -362,6 +362,7 @@ import keepYourHandsOffEizouken from "@/data/mappings/keep-your-hands-off-eizouk import campfireCookingInAnotherWorld from "@/data/mappings/campfire-cooking-in-another-world.json"; import daemonsOfTheShadowRealm from "@/data/mappings/daemons-of-the-shadow-realm.json"; import initialD from "@/data/mappings/initial-d.json"; +import isThisAZombie from "@/data/mappings/is-this-a-zombie.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -793,6 +794,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ campfireCookingInAnotherWorld, daemonsOfTheShadowRealm, initialD, + isThisAZombie, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/is-this-a-zombie.json b/src/data/mappings/is-this-a-zombie.json new file mode 100644 index 0000000..21ecd09 --- /dev/null +++ b/src/data/mappings/is-this-a-zombie.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 8841, + "anilistMangaId": 53067, + "title": "Is this a Zombie?", + "sourceNotes": "Light-novel sourced (AniList NOVEL entry 53067; series complete at 19 volumes, which AniList lists as 118 chapters). Chapter values here are light-novel VOLUME numbers, not AniList chapter counts, since community episode-to-source guides track volumes. Cumulative episodes across S1 (12) + S2 \"of the Dead\" (10) = 22. The adaptation is non-linear and heavily comedic: S1 draws from Novels 1-3, the 2-episode OVA adapts Novel 6, and S2 \"of the Dead\" adapts most of Novel 7 with substantial anime-original content; Novels 4-6 are largely skipped on TV. Per-arc volume boundaries are therefore approximate.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 2], + "arc": "Ayumu the Masou-Shoujo (Novels 1-2)" + }, + { + "episodes": [7, 12], + "chapters": [3, 3], + "arc": "Kyoko, King of Night (Novel 3)" + }, + { + "episodes": [13, 22], + "chapters": [7, 7], + "arc": "of the Dead (Novel 7)" + }, + { + "chapters": [8, 19], + "arc": "Remaining novels (unadapted)" + } + ] +} From 4f39d62f13d3a5970f5b1f7185dad9c89ad7f2d0 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:03 -0400 Subject: [PATCH 058/100] KSN: add `blast-of-tempest.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–24 ↔ chapters 1–50 - anime `14075` → manga `45205` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/blast-of-tempest.json | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/data/mappings/blast-of-tempest.json diff --git a/src/data/index.ts b/src/data/index.ts index 0a47b58..dd45acf 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -363,6 +363,7 @@ import campfireCookingInAnotherWorld from "@/data/mappings/campfire-cooking-in-a import daemonsOfTheShadowRealm from "@/data/mappings/daemons-of-the-shadow-realm.json"; import initialD from "@/data/mappings/initial-d.json"; import isThisAZombie from "@/data/mappings/is-this-a-zombie.json"; +import blastOfTempest from "@/data/mappings/blast-of-tempest.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -795,6 +796,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ daemonsOfTheShadowRealm, initialD, isThisAZombie, + blastOfTempest, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/blast-of-tempest.json b/src/data/mappings/blast-of-tempest.json new file mode 100644 index 0000000..2abeb70 --- /dev/null +++ b/src/data/mappings/blast-of-tempest.json @@ -0,0 +1,18 @@ +{ + "anilistAnimeId": 14075, + "anilistMangaId": 45205, + "title": "Blast of Tempest", + "sourceNotes": "Single continuous 24-episode run (Bones, 2012-2013) that adapted the complete manga and concluded roughly alongside it, so no anime-original ending. Manga complete at 50 chapters / 10 volumes on AniList (some sources count ~44 numbered chapters plus side/extra chapters). Pacing is roughly 2 chapters per episode. Episode 13 (\"Philosophy of Dreams\") is largely a recap/bridge told from Mahiro's POV. The story has a clear two-part structure homaging Shakespeare: the first cour (eps 1-12) is \"The Tempest\" (Hakaze and the Kusaribe clan's conflict over the Tree of Exodus), and the second cour (eps 13-24) is \"Hamlet\" (the mystery of who killed Aika). Chapter boundaries within each half are approximate; the split follows the ep 12/13 cour break.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 25], + "arc": "The Tempest (Tree of Exodus)" + }, + { + "episodes": [13, 24], + "chapters": [26, 50], + "arc": "Hamlet (Aika's Death)" + } + ] +} From 019b3b9a421d89fac8e1278908de61c8e5f4c54f Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:06 -0400 Subject: [PATCH 059/100] KSN: add `love-and-lies.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–12 ↔ chapters 1–301 - anime `98320` → manga `85566` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/love-and-lies.json | 36 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/data/mappings/love-and-lies.json diff --git a/src/data/index.ts b/src/data/index.ts index dd45acf..78f1768 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -364,6 +364,7 @@ import daemonsOfTheShadowRealm from "@/data/mappings/daemons-of-the-shadow-realm import initialD from "@/data/mappings/initial-d.json"; import isThisAZombie from "@/data/mappings/is-this-a-zombie.json"; import blastOfTempest from "@/data/mappings/blast-of-tempest.json"; +import loveAndLies from "@/data/mappings/love-and-lies.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -797,6 +798,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ initialD, isThisAZombie, blastOfTempest, + loveAndLies, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/love-and-lies.json b/src/data/mappings/love-and-lies.json new file mode 100644 index 0000000..0059eb6 --- /dev/null +++ b/src/data/mappings/love-and-lies.json @@ -0,0 +1,36 @@ +{ + "anilistAnimeId": 98320, + "anilistMangaId": 85566, + "title": "LOVE and LIES", + "sourceNotes": "Single 12-episode season (2017), the only TV anime. Source is the manga Koi to Uso, serialized in the Manga Box app in short installments; community guides use a fine chapter numbering (~287 chapters) in which the anime ends at chapter 118, while AniList lists 301 chapters (including bonus/extra installments). Manga complete. Per-episode chapter boundaries are approximate (proportional across the ~118 adapted chapters, aligned to episode narrative beats). A 2-episode OVA exists but is home-video (excluded). Unadapted tail extended to AniList's final count of 301.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 30], + "arc": "Confession & Assignment" + }, + { + "episodes": [4, 6], + "chapters": [31, 60], + "arc": "Family Camp & Ministry Seminar" + }, + { + "episodes": [7, 9], + "chapters": [61, 90], + "arc": "School Festival" + }, + { + "episodes": [10, 12], + "chapters": [91, 118], + "arc": "Wedding Trip & Ririna's Strategy" + }, + { + "chapters": [119, 220], + "arc": "Deepening Love Triangle" + }, + { + "chapters": [221, 301], + "arc": "Choosing an Ending" + } + ] +} From 915f79e9b069bedd56c835bb4baa6787beb79125 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:09 -0400 Subject: [PATCH 060/100] KSN: add `boarding-school-juliet.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 12 arcs covering episodes 1–12 ↔ chapters 1–121 - anime `101310` → manga `86279` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/boarding-school-juliet.json | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/data/mappings/boarding-school-juliet.json diff --git a/src/data/index.ts b/src/data/index.ts index 78f1768..5bb95a1 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -365,6 +365,7 @@ import initialD from "@/data/mappings/initial-d.json"; import isThisAZombie from "@/data/mappings/is-this-a-zombie.json"; import blastOfTempest from "@/data/mappings/blast-of-tempest.json"; import loveAndLies from "@/data/mappings/love-and-lies.json"; +import boardingSchoolJuliet from "@/data/mappings/boarding-school-juliet.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -799,6 +800,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ isThisAZombie, blastOfTempest, loveAndLies, + boardingSchoolJuliet, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/boarding-school-juliet.json b/src/data/mappings/boarding-school-juliet.json new file mode 100644 index 0000000..305acc4 --- /dev/null +++ b/src/data/mappings/boarding-school-juliet.json @@ -0,0 +1,61 @@ +{ + "anilistAnimeId": 101310, + "anilistMangaId": 86279, + "title": "Boarding School Juliet", + "sourceNotes": "Single 12-episode TV season (LIDEN FILMS, 2018) with no filler. Episode-to-chapter basis from the AnimeFillerGuide conversion: the anime adapts manga chapters 1-19 (through Volume 4), roughly 1.5 chapters per episode. Manga by Yousuke Kaneda is complete at 16 volumes; the story concludes with the \"West Arc\" at chapter 119, and AniList lists 121 chapters counting the volume bonus/extra chapters, so the final chapters-only entry extends to 121. Tail-arc chapter boundaries (post-episode 12) are grouped from Wikipedia volume ranges and ANN chapter titles and are approximate.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 3], + "arc": "Introduction & Confession" + }, + { + "episodes": [3, 4], + "chapters": [4, 7], + "arc": "Princess Char & Hasuki" + }, + { + "episodes": [5, 7], + "chapters": [8, 12], + "arc": "Dahlia Sports Festival" + }, + { + "episodes": [8, 10], + "chapters": [13, 15], + "arc": "Prefects & Char's Present" + }, + { + "episodes": [11, 12], + "chapters": [16, 19], + "arc": "Juliet's Birthday" + }, + { + "chapters": [20, 27], + "arc": "Summer Break / Beach" + }, + { + "chapters": [28, 37], + "arc": "Autumn Festival & Mid-terms" + }, + { + "chapters": [38, 52], + "arc": "School Festival & Prefect Exam" + }, + { + "chapters": [53, 73], + "arc": "Family & Home Visit" + }, + { + "chapters": [74, 89], + "arc": "Prefect Election" + }, + { + "chapters": [90, 100], + "arc": "Exhibition Match & Servant Wars" + }, + { + "chapters": [101, 121], + "arc": "West Arc (Finale)" + } + ] +} From 9653c33559bcaf40b3cd50b9a9e52ebda4c06b26 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:13 -0400 Subject: [PATCH 061/100] KSN: add `skeleton-knight-in-another-world.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–72 - anime `132474` → manga `98900` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../skeleton-knight-in-another-world.json | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/skeleton-knight-in-another-world.json diff --git a/src/data/index.ts b/src/data/index.ts index 5bb95a1..10bebb3 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -366,6 +366,7 @@ import isThisAZombie from "@/data/mappings/is-this-a-zombie.json"; import blastOfTempest from "@/data/mappings/blast-of-tempest.json"; import loveAndLies from "@/data/mappings/love-and-lies.json"; import boardingSchoolJuliet from "@/data/mappings/boarding-school-juliet.json"; +import skeletonKnightInAnotherWorld from "@/data/mappings/skeleton-knight-in-another-world.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -801,6 +802,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ blastOfTempest, loveAndLies, boardingSchoolJuliet, + skeletonKnightInAnotherWorld, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/skeleton-knight-in-another-world.json b/src/data/mappings/skeleton-knight-in-another-world.json new file mode 100644 index 0000000..f3090ee --- /dev/null +++ b/src/data/mappings/skeleton-knight-in-another-world.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 132474, + "anilistMangaId": 98900, + "title": "Skeleton Knight in Another World", + "sourceNotes": "Single-cour TV anime (S1, 12 episodes, 2022) from Studio Kai. The printed source is the light novel (AniList 87239, ongoing), but this mapping uses the ongoing manga adaptation (AniList 98900) because its chapters are numbered continuously and the community \"where to start reading\" boundary lands cleanly at manga chapter 21 (Volume 5). The anime adapts manga chapters 1-20 (manga volumes 1-4), equivalent to light novel volumes 1-3; readers continue at manga ch. 21 / LN vol. 4. Chapter ranges are volume-aligned and approximate (~1.7 chapters per episode, some minor LN arcs cut). Manga ongoing (current ch. 72, vol. 15). A 12-episode Season 2 began airing July 2026 (AniList 185542) and is not covered here.", + "mappings": [ + { + "episodes": [1, 5], + "chapters": [1, 10], + "arc": "Diento & Slave Market Arc" + }, + { + "episodes": [6, 8], + "chapters": [11, 15], + "arc": "Elf Village & Nohzan Conflict Arc" + }, + { + "episodes": [9, 12], + "chapters": [16, 20], + "arc": "Rhoden Capital & Beastfolk Arc" + }, + { + "chapters": [21, 72], + "arc": "Post-anime continuation (unadapted)" + } + ] +} From ca29a09f12d6dca33a359b6644d391bf7e707933 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:16 -0400 Subject: [PATCH 062/100] KSN: add `my-senpai-is-annoying.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–294 - anime `120646` → manga `103111` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/my-senpai-is-annoying.json | 22 ++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/my-senpai-is-annoying.json diff --git a/src/data/index.ts b/src/data/index.ts index 10bebb3..0ea3a0a 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -367,6 +367,7 @@ import blastOfTempest from "@/data/mappings/blast-of-tempest.json"; import loveAndLies from "@/data/mappings/love-and-lies.json"; import boardingSchoolJuliet from "@/data/mappings/boarding-school-juliet.json"; import skeletonKnightInAnotherWorld from "@/data/mappings/skeleton-knight-in-another-world.json"; +import mySenpaiIsAnnoying from "@/data/mappings/my-senpai-is-annoying.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -803,6 +804,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ loveAndLies, boardingSchoolJuliet, skeletonKnightInAnotherWorld, + mySenpaiIsAnnoying, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/my-senpai-is-annoying.json b/src/data/mappings/my-senpai-is-annoying.json new file mode 100644 index 0000000..fa638ae --- /dev/null +++ b/src/data/mappings/my-senpai-is-annoying.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 120646, + "anilistMangaId": 103111, + "title": "My Senpai is Annoying", + "sourceNotes": "Single 12-episode TV season (2021, Doga Kobo, dir. Ryota Itoh); it is the first and only season, so episode numbers are non-cumulative. Source is Shiro Manta's 4-koma slice-of-life comedy Senpai ga Uzai Kouhai no Hanashi (id 103111). AniList lists the manga as complete at 294 chapters, but that count includes bonus/split chapters — the published main run ended on 2024-07-26 at chapter 236 across 13 volumes; the tail entry is extended to AniList's 294 per convention. 4-koma gag source, so chapter ranges are approximate: the anime samples short vignettes out of order and skips a number of skits rather than mapping 1:1, and there are no story arcs. Community guides say the anime ends around chapter 76, so the 12 episodes are treated as two coarse episodic groups plus an unadapted manga tail; a reader continues from roughly chapter 77 to the finale. No theatrical films exist, so no movies are listed.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 38], + "arc": "Episodes 1-6 (Futaba and Takeda's office everyday-life vignettes; 4-koma, approximate)" + }, + { + "episodes": [7, 12], + "chapters": [39, 76], + "arc": "Episodes 7-12 (continued cast antics through the anime finale; 4-koma, approximate)" + }, + { + "chapters": [77, 294], + "arc": "Later vignettes to the finale (unadapted; 4-koma, approximate)" + } + ] +} From c1a05c97ec314a7172941ff70a2c07c5a655546d Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:19 -0400 Subject: [PATCH 063/100] KSN: add `reincarnated-as-a-sword.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–97 - anime `139587` → manga `98014` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../mappings/reincarnated-as-a-sword.json | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/reincarnated-as-a-sword.json diff --git a/src/data/index.ts b/src/data/index.ts index 0ea3a0a..644a683 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -368,6 +368,7 @@ import loveAndLies from "@/data/mappings/love-and-lies.json"; import boardingSchoolJuliet from "@/data/mappings/boarding-school-juliet.json"; import skeletonKnightInAnotherWorld from "@/data/mappings/skeleton-knight-in-another-world.json"; import mySenpaiIsAnnoying from "@/data/mappings/my-senpai-is-annoying.json"; +import reincarnatedAsASword from "@/data/mappings/reincarnated-as-a-sword.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -805,6 +806,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ boardingSchoolJuliet, skeletonKnightInAnotherWorld, mySenpaiIsAnnoying, + reincarnatedAsASword, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/reincarnated-as-a-sword.json b/src/data/mappings/reincarnated-as-a-sword.json new file mode 100644 index 0000000..c75e8d3 --- /dev/null +++ b/src/data/mappings/reincarnated-as-a-sword.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 139587, + "anilistMangaId": 98014, + "title": "Reincarnated as a Sword", + "sourceNotes": "12-episode ONA (C2C, 2022); use the S1 anime id 139587. The printed source is Yuu Tanaka's light novel (AniList id 97466), but that has no continuous chapter numbering, so this maps to the Tomowo Maruyama manga adaptation (AniList id 98014), which uses the running chapter numbers community episode-to-source guides reference. Manga ongoing (chapter 97 as of June 2026; AniList lists no count). The anime adapts manga chapters 1-27 (LN vol 1 through vol 2 ch 3); guides say to resume the manga at Vol 6, Ch 28 (the Undead Dungeon arc) after the anime. Season 2 announced for Oct 2026. Episode boundaries within each arc are approximate; the unadapted tail is a single chapters-only entry since later per-arc manga chapter boundaries are not firmly documented.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 7], + "arc": "Introduction (Fran and Teacher / Alessa)" + }, + { + "episodes": [4, 7], + "chapters": [8, 15], + "arc": "Goblin Dungeon Arc" + }, + { + "episodes": [8, 12], + "chapters": [16, 27], + "arc": "Spider Dungeon Arc" + }, + { + "chapters": [28, 97], + "arc": "Undead Dungeon Arc onward (unadapted)" + } + ] +} From 291d253c3391e176f4fe8d24403d2ae48e031df2 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:22 -0400 Subject: [PATCH 064/100] KSN: add `a-couple-of-cuckoos.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–36 ↔ chapters 1–300 - anime `132052` → manga `114383` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/a-couple-of-cuckoos.json | 52 ++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/data/mappings/a-couple-of-cuckoos.json diff --git a/src/data/index.ts b/src/data/index.ts index 644a683..b200a04 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -369,6 +369,7 @@ import boardingSchoolJuliet from "@/data/mappings/boarding-school-juliet.json"; import skeletonKnightInAnotherWorld from "@/data/mappings/skeleton-knight-in-another-world.json"; import mySenpaiIsAnnoying from "@/data/mappings/my-senpai-is-annoying.json"; import reincarnatedAsASword from "@/data/mappings/reincarnated-as-a-sword.json"; +import aCoupleOfCuckoos from "@/data/mappings/a-couple-of-cuckoos.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -807,6 +808,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ skeletonKnightInAnotherWorld, mySenpaiIsAnnoying, reincarnatedAsASword, + aCoupleOfCuckoos, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/a-couple-of-cuckoos.json b/src/data/mappings/a-couple-of-cuckoos.json new file mode 100644 index 0000000..39ad9a8 --- /dev/null +++ b/src/data/mappings/a-couple-of-cuckoos.json @@ -0,0 +1,52 @@ +{ + "anilistAnimeId": 132052, + "anilistMangaId": 114383, + "title": "A Couple of Cuckoos", + "sourceNotes": "Cumulative episodes across S1 (24 eps, 2 cours, 2022) + S2 (12 eps, 2025) = 36 total; S2E1 is cumulative episode 25. Faithful ~2-3-chapters-per-episode adaptation of Miki Yoshikawa's romcom manga (Weekly Shonen Magazine), 0 filler. S1 covers chapters 1-56 (a viewer resumes at ch 57); S2 covers roughly ch 57-112 (a viewer resumes at ch 113). The adaptation reorders a few late-S1 chapters: S1E24 pulls ch 59-60 forward while S2E25 backfills the skipped ch 57-58, so chapter ranges here are presented monotonically (S1 = ch 1-56, S2 = ch 57-112) to match the clean \"start reading\" points rather than strict adaptation order. Since the source has no official arc names, groupings are a descriptive segmentation of this love-polygon romcom. Manga is ongoing and entered its final arc on Jan 28, 2026 (current ch. ~300, 33 volumes); the unadapted tail is chapters-only. The \"Kakkou no Iikagen\" YouTube mini-series is a promotional short spin-off and is not mapped.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 8], + "arc": "The Baby Swap & the Arranged Engagement" + }, + { + "episodes": [5, 9], + "chapters": [9, 21], + "arc": "Erika Transfers In: School Life & the Love Square" + }, + { + "episodes": [10, 13], + "chapters": [22, 30], + "arc": "Hiro, Sachi & Deepening Feelings" + }, + { + "episodes": [14, 19], + "chapters": [31, 44], + "arc": "Summer Break: Beach, Idol Work & the Festival" + }, + { + "episodes": [20, 24], + "chapters": [45, 56], + "arc": "The Amano Family & the S1 Finale" + }, + { + "episodes": [25, 28], + "chapters": [57, 76], + "arc": "New Term: Rivalries & the Culture Festival" + }, + { + "episodes": [29, 32], + "chapters": [77, 95], + "arc": "Shifting Hearts & the Marriage Question" + }, + { + "episodes": [33, 36], + "chapters": [96, 112], + "arc": "Confessions & the S2 Finale" + }, + { + "chapters": [113, 300], + "arc": "Beyond the Anime (manga-only, ongoing final arc)" + } + ] +} From 4476dd8f38dd668d74f3621eda072f3a9900ad1a Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:25 -0400 Subject: [PATCH 065/100] KSN: add `remake-our-life.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–12 ↔ chapters 1–12 - anime `114065` → manga `105819` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/remake-our-life.json | 36 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/data/mappings/remake-our-life.json diff --git a/src/data/index.ts b/src/data/index.ts index b200a04..abe7dc9 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -370,6 +370,7 @@ import skeletonKnightInAnotherWorld from "@/data/mappings/skeleton-knight-in-ano import mySenpaiIsAnnoying from "@/data/mappings/my-senpai-is-annoying.json"; import reincarnatedAsASword from "@/data/mappings/reincarnated-as-a-sword.json"; import aCoupleOfCuckoos from "@/data/mappings/a-couple-of-cuckoos.json"; +import remakeOurLife from "@/data/mappings/remake-our-life.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -809,6 +810,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ mySenpaiIsAnnoying, reincarnatedAsASword, aCoupleOfCuckoos, + remakeOurLife, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/remake-our-life.json b/src/data/mappings/remake-our-life.json new file mode 100644 index 0000000..c6d864c --- /dev/null +++ b/src/data/mappings/remake-our-life.json @@ -0,0 +1,36 @@ +{ + "anilistAnimeId": 114065, + "anilistMangaId": 105819, + "title": "Remake Our Life!", + "sourceNotes": "Single-cour 12-episode anime by feel (2021), plus an unnumbered recap (ep 6.5) that is not counted in the episode numbering. The source is Nachi Kio's light novel (AniList 105819, NOVEL format), which is complete at 12 main volumes (March 2017 - March 2023). The LN exposes no continuous chapter numbering, so ranges use LIGHT-NOVEL VOLUME numbers as the unit and are approximate (~3 episodes per volume). Multiple guides agree the anime adapts LN volumes 1-4, ending on the Volume 4 \"changed future\" twist; readers are advised to continue from Volume 5. Volumes 5-12 (final arc begins at vol 11) are unadapted.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "Volume 1: Ten Years Back / Becoming a Creator" + }, + { + "episodes": [4, 6], + "chapters": [2, 2], + "arc": "Volume 2: Finding Something Worth Getting Serious About" + }, + { + "episodes": [7, 9], + "chapters": [3, 3], + "arc": "Volume 3" + }, + { + "episodes": [10, 12], + "chapters": [4, 4], + "arc": "Volume 4: The Changed Future" + }, + { + "chapters": [5, 10], + "arc": "Volumes 5-10 (unadapted)" + }, + { + "chapters": [11, 12], + "arc": "Volumes 11-12: Final Arc (unadapted)" + } + ] +} From 3ccb742d373e968a2c665788cdb67d1c4e69658f Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:28 -0400 Subject: [PATCH 066/100] KSN: add `chained-soldier.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 11 arcs covering episodes 1–24 ↔ chapters 1–182 - anime `141821` → manga `106064` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/chained-soldier.json | 62 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/data/mappings/chained-soldier.json diff --git a/src/data/index.ts b/src/data/index.ts index abe7dc9..6c74fdf 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -371,6 +371,7 @@ import mySenpaiIsAnnoying from "@/data/mappings/my-senpai-is-annoying.json"; import reincarnatedAsASword from "@/data/mappings/reincarnated-as-a-sword.json"; import aCoupleOfCuckoos from "@/data/mappings/a-couple-of-cuckoos.json"; import remakeOurLife from "@/data/mappings/remake-our-life.json"; +import chainedSoldier from "@/data/mappings/chained-soldier.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -811,6 +812,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ reincarnatedAsASword, aCoupleOfCuckoos, remakeOurLife, + chainedSoldier, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/chained-soldier.json b/src/data/mappings/chained-soldier.json new file mode 100644 index 0000000..2f6d45e --- /dev/null +++ b/src/data/mappings/chained-soldier.json @@ -0,0 +1,62 @@ +{ + "anilistAnimeId": 141821, + "anilistMangaId": 106064, + "title": "Chained Soldier", + "sourceNotes": "Cumulative episodes across S1 (12, Seven Arcs, 2024) + S2 (12, Passione, 2026) = 24 episodes, adapting the manga through roughly chapter 86 with no filler. Source manga \"Mato Seihei no Slave\" (AniList 106064) by Takahiro/Youhei Takemura is ongoing (~21 volumes, current ch. 182 as of mid-2026). Episode-to-chapter boundaries follow the AnimeFillerGuide conversion table; arc names are community/volume names from the fandom wiki and Wikipedia (mostly unofficial). Some episode-to-chapter overlaps (flashback panels) were normalized to contiguous ranges. The final chapters-only entry covers the large unadapted tail (ch. 87 to current 182).", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 4], + "arc": "Birth of a Slave" + }, + { + "episodes": [3, 4], + "chapters": [5, 13], + "arc": "Kyouka & the 7th Squad" + }, + { + "episodes": [5, 8], + "chapters": [14, 26], + "arc": "Intersquad Tournament" + }, + { + "episodes": [9, 10], + "chapters": [27, 33], + "arc": "Reunion" + }, + { + "episodes": [11, 11], + "chapters": [34, 40], + "arc": "Tenka vs Aoba" + }, + { + "episodes": [12, 12], + "chapters": [41, 45], + "arc": "Homecoming" + }, + { + "episodes": [13, 14], + "chapters": [46, 52], + "arc": "Congregation of Commanders" + }, + { + "episodes": [15, 18], + "chapters": [53, 65], + "arc": "The Azuma Banquet" + }, + { + "episodes": [19, 22], + "chapters": [66, 79], + "arc": "Yokohama Showdown" + }, + { + "episodes": [23, 24], + "chapters": [80, 86], + "arc": "Slave: Heaven" + }, + { + "chapters": [87, 182], + "arc": "Post-Anime Arcs (Unadapted)" + } + ] +} From 2dcb58640ef6760f78f39e81136f7bcb682aac6d Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:32 -0400 Subject: [PATCH 067/100] KSN: add `assassins-pride.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–13 - anime `104722` → manga `99350` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/assassins-pride.json | 32 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/assassins-pride.json diff --git a/src/data/index.ts b/src/data/index.ts index 6c74fdf..c79276c 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -372,6 +372,7 @@ import reincarnatedAsASword from "@/data/mappings/reincarnated-as-a-sword.json"; import aCoupleOfCuckoos from "@/data/mappings/a-couple-of-cuckoos.json"; import remakeOurLife from "@/data/mappings/remake-our-life.json"; import chainedSoldier from "@/data/mappings/chained-soldier.json"; +import assassinsPride from "@/data/mappings/assassins-pride.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -813,6 +814,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ aCoupleOfCuckoos, remakeOurLife, chainedSoldier, + assassinsPride, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/assassins-pride.json b/src/data/mappings/assassins-pride.json new file mode 100644 index 0000000..4767450 --- /dev/null +++ b/src/data/mappings/assassins-pride.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 104722, + "anilistMangaId": 99350, + "title": "Assassin's Pride", + "sourceNotes": "LN-based; ranges are by NOVEL VOLUME (not chapters) of Kei Amagi's \"Assassin's Pride\" light novel (AniList id 99350; 13-volume main series complete in 2021, plus 2 \"Secret Garden\" side-story volumes). The single 12-episode 2019 anime adapts roughly volumes 1-5 but NON-SEQUENTIALLY and loosely: eps 1-3 = Vol 1 (Melida gains mana under tutor Kufa), eps 4-6 = Vol 2 (the Luna Lumiere / \"Queen Selection Battle\" tournament with twins Mule & Salacha), eps 7-9 = Vol 5 (\"The Abyssal Feast\" detour), eps 10-12 = Vol 3 (\"Court of Fate\" / Labyrinth Library, Mule & Salacha return). Volume 4 (\"Sakura Revolt Railway\") is skipped entirely; adaptation guides recommend readers resume at Vol 6. Chapters[] therefore encode volume numbers, and the sequence is intentionally out of numeric order to follow episode progression. Vols 6-13 are unadapted.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "The Incompetent Gifted Girl (Vol 1)" + }, + { + "episodes": [4, 6], + "chapters": [2, 2], + "arc": "Luna Lumiere / Queen Selection Battle (Vol 2)" + }, + { + "episodes": [7, 9], + "chapters": [5, 5], + "arc": "The Abyssal Feast (Vol 5)" + }, + { + "episodes": [10, 12], + "chapters": [3, 3], + "arc": "Court of Fate / Labyrinth Library (Vol 3)" + }, + { + "chapters": [6, 13], + "arc": "Post-anime volumes (Vols 6-13, unadapted; Vol 4 skipped)" + } + ] +} From 09df88ef783c13d56d7aa15323cb2d4557b620e2 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:35 -0400 Subject: [PATCH 068/100] KSN: add `greatest-demon-lord-reborn-typical-nobody.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 10 arcs covering episodes 1–12 ↔ chapters 1–122 - anime `130586` → manga `113484` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + ...test-demon-lord-reborn-typical-nobody.json | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/data/mappings/greatest-demon-lord-reborn-typical-nobody.json diff --git a/src/data/index.ts b/src/data/index.ts index c79276c..56b8263 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -373,6 +373,7 @@ import aCoupleOfCuckoos from "@/data/mappings/a-couple-of-cuckoos.json"; import remakeOurLife from "@/data/mappings/remake-our-life.json"; import chainedSoldier from "@/data/mappings/chained-soldier.json"; import assassinsPride from "@/data/mappings/assassins-pride.json"; +import greatestDemonLordRebornTypicalNobody from "@/data/mappings/greatest-demon-lord-reborn-typical-nobody.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -815,6 +816,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ remakeOurLife, chainedSoldier, assassinsPride, + greatestDemonLordRebornTypicalNobody, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/greatest-demon-lord-reborn-typical-nobody.json b/src/data/mappings/greatest-demon-lord-reborn-typical-nobody.json new file mode 100644 index 0000000..e25c25e --- /dev/null +++ b/src/data/mappings/greatest-demon-lord-reborn-typical-nobody.json @@ -0,0 +1,51 @@ +{ + "anilistAnimeId": 130586, + "anilistMangaId": 113484, + "title": "The Greatest Demon Lord Is Reborn as a Typical Nobody", + "sourceNotes": "LN-based; mapped against the Fujimi Fantasia Bunko light novel (AniList NOVEL entry 113484), which the community sync guides use — one story arc corresponds to one LN volume. Single 12-episode TV season (2022), so episodes are non-cumulative. The anime adapts LN volumes 1-3 (arcs 1-3), heavily reordering and adding original scenes; readers should continue at volume 4. LN complete at 10 volumes (AniList: 122 chapters). Volume 1 (21 chapters) and volume 2 (16 chapters) counts are documented on the series wiki; chapter boundaries for volumes 3-10 are approximate, evenly distributed to reach the 122-chapter total. The side-story volume 6.5 (\"The Wonderful Life of a Typical Nobody\") is excluded from this numbering. The separate manga (AniList 108441, 35 ch) is a minor, discontinued adaptation and is not the mapping basis.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 21], + "arc": "The Myth-Killing Honor Student" + }, + { + "episodes": [5, 8], + "chapters": [22, 37], + "arc": "The Raging Champion" + }, + { + "episodes": [9, 12], + "chapters": [38, 48], + "arc": "The Catastrophe of the Great Hero" + }, + { + "chapters": [49, 59], + "arc": "The Lonely Divine Scholar" + }, + { + "chapters": [60, 70], + "arc": "Papal Baptism" + }, + { + "chapters": [71, 81], + "arc": "Former Typical Nobody" + }, + { + "chapters": [82, 92], + "arc": "Clown of the Outer Gods (Evil God Clown)" + }, + { + "chapters": [93, 103], + "arc": "Goddess Awakening" + }, + { + "chapters": [104, 113], + "arc": "Dream of the Evil God" + }, + { + "chapters": [114, 122], + "arc": "Advent of the Great Demon King" + } + ] +} From 87c99298d3bbb766980521a69fdfebb743cb549e Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:38 -0400 Subject: [PATCH 069/100] KSN: add `o-maidens-in-your-savage-season.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–33 - anime `105932` → manga `101719` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../o-maidens-in-your-savage-season.json | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/data/mappings/o-maidens-in-your-savage-season.json diff --git a/src/data/index.ts b/src/data/index.ts index 56b8263..8afe157 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -374,6 +374,7 @@ import remakeOurLife from "@/data/mappings/remake-our-life.json"; import chainedSoldier from "@/data/mappings/chained-soldier.json"; import assassinsPride from "@/data/mappings/assassins-pride.json"; import greatestDemonLordRebornTypicalNobody from "@/data/mappings/greatest-demon-lord-reborn-typical-nobody.json"; +import oMaidensInYourSavageSeason from "@/data/mappings/o-maidens-in-your-savage-season.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -817,6 +818,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ chainedSoldier, assassinsPride, greatestDemonLordRebornTypicalNobody, + oMaidensInYourSavageSeason, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/o-maidens-in-your-savage-season.json b/src/data/mappings/o-maidens-in-your-savage-season.json new file mode 100644 index 0000000..a8679ef --- /dev/null +++ b/src/data/mappings/o-maidens-in-your-savage-season.json @@ -0,0 +1,28 @@ +{ + "anilistAnimeId": 105932, + "anilistMangaId": 101719, + "title": "O Maidens in Your Savage Season", + "sourceNotes": "Single-cour TV anime (12 episodes, 2019, Lay-duce) adapting Mari Okada & Nao Emoto's ensemble literature-club drama. The manga is complete at 32 numbered chapters across 8 volumes (V1: ch1-4, V2: 5-8, V3: 9-12, V4: 13-16, V5: 17-20, V6: 21-23, V7: 24-27, V8: 28-32); AniList reports 33 chapters because it counts a bonus/final extra, so the last entry extends to 33. The manga and anime concluded the same season (July-Sept 2019) and the anime faithfully adapts the full story, condensing roughly 2.7 chapters per episode with a slightly restructured but complete ending — a reader who finishes the anime has effectively finished the manga. This show has no canonical arc names; the segment titles below are descriptive narrative phases and the episode-to-chapter boundaries are approximate.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 8], + "arc": "The Literature Club & Awakening Desire" + }, + { + "episodes": [4, 6], + "chapters": [9, 16], + "arc": "Kazusa & Izumi / Niina's Past" + }, + { + "episodes": [7, 9], + "chapters": [17, 24], + "arc": "Momoko, Sonezaki & Tangled Feelings" + }, + { + "episodes": [10, 12], + "chapters": [25, 33], + "arc": "Summer Camp & Resolution (Finale)" + } + ] +} From c421f3a6d5b4d44a6c0e3cfbabeaf762b9110a31 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:41 -0400 Subject: [PATCH 070/100] KSN: add `our-last-crusade.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–24 ↔ chapters 1–16 - anime `112667` → manga `100670` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/our-last-crusade.json | 52 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/data/mappings/our-last-crusade.json diff --git a/src/data/index.ts b/src/data/index.ts index 8afe157..fbadbef 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -375,6 +375,7 @@ import chainedSoldier from "@/data/mappings/chained-soldier.json"; import assassinsPride from "@/data/mappings/assassins-pride.json"; import greatestDemonLordRebornTypicalNobody from "@/data/mappings/greatest-demon-lord-reborn-typical-nobody.json"; import oMaidensInYourSavageSeason from "@/data/mappings/o-maidens-in-your-savage-season.json"; +import ourLastCrusade from "@/data/mappings/our-last-crusade.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -819,6 +820,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ assassinsPride, greatestDemonLordRebornTypicalNobody, oMaidensInYourSavageSeason, + ourLastCrusade, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/our-last-crusade.json b/src/data/mappings/our-last-crusade.json new file mode 100644 index 0000000..ccfc890 --- /dev/null +++ b/src/data/mappings/our-last-crusade.json @@ -0,0 +1,52 @@ +{ + "anilistAnimeId": 112667, + "anilistMangaId": 100670, + "title": "Our Last Crusade or the Rise of a New World", + "sourceNotes": "LN-based mapping (AniList source id 100670, the Fujimi Fantasia Bunko novel by Kei Sazane); the discontinued Okama manga (43 ch.) is a minor side-adaptation and is not used. Ranges are by LN VOLUME, not chapter — the \"chapters\" fields hold volume numbers. Cumulative episodes across S1 (12) + S2 (12) = 24. Season 1 adapts volumes 1-4; Season 2 adapts volumes 5-8. Arc names are the anime's cour-segment titles (Wikipedia episode list), aligned one segment per volume as an approximation — the third novel in particular was heavily condensed. Light novel is ongoing (16 volumes published, plus 3 Secret File short-story collections); volumes 9-16 are unadapted.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "Encounter (Vol. 1)" + }, + { + "episodes": [4, 5], + "chapters": [2, 2], + "arc": "Intersection (Vol. 2)" + }, + { + "episodes": [6, 9], + "chapters": [3, 3], + "arc": "Paradise (Vol. 3)" + }, + { + "episodes": [10, 12], + "chapters": [4, 4], + "arc": "Beginning (Vol. 4)" + }, + { + "episodes": [13, 15], + "chapters": [5, 5], + "arc": "Witch (Vol. 5)" + }, + { + "episodes": [16, 18], + "chapters": [6, 6], + "arc": "Line of Descent (Vol. 6)" + }, + { + "episodes": [19, 22], + "chapters": [7, 7], + "arc": "Last Crusade (Vol. 7)" + }, + { + "episodes": [23, 24], + "chapters": [8, 8], + "arc": "Morning Star (Vol. 8)" + }, + { + "chapters": [9, 16], + "arc": "Unadapted (Vols. 9-16)" + } + ] +} From 9e647c5408695f4bbe21ef2c9959b30a241ca5fd Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:44 -0400 Subject: [PATCH 071/100] KSN: add `ragna-crimson.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–24 ↔ chapters 1–94 - anime `146493` → manga `99065` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/ragna-crimson.json | 32 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/ragna-crimson.json diff --git a/src/data/index.ts b/src/data/index.ts index fbadbef..7440e77 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -376,6 +376,7 @@ import assassinsPride from "@/data/mappings/assassins-pride.json"; import greatestDemonLordRebornTypicalNobody from "@/data/mappings/greatest-demon-lord-reborn-typical-nobody.json"; import oMaidensInYourSavageSeason from "@/data/mappings/o-maidens-in-your-savage-season.json"; import ourLastCrusade from "@/data/mappings/our-last-crusade.json"; +import ragnaCrimson from "@/data/mappings/ragna-crimson.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -821,6 +822,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ greatestDemonLordRebornTypicalNobody, oMaidensInYourSavageSeason, ourLastCrusade, + ragnaCrimson, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/ragna-crimson.json b/src/data/mappings/ragna-crimson.json new file mode 100644 index 0000000..7cdbf4c --- /dev/null +++ b/src/data/mappings/ragna-crimson.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 146493, + "anilistMangaId": 99065, + "title": "Ragna Crimson", + "sourceNotes": "Single 24-episode TV anime (two consecutive cours, Oct 2023-Mar 2024); episodes are non-cumulative since there is only one season. The anime adapts manga chapters 1-56. Arc names and chapter/episode boundaries are the fan/community divisions from the Ragna Crimson Fandom wiki (the wiki notes these are unofficial). Boundary chapters and episodes overlap at arc edges (e.g. ch. 7 and ep. 4 straddle the first two arcs) because the adaptation splits chapters across arcs. Manga is ongoing (current ch. ~94 as of June 2026); chapters 57 onward are unadapted.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 7], + "arc": "Birth of the Reaper" + }, + { + "episodes": [4, 8], + "chapters": [7, 16], + "arc": "Royal Capital" + }, + { + "episodes": [8, 17], + "chapters": [17, 40], + "arc": "Argentum Corps" + }, + { + "episodes": [18, 24], + "chapters": [41, 56], + "arc": "Winged Bloodline" + }, + { + "chapters": [57, 94], + "arc": "Post-Winged Bloodline (unadapted)" + } + ] +} From 6ca694640360be4e30b6d4d48dbff56573c2bdab Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:47 -0400 Subject: [PATCH 072/100] KSN: add `seitokai-yakuindomo.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–26 ↔ chapters 1–655 - 2 movies - anime `8675` → manga `44110` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/seitokai-yakuindomo.json | 38 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/data/mappings/seitokai-yakuindomo.json diff --git a/src/data/index.ts b/src/data/index.ts index 7440e77..4cc081d 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -377,6 +377,7 @@ import greatestDemonLordRebornTypicalNobody from "@/data/mappings/greatest-demon import oMaidensInYourSavageSeason from "@/data/mappings/o-maidens-in-your-savage-season.json"; import ourLastCrusade from "@/data/mappings/our-last-crusade.json"; import ragnaCrimson from "@/data/mappings/ragna-crimson.json"; +import seitokaiYakuindomo from "@/data/mappings/seitokai-yakuindomo.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -823,6 +824,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ oMaidensInYourSavageSeason, ourLastCrusade, ragnaCrimson, + seitokaiYakuindomo, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/seitokai-yakuindomo.json b/src/data/mappings/seitokai-yakuindomo.json new file mode 100644 index 0000000..6631a96 --- /dev/null +++ b/src/data/mappings/seitokai-yakuindomo.json @@ -0,0 +1,38 @@ +{ + "anilistAnimeId": 8675, + "anilistMangaId": 44110, + "title": "Seitokai Yakuindomo", + "sourceNotes": "Source is the completed Seitokai Yakuindomo 4-koma gag manga by Tozen Ujiie (AniList 44110): 655 chapters / 22 volumes, ran 2007-2021 (Manga complete). This is an episodic 4-koma with NO story arcs — the anime pulls short gag strips out of chronological order across both seasons, so exact per-episode chapter boundaries do not exist and the ranges below are APPROXIMATE season blocks. Cumulative episodes across S1 (13) + S2 \"Seitokai Yakuindomo*\" (13) = 26. Community/fandom consensus is that by the end of the two TV seasons (plus the bundled OVAs) roughly the first ~280 chapters' worth of material had been adapted, and readers picking up where the anime leaves off should start around chapter 280; everything from ~281 to 655 is unadapted by the TV run. The two theatrical films (2017, 2021) are new-animation canon continuations and are listed in movies[]. Chapter split within the anime block is an even estimate, not a strip-accurate boundary.", + "mappings": [ + { + "episodes": [1, 13], + "chapters": [1, 140], + "arc": "Season 1" + }, + { + "episodes": [14, 26], + "chapters": [141, 280], + "arc": "Season 2 (Seitokai Yakuindomo*)" + }, + { + "chapters": [281, 655], + "arc": "Post-anime (unadapted)" + } + ], + "movies": [ + { + "anilistId": 98240, + "title": "Seitokai Yakuindomo the Movie", + "year": 2017, + "afterEpisode": 26, + "note": "Canon theatrical feature with new animation continuing the TV series' gag skits; adapts additional manga strips beyond the second season." + }, + { + "anilistId": 113692, + "title": "Seitokai Yakuindomo the Movie 2", + "year": 2021, + "afterEpisode": 26, + "note": "Second canon theatrical feature (delayed from 2020 to Jan 2021), new-animation continuation released around the manga's conclusion." + } + ] +} From fa18591f38f229d4ac8f5773e4d2d178448ec125 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:50 -0400 Subject: [PATCH 073/100] KSN: add `why-the-hell-are-you-here-teacher.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–131 - anime `104325` → manga `97827` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../why-the-hell-are-you-here-teacher.json | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/why-the-hell-are-you-here-teacher.json diff --git a/src/data/index.ts b/src/data/index.ts index 4cc081d..5410251 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -378,6 +378,7 @@ import oMaidensInYourSavageSeason from "@/data/mappings/o-maidens-in-your-savage import ourLastCrusade from "@/data/mappings/our-last-crusade.json"; import ragnaCrimson from "@/data/mappings/ragna-crimson.json"; import seitokaiYakuindomo from "@/data/mappings/seitokai-yakuindomo.json"; +import whyTheHellAreYouHereTeacher from "@/data/mappings/why-the-hell-are-you-here-teacher.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -825,6 +826,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ ourLastCrusade, ragnaCrimson, seitokaiYakuindomo, + whyTheHellAreYouHereTeacher, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/why-the-hell-are-you-here-teacher.json b/src/data/mappings/why-the-hell-are-you-here-teacher.json new file mode 100644 index 0000000..463b10b --- /dev/null +++ b/src/data/mappings/why-the-hell-are-you-here-teacher.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 104325, + "anilistMangaId": 97827, + "title": "Why the hell are you here, Teacher!?", + "sourceNotes": "Single-cour TV_SHORT (12 episodes, ~7 min each) from 2019; episodes are cumulative within the one season. The source manga by Soborou is an omnibus told couple-by-couple (roughly 10 chapters per tankoubon volume), each volume centering a different older-female-teacher / younger-male-student pair. The anime adapts the first four couples in order — Kojima (ep 1-4), Matsukaze (ep 5-6), Hazakura (ep 7-9), and school-nurse Tachibana (ep 10-12) — covering chapters 1-40; anime-to-manga guides confirm chapter 40 ends the anime's couples and readers resume at chapter 41. Because it is a gag/omnibus 4-koma-style romcom with no continuous plot, chapter boundaries are per-couple volume splits and approximate. Manga complete at 131 chapters (AniList); a Blu-ray OVA \"Thirteenth Period\" special exists but is not theatrical. Chapters 41-131 introduce new pairings and are unadapted.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 10], + "arc": "Kana Kojima" + }, + { + "episodes": [5, 6], + "chapters": [11, 20], + "arc": "Mayu Matsukaze" + }, + { + "episodes": [7, 9], + "chapters": [21, 30], + "arc": "Hikari Hazakura" + }, + { + "episodes": [10, 12], + "chapters": [31, 40], + "arc": "Chizuru Tachibana" + }, + { + "chapters": [41, 131], + "arc": "New Couples (unadapted)" + } + ] +} From 03e3cb5a3341279d516846c2b74901de80bed104 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:53 -0400 Subject: [PATCH 074/100] KSN: add `maoyu.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–63 - anime `14833` → manga `58125` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/maoyu.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/maoyu.json diff --git a/src/data/index.ts b/src/data/index.ts index 5410251..c4675f1 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -379,6 +379,7 @@ import ourLastCrusade from "@/data/mappings/our-last-crusade.json"; import ragnaCrimson from "@/data/mappings/ragna-crimson.json"; import seitokaiYakuindomo from "@/data/mappings/seitokai-yakuindomo.json"; import whyTheHellAreYouHereTeacher from "@/data/mappings/why-the-hell-are-you-here-teacher.json"; +import maoyu from "@/data/mappings/maoyu.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -827,6 +828,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ ragnaCrimson, seitokaiYakuindomo, whyTheHellAreYouHereTeacher, + maoyu, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/maoyu.json b/src/data/mappings/maoyu.json new file mode 100644 index 0000000..b58d237 --- /dev/null +++ b/src/data/mappings/maoyu.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 14833, + "anilistMangaId": 58125, + "title": "Maoyu: Archenemy & Hero", + "sourceNotes": "Single 12-episode 2013 anime by Arms (plus a 9.5 recap special, not counted in the sequence); no later seasons, so anilistAnimeId is 14833. Light-novel sourced: mapped to the AniList novel entry (id 58125), which is complete at 5 main volumes + 3 side-story volumes and lists 63 chapters. The novel numbers its content as \"scrolls\" (Vol. 1 = 11 scrolls, Vol. 2 = 10 scrolls). The anime is a diligent adaptation covering Vol. 1 in full and Vol. 2 through roughly scroll 5 — community episode-to-source guides advise resuming reading at \"Novel 2, Chapter 5.\" Chapter ranges are by volume/scroll and episode boundaries are approximate; the final entry extends to the source's 63-chapter total. No theatrical films or OVAs exist.", + "mappings": [ + { + "episodes": [1, 9], + "chapters": [1, 11], + "arc": "The Alliance and the Southern Reforms (Vol. 1)" + }, + { + "episodes": [10, 12], + "chapters": [12, 16], + "arc": "Conspiracy of the Kurultai — anime portion (Vol. 2)" + }, + { + "chapters": [17, 63], + "arc": "The War's End (Vols. 2-5, unadapted)" + } + ] +} From c4eb807030e062b45134fc34b1ac97f4c3b16fd9 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:56 -0400 Subject: [PATCH 075/100] KSN: add `azumanga-daioh.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–26 ↔ chapters 1–69 - anime `66` → manga `30085` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/azumanga-daioh.json | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/data/mappings/azumanga-daioh.json diff --git a/src/data/index.ts b/src/data/index.ts index c4675f1..b65f5dd 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -380,6 +380,7 @@ import ragnaCrimson from "@/data/mappings/ragna-crimson.json"; import seitokaiYakuindomo from "@/data/mappings/seitokai-yakuindomo.json"; import whyTheHellAreYouHereTeacher from "@/data/mappings/why-the-hell-are-you-here-teacher.json"; import maoyu from "@/data/mappings/maoyu.json"; +import azumangaDaioh from "@/data/mappings/azumanga-daioh.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -829,6 +830,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ seitokaiYakuindomo, whyTheHellAreYouHereTeacher, maoyu, + azumangaDaioh, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/azumanga-daioh.json b/src/data/mappings/azumanga-daioh.json new file mode 100644 index 0000000..c18b86a --- /dev/null +++ b/src/data/mappings/azumanga-daioh.json @@ -0,0 +1,23 @@ +{ + "anilistAnimeId": 66, + "anilistMangaId": 30085, + "title": "Azumanga Daioh", + "sourceNotes": "Single 26-episode TV season (J.C.Staff, 2002), no cumulative arithmetic needed. Paired with Kiyohiko Azuma's original Azumanga Daioh yonkoma (4-koma) manga (id 30085), complete at 69 chapters across 4 tankobon volumes — the 1-69 numbering is Anime News Network's retroactive catalog numbering, since the strips were serialized unnumbered in Dengeki Daioh (1999-2002). The manga is organized by calendar month, and both manga and anime follow the cast through three high-school years (April 1999 to graduation March 2002); each of the four volumes covers roughly one year with the second/third volumes straddling a year boundary. The anime year transitions fall at ep 10 (second years, Kagura joins the class) and ep 20 (final/third year, entrance-exam prep). 4-koma slice-of-life source — chapter ranges per school year are approximate and do not map 1:1 to episodes.", + "mappings": [ + { + "episodes": [1, 9], + "chapters": [1, 24], + "arc": "First Year (cast introduced, Osaka transfers in) — vol 1 + early vol 2" + }, + { + "episodes": [10, 19], + "chapters": [25, 48], + "arc": "Second Year (Kagura joins the class, summer trips) — late vol 2 + vol 3" + }, + { + "episodes": [20, 26], + "chapters": [49, 69], + "arc": "Third Year (entrance exams, Okinawa trip, graduation) — vol 4" + } + ] +} From 213a815eca1eed124a43d40e9274026a236b4c68 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:18:59 -0400 Subject: [PATCH 076/100] KSN: add `senko-san.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–93 - anime `105914` → manga `100584` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/senko-san.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/senko-san.json diff --git a/src/data/index.ts b/src/data/index.ts index b65f5dd..8f63517 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -381,6 +381,7 @@ import seitokaiYakuindomo from "@/data/mappings/seitokai-yakuindomo.json"; import whyTheHellAreYouHereTeacher from "@/data/mappings/why-the-hell-are-you-here-teacher.json"; import maoyu from "@/data/mappings/maoyu.json"; import azumangaDaioh from "@/data/mappings/azumanga-daioh.json"; +import senkoSan from "@/data/mappings/senko-san.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -831,6 +832,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ whyTheHellAreYouHereTeacher, maoyu, azumangaDaioh, + senkoSan, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/senko-san.json b/src/data/mappings/senko-san.json new file mode 100644 index 0000000..23132d9 --- /dev/null +++ b/src/data/mappings/senko-san.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 105914, + "anilistMangaId": 100584, + "title": "The Helpful Fox Senko-san", + "sourceNotes": "Single 12-episode TV season (2019, Doga Kobo). Source is Rimukoro's Sewayaki Kitsune no Senko-san manga (id 100584), an episodic slice-of-life serialized on Comic Newtype; it is complete at 12 tankobon volumes / 93 main chapters (volume boundaries per MangaDex: v1 ch1-7, v2 ch8-15, v3 ch16-23, v4 ch24-31, ... v12 ch84-91, plus uncategorized ch92-93; .5 side chapters ignored). Cumulative episodes are trivial here (one season, 12 episodes). Episodic source — chapter ranges are approximate: the short comfort-comedy chapters do not map 1:1 to episodes, and the anime reorders and samples material from roughly volumes 1-4 (the only volumes out when it aired, ch1-31) rather than following a continuous arc. There are no story arcs, so the adaptation is treated as coarse episodic groupings plus an unadapted manga tail. No theatrical films or OVAs exist, so no movies are listed.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 15], + "arc": "Episodes 1-6 (Senko moves in and pampers Nakano; everyday comfort vignettes) — roughly vols 1-2, approximate" + }, + { + "episodes": [7, 12], + "chapters": [16, 31], + "arc": "Episodes 7-12 (Shiro, the beach trip, and more household antics) — roughly vols 3-4, approximate" + }, + { + "chapters": [32, 93], + "arc": "Later chapters to the finale (vols 5-12; unadapted, approximate)" + } + ] +} From e9c1263b04a238431995c42c3c10b088ef155862 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:19:03 -0400 Subject: [PATCH 077/100] KSN: add `interspecies-reviewers.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 13 arcs covering episodes 1–12 ↔ chapters 1–79 - anime `110270` → manga `101175` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/interspecies-reviewers.json | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/data/mappings/interspecies-reviewers.json diff --git a/src/data/index.ts b/src/data/index.ts index 8f63517..99c2317 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -382,6 +382,7 @@ import whyTheHellAreYouHereTeacher from "@/data/mappings/why-the-hell-are-you-he import maoyu from "@/data/mappings/maoyu.json"; import azumangaDaioh from "@/data/mappings/azumanga-daioh.json"; import senkoSan from "@/data/mappings/senko-san.json"; +import interspeciesReviewers from "@/data/mappings/interspecies-reviewers.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -833,6 +834,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ maoyu, azumangaDaioh, senkoSan, + interspeciesReviewers, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/interspecies-reviewers.json b/src/data/mappings/interspecies-reviewers.json new file mode 100644 index 0000000..966d8cb --- /dev/null +++ b/src/data/mappings/interspecies-reviewers.json @@ -0,0 +1,72 @@ +{ + "anilistAnimeId": 110270, + "anilistMangaId": 101175, + "title": "Interspecies Reviewers", + "sourceNotes": "Single 12-episode season (2020); cumulative episodes 1-12 match the broadcast order. Source manga by Amahara/masha is ongoing (11 volumes, ~ch. 79 as of 2026); AniList reports null counts. This is an episodic anthology with no story arcs, so mappings are per-episode, named by the featured brothel/species. Each episode adapts roughly two manga chapters, but the anime freely REORDERS chapters relative to publication (e.g. Ep1 = ch 1,3,2; Ep5 = ch 10,12; Ep6 = ch 11,13), so listed [start,end] spans are approximate and can overlap between adjacent episodes. The anime skips ch. 22 and 24 and ends at ch. 27 (all but the final chapter of Vol. 3); manga readers should continue from ch. 28. Sex scenes in the anime are anime-original.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 3], + "arc": "Elf, Birdmaid & Catgirl Brothels" + }, + { + "episodes": [2, 2], + "chapters": [4, 5], + "arc": "Fairy Brothel (Nectar)" + }, + { + "episodes": [3, 3], + "chapters": [6, 7], + "arc": "Genderswap Inn" + }, + { + "episodes": [4, 4], + "chapters": [8, 9], + "arc": "Salamander & Succubus Joints" + }, + { + "episodes": [5, 5], + "chapters": [10, 12], + "arc": "Cyclops & Mushroom Girls" + }, + { + "episodes": [6, 6], + "chapters": [11, 13], + "arc": "Will o' Wisp & Golem Girls" + }, + { + "episodes": [7, 7], + "chapters": [14, 15], + "arc": "Meidri's Secret & Egg-Laying Show" + }, + { + "episodes": [8, 8], + "chapters": [16, 17], + "arc": "Succubus Tower" + }, + { + "episodes": [9, 9], + "chapters": [18, 19], + "arc": "Ghost Brothel & Lotion" + }, + { + "episodes": [10, 10], + "chapters": [20, 21], + "arc": "Perfect-Score Brothel" + }, + { + "episodes": [11, 11], + "chapters": [23, 25], + "arc": "Philanthropist Succubi & Drunken Fools" + }, + { + "episodes": [12, 12], + "chapters": [26, 27], + "arc": "New Year's Weddings" + }, + { + "chapters": [28, 79], + "arc": "Unadapted (Vol. 3 finale onward)" + } + ] +} From 72ad962a21ae8b74e8fb748cf43f1839fdc49b68 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:19:06 -0400 Subject: [PATCH 078/100] KSN: add `keijo.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–177 - anime `21639` → manga `85929` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/keijo.json | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/keijo.json diff --git a/src/data/index.ts b/src/data/index.ts index 99c2317..d33683e 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -383,6 +383,7 @@ import maoyu from "@/data/mappings/maoyu.json"; import azumangaDaioh from "@/data/mappings/azumanga-daioh.json"; import senkoSan from "@/data/mappings/senko-san.json"; import interspeciesReviewers from "@/data/mappings/interspecies-reviewers.json"; +import keijo from "@/data/mappings/keijo.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -835,6 +836,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ azumangaDaioh, senkoSan, interspeciesReviewers, + keijo, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/keijo.json b/src/data/mappings/keijo.json new file mode 100644 index 0000000..4ca1652 --- /dev/null +++ b/src/data/mappings/keijo.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 21639, + "anilistMangaId": 85929, + "title": "Keijo!!!!!!!!", + "sourceNotes": "Single 12-episode season (2016), no sequel. Source is Daichi Sorayomi's manga \"Keijo!!!!!!!! Hip Whip Girl\" (Weekly Shonen Sunday, complete at 177 chapters / 18 volumes). The anime skips the first ~34 chapters: episode 1 condenses chapters 22-34 into an opening flashback and begins its main narrative on page 4 of chapter 35. From there it adapts roughly 4-5 chapters per episode (with some skipped chapters and page-level splits) up through chapter 90 in the finale, ending mid-East-West War as the Debut War Arc opens. Chapter ranges follow the Keijo Fandom per-episode \"chapters\" fields. Because the anime was cut short, everything from ~chapter 91 to the manga's end (ch 177) is unadapted; a viewer resumes reading around chapter 88-91.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [22, 44], + "arc": "Second Exam & Sweet Room Arc" + }, + { + "episodes": [4, 5], + "chapters": [45, 55], + "arc": "Class Exchange Arc" + }, + { + "episodes": [6, 7], + "chapters": [56, 61], + "arc": "Training Camp (Kyoto) Arc" + }, + { + "episodes": [8, 12], + "chapters": [62, 90], + "arc": "The East-West War Arc" + }, + { + "chapters": [91, 177], + "arc": "The Debut War Arc & Finale (unadapted)" + } + ] +} From 63e68d5d830200e94098fa2fde27b7570dabb80f Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:19:09 -0400 Subject: [PATCH 079/100] KSN: add `vermeil-in-gold.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–12 ↔ chapters 1–41 - anime `146210` → manga `118741` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/vermeil-in-gold.json | 37 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/vermeil-in-gold.json diff --git a/src/data/index.ts b/src/data/index.ts index d33683e..b4712e8 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -384,6 +384,7 @@ import azumangaDaioh from "@/data/mappings/azumanga-daioh.json"; import senkoSan from "@/data/mappings/senko-san.json"; import interspeciesReviewers from "@/data/mappings/interspecies-reviewers.json"; import keijo from "@/data/mappings/keijo.json"; +import vermeilInGold from "@/data/mappings/vermeil-in-gold.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -837,6 +838,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ senkoSan, interspeciesReviewers, keijo, + vermeilInGold, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/vermeil-in-gold.json b/src/data/mappings/vermeil-in-gold.json new file mode 100644 index 0000000..51f8ada --- /dev/null +++ b/src/data/mappings/vermeil-in-gold.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 146210, + "anilistMangaId": 118741, + "title": "Vermeil in Gold", + "sourceNotes": "Single 12-episode TV season (2022) sourced from the Monthly Shonen Gangan manga by Kota Amana and Yoko Umezu. The anime adapts manga chapters 1-17; the fandom/filler guides note the anime reordered some events (notably Vermeil's backstory and the close of the Iolite fight) but coverage is essentially linear at ~1.4 chapters/episode. Read on from chapter 18 (start of volume 5) to continue past the anime. The manga has no officially named story arcs, so arc labels here are descriptive, drawn from episode titles and story beats, and internal chapter boundaries between episodes are approximate. Manga is ongoing (latest ~ch. 41 as of mid-2026, 11 volumes); the final chapters-only entry covers the unadapted remainder through the current chapter.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 4], + "arc": "Summoning the Strongest Familiar" + }, + { + "episodes": [3, 3], + "chapters": [5, 6], + "arc": "The Dragonrider" + }, + { + "episodes": [4, 6], + "chapters": [7, 10], + "arc": "Rampage" + }, + { + "episodes": [7, 9], + "chapters": [11, 14], + "arc": "Class Representative Selection" + }, + { + "episodes": [10, 12], + "chapters": [15, 17], + "arc": "Vermeil's Past" + }, + { + "chapters": [18, 41], + "arc": "Beyond the Anime (unadapted)" + } + ] +} From d72143fa332f71f2303068af236e16ed039fdd88 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:19:12 -0400 Subject: [PATCH 080/100] KSN: add `genius-princes-guide-raising-nation-debt.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–12 - anime `129190` → manga `111631` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ ...ius-princes-guide-raising-nation-debt.json | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/genius-princes-guide-raising-nation-debt.json diff --git a/src/data/index.ts b/src/data/index.ts index b4712e8..91ebf21 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -385,6 +385,7 @@ import senkoSan from "@/data/mappings/senko-san.json"; import interspeciesReviewers from "@/data/mappings/interspecies-reviewers.json"; import keijo from "@/data/mappings/keijo.json"; import vermeilInGold from "@/data/mappings/vermeil-in-gold.json"; +import geniusPrincesGuideRaisingNationDebt from "@/data/mappings/genius-princes-guide-raising-nation-debt.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -839,6 +840,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ interspeciesReviewers, keijo, vermeilInGold, + geniusPrincesGuideRaisingNationDebt, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/genius-princes-guide-raising-nation-debt.json b/src/data/mappings/genius-princes-guide-raising-nation-debt.json new file mode 100644 index 0000000..e7de743 --- /dev/null +++ b/src/data/mappings/genius-princes-guide-raising-nation-debt.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 129190, + "anilistMangaId": 111631, + "title": "The Genius Prince's Guide to Raising a Nation Out of Debt", + "sourceNotes": "Light-novel-based (source: GA Bunko LN by Toru Toba, AniList id 111631; the \"chapters\" ranges below denote LN VOLUME numbers, not chapters, since AniList lists no chapter counts and community episode guides track the LN by volume). The single 12-episode 2022 TV series adapts LN volumes 1-5 at a fast pace and ends heading into volume 6 (per wheredoestheanimeleaveoff). Volume boundaries: Vol 1 = the Marden war / selling-the-kingdom opener (ep 1-2), Vol 2 = the political-marriage and Cavarin conspiracy/rebellion (ep 3-5), Vol 3 = the Levetia Holy Elite / Spirit Festival arc (ep 6-7), Vols 4-5 = the Mealtars merchant-city Summit of Imperial Heirs (ep 8-12). LN ongoing; 12 volumes published (latest Sept 2022). Volume-level ranges are approximate given the compressed adaptation. No theatrical films.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 1], + "arc": "Selling the Kingdom (Marden War)" + }, + { + "episodes": [3, 5], + "chapters": [2, 2], + "arc": "Political Marriage & Cavarin Rebellion" + }, + { + "episodes": [6, 7], + "chapters": [3, 3], + "arc": "Levetia Holy Elite" + }, + { + "episodes": [8, 12], + "chapters": [4, 5], + "arc": "Mealtars Summit of Imperial Heirs" + }, + { + "chapters": [6, 12], + "arc": "Continuing Volumes (unadapted)" + } + ] +} From 5100d6acd1b57d2bdcb244f4c09f6fc8044eb845 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:19:16 -0400 Subject: [PATCH 081/100] KSN: add `im-quitting-heroing.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–12 ↔ chapters 1–44 - anime `140457` → manga `102861` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/im-quitting-heroing.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/im-quitting-heroing.json diff --git a/src/data/index.ts b/src/data/index.ts index 91ebf21..d973f07 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -386,6 +386,7 @@ import interspeciesReviewers from "@/data/mappings/interspecies-reviewers.json"; import keijo from "@/data/mappings/keijo.json"; import vermeilInGold from "@/data/mappings/vermeil-in-gold.json"; import geniusPrincesGuideRaisingNationDebt from "@/data/mappings/genius-princes-guide-raising-nation-debt.json"; +import imQuittingHeroing from "@/data/mappings/im-quitting-heroing.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -841,6 +842,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ keijo, vermeilInGold, geniusPrincesGuideRaisingNationDebt, + imQuittingHeroing, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/im-quitting-heroing.json b/src/data/mappings/im-quitting-heroing.json new file mode 100644 index 0000000..9de027d --- /dev/null +++ b/src/data/mappings/im-quitting-heroing.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 140457, + "anilistMangaId": 102861, + "title": "I'm Quitting Heroing", + "sourceNotes": "Single 12-episode season (Spring 2022, EMT Squared). The show is sourced from Quantum's light novel (3 volumes, complete 2018), but community episode-to-source guides reference the concrete manga adaptation, which fully adapts the LN and is complete at 44 chapters / 8 volumes (2023) — so chapter ranges here use the manga's numbering. The anime adapts LN Volume 1, which equals manga chapters 1-16 (readers continue at manga ch. 17 / LN Vol. 2). The story is largely episodic (hero Leo joins the Demon Queen Echidna's army), so a per-episode chapter split isn't published; the adapted cour is mapped as one block. Chapters 17-44 (LN Vols. 2-3) are unadapted.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 16], + "arc": "Demon Queen's Castle (LN Vol. 1)" + }, + { + "chapters": [17, 44], + "arc": "Post-Anime (LN Vols. 2-3)" + } + ] +} From 3a95716b00f8ba1335d1fbe40ad0e583b33de17d Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:13 -0400 Subject: [PATCH 082/100] KSN: add `farming-life-in-another-world.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–24 ↔ chapters 1–319 - anime `146850` → manga `100456` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../farming-life-in-another-world.json | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/farming-life-in-another-world.json diff --git a/src/data/index.ts b/src/data/index.ts index d973f07..cb1cac0 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -387,6 +387,7 @@ import keijo from "@/data/mappings/keijo.json"; import vermeilInGold from "@/data/mappings/vermeil-in-gold.json"; import geniusPrincesGuideRaisingNationDebt from "@/data/mappings/genius-princes-guide-raising-nation-debt.json"; import imQuittingHeroing from "@/data/mappings/im-quitting-heroing.json"; +import farmingLifeInAnotherWorld from "@/data/mappings/farming-life-in-another-world.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -843,6 +844,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ vermeilInGold, geniusPrincesGuideRaisingNationDebt, imQuittingHeroing, + farmingLifeInAnotherWorld, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/farming-life-in-another-world.json b/src/data/mappings/farming-life-in-another-world.json new file mode 100644 index 0000000..c07f835 --- /dev/null +++ b/src/data/mappings/farming-life-in-another-world.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 146850, + "anilistMangaId": 100456, + "title": "Farming Life in Another World", + "sourceNotes": "Light-novel-sourced (Isekai Nonbiri Nouka), but the community aligns the anime to the manga adaptation (AniList 100456), which is the numbering used by every \"where to start reading\" guide; ranges are therefore given in manga chapters. Cumulative episodes across S1 (12) + S2 (12) = 24. The adaptation is extremely loose slice-of-life: it plucks, condenses, re-orders and rewrites arcs rather than following the source linearly, so per-episode chapter boundaries are not knowable and these ranges are approximate season-level spans. Anchors from reading guides: after S1 you resume at manga Vol. 3 Ch. 25 (S1 ≈ ch. 1-24), and S2 makes a large jump and ends around manga Ch. 314, skipping many intervening arcs. Manga ongoing (current ch. 319 as of July 2026).", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 24], + "arc": "Big Tree Village Founding" + }, + { + "episodes": [13, 24], + "chapters": [25, 314], + "arc": "Village Expansion" + }, + { + "chapters": [315, 319], + "arc": "Beyond the Anime (unadapted)" + } + ] +} From 15cb29b58a6a92797e1db2f64a2267195aba8701 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:16 -0400 Subject: [PATCH 083/100] KSN: add `insomniacs-after-school.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 9 arcs covering episodes 1–13 ↔ chapters 1–125 - anime `143653` → manga `110473` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../mappings/insomniacs-after-school.json | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/data/mappings/insomniacs-after-school.json diff --git a/src/data/index.ts b/src/data/index.ts index cb1cac0..d91ca47 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -388,6 +388,7 @@ import vermeilInGold from "@/data/mappings/vermeil-in-gold.json"; import geniusPrincesGuideRaisingNationDebt from "@/data/mappings/genius-princes-guide-raising-nation-debt.json"; import imQuittingHeroing from "@/data/mappings/im-quitting-heroing.json"; import farmingLifeInAnotherWorld from "@/data/mappings/farming-life-in-another-world.json"; +import insomniacsAfterSchool from "@/data/mappings/insomniacs-after-school.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -845,6 +846,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ geniusPrincesGuideRaisingNationDebt, imQuittingHeroing, farmingLifeInAnotherWorld, + insomniacsAfterSchool, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/insomniacs-after-school.json b/src/data/mappings/insomniacs-after-school.json new file mode 100644 index 0000000..287f54e --- /dev/null +++ b/src/data/mappings/insomniacs-after-school.json @@ -0,0 +1,50 @@ +{ + "anilistAnimeId": 143653, + "anilistMangaId": 110473, + "title": "Insomniacs After School", + "sourceNotes": "Single 13-episode cour (2023); no second season. Source manga by Makoto Ojiro is complete at 125 chapters / 14 volumes (Sept 2019 - Oct 2023). The anime adapts roughly chapters 1-57 (through the end of Vol. 6 / start of Vol. 7), then ends on an anime-original positive note; readers are advised to continue from around chapter 55. This is a slice-of-life romance with no canonical named story arcs, so arc labels are descriptive and boundaries are aligned to tankobon volume breaks (Vol. 1: 1-8, Vol. 2: 9-18, Vol. 3: 19-27, Vol. 4: 28-37, Vol. 5: 38-47, Vol. 6: 48-55, Vol. 7: 56-64). Episode ranges are apportioned proportionally across the ~57 adapted chapters (~4.4 chapters/episode); per-episode chapter boundaries are approximate. Chapters 58-125 are unadapted.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 8], + "arc": "Fellow Insomniacs" + }, + { + "episodes": [3, 4], + "chapters": [9, 18], + "arc": "Reviving the Astronomy Club" + }, + { + "episodes": [5, 6], + "chapters": [19, 27], + "arc": "Chasing the Stars" + }, + { + "episodes": [7, 9], + "chapters": [28, 37], + "arc": "Summer Fireworks" + }, + { + "episodes": [10, 11], + "chapters": [38, 47], + "arc": "New Semester" + }, + { + "episodes": [12, 13], + "chapters": [48, 57], + "arc": "The Last Star" + }, + { + "chapters": [58, 80], + "arc": "Second Year" + }, + { + "chapters": [81, 107], + "arc": "Growing Closer" + }, + { + "chapters": [108, 125], + "arc": "Final Nights" + } + ] +} From 530907785415ecf2a856c352867ab8b48a716d20 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:19 -0400 Subject: [PATCH 084/100] KSN: add `kakushigoto.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 12 arcs covering episodes 1–12 ↔ chapters 1–232 - anime `113311` → manga `97603` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + src/data/mappings/kakushigoto.json | 68 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/data/mappings/kakushigoto.json diff --git a/src/data/index.ts b/src/data/index.ts index d91ca47..81070db 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -389,6 +389,7 @@ import geniusPrincesGuideRaisingNationDebt from "@/data/mappings/genius-princes- import imQuittingHeroing from "@/data/mappings/im-quitting-heroing.json"; import farmingLifeInAnotherWorld from "@/data/mappings/farming-life-in-another-world.json"; import insomniacsAfterSchool from "@/data/mappings/insomniacs-after-school.json"; +import kakushigoto from "@/data/mappings/kakushigoto.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -847,6 +848,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ imQuittingHeroing, farmingLifeInAnotherWorld, insomniacsAfterSchool, + kakushigoto, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kakushigoto.json b/src/data/mappings/kakushigoto.json new file mode 100644 index 0000000..f38ddd1 --- /dev/null +++ b/src/data/mappings/kakushigoto.json @@ -0,0 +1,68 @@ +{ + "anilistAnimeId": 113311, + "anilistMangaId": 97603, + "title": "Kakushigoto", + "sourceNotes": "Single 12-episode TV season (2020) adapting Koji Kumeta's manga \"Kakushigoto: My Dad's Secret Ambition.\" Manga complete at 232 short chapters across 12 tankobon volumes (2015-2020, AniList manga id 97603). This is an episodic gag comedy with NO named story arcs and no published per-episode chapter guide; the anime does not follow strict publication order but interweaves the past (Hime age 10) with a present-day frame (Hime age 18 opening the storehouse), broadly progressing through the manga and reaching its conclusion in the finale. Mappings use the actual ANN episode titles as labels, aligned one-episode-per-volume across the manga's 12 volumes; chapter ranges are APPROXIMATE (even split of 232 chapters into 12 volume-sized blocks). The 2021 \"Kakushigoto Theatrical Edition\" is a recap re-edit of the TV footage (AniList SUMMARY) and is excluded.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 20], + "arc": "Secrets" + }, + { + "episodes": [2, 2], + "chapters": [21, 40], + "arc": "Beach Sandals and B4" + }, + { + "episodes": [3, 3], + "chapters": [41, 59], + "arc": "Makeshift Circus" + }, + { + "episodes": [4, 4], + "chapters": [60, 78], + "arc": "Normale Namae" + }, + { + "episodes": [5, 5], + "chapters": [79, 97], + "arc": "And Yet Everyone Gets Their Turn in the End" + }, + { + "episodes": [6, 6], + "chapters": [98, 116], + "arc": "School Rucksack" + }, + { + "episodes": [7, 7], + "chapters": [117, 136], + "arc": "Inuhoshiki: Dog Wanted" + }, + { + "episodes": [8, 8], + "chapters": [137, 155], + "arc": "Our Rough Draft" + }, + { + "episodes": [9, 9], + "chapters": [156, 174], + "arc": "Your Lie in December" + }, + { + "episodes": [10, 10], + "chapters": [175, 193], + "arc": "I\"S (Izu)" + }, + { + "episodes": [11, 11], + "chapters": [194, 213], + "arc": "Saishukai: The Last Chapter Doesn't Bother Her" + }, + { + "episodes": [12, 12], + "chapters": [214, 232], + "arc": "Hidden Truths" + } + ] +} From d4b10a1acca5d11597b5f93e8598a58daa1a3149 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:22 -0400 Subject: [PATCH 085/100] KSN: add `you-and-i-are-polar-opposites.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–12 ↔ chapters 1–76 - anime `184951` → manga `147997` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + .../you-and-i-are-polar-opposites.json | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/you-and-i-are-polar-opposites.json diff --git a/src/data/index.ts b/src/data/index.ts index 81070db..860723e 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -390,6 +390,7 @@ import imQuittingHeroing from "@/data/mappings/im-quitting-heroing.json"; import farmingLifeInAnotherWorld from "@/data/mappings/farming-life-in-another-world.json"; import insomniacsAfterSchool from "@/data/mappings/insomniacs-after-school.json"; import kakushigoto from "@/data/mappings/kakushigoto.json"; +import youAndIArePolarOpposites from "@/data/mappings/you-and-i-are-polar-opposites.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -849,6 +850,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ farmingLifeInAnotherWorld, insomniacsAfterSchool, kakushigoto, + youAndIArePolarOpposites, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/you-and-i-are-polar-opposites.json b/src/data/mappings/you-and-i-are-polar-opposites.json new file mode 100644 index 0000000..f495e04 --- /dev/null +++ b/src/data/mappings/you-and-i-are-polar-opposites.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 184951, + "anilistMangaId": 147997, + "title": "You and I Are Polar Opposites", + "sourceNotes": "Season 1 (12 eps, Winter 2026, Lapin Track) is a faithful, zero-filler adaptation of Kocha Agasawa's Shonen Jump+ romance manga at roughly 2.5 chapters per episode, covering ch 1-31 (a viewer resumes reading at ch 32). The manga is complete: AniList lists 76 chapters across 8 volumes (the main story ran to ch 65, with the remainder being bonus/extra chapters). Season 2 (AniList id 210031, 13 eps, Summer 2026) adapts ch 32 onward, but its per-episode chapter boundaries are not yet documented, so the ch 32-76 remainder is listed as a chapters-only tail. Episode ranges are cumulative; S2 would begin at episode 13. Arc names are editorial groupings of this episodic slice-of-life romance, which has no official arc titles; the per-episode chapter mapping follows published episode guides.", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 5], + "arc": "Opposites Attract: Suzuki & Tani Start Dating" + }, + { + "episodes": [4, 5], + "chapters": [6, 11], + "arc": "Summer Nights & the Friend Group" + }, + { + "episodes": [6, 6], + "chapters": [12, 14], + "arc": "Cultural Festival" + }, + { + "episodes": [7, 9], + "chapters": [15, 22], + "arc": "Autumn Feelings" + }, + { + "episodes": [10, 12], + "chapters": [23, 31], + "arc": "Class Trip (S1 Finale)" + }, + { + "chapters": [32, 76], + "arc": "Beyond the Anime (Season 2 onward)" + } + ] +} From 2c79793e512acf524ae0d5a33fe623c7c4c9cc17 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:25 -0400 Subject: [PATCH 086/100] KSN: add `faraway-paladin.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–24 ↔ chapters 1–75 - anime `132473` → manga `101521` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/faraway-paladin.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/faraway-paladin.json diff --git a/src/data/index.ts b/src/data/index.ts index 860723e..4d5f909 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -391,6 +391,7 @@ import farmingLifeInAnotherWorld from "@/data/mappings/farming-life-in-another-w import insomniacsAfterSchool from "@/data/mappings/insomniacs-after-school.json"; import kakushigoto from "@/data/mappings/kakushigoto.json"; import youAndIArePolarOpposites from "@/data/mappings/you-and-i-are-polar-opposites.json"; +import farawayPaladin from "@/data/mappings/faraway-paladin.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -851,6 +852,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ insomniacsAfterSchool, kakushigoto, youAndIArePolarOpposites, + farawayPaladin, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/faraway-paladin.json b/src/data/mappings/faraway-paladin.json new file mode 100644 index 0000000..627d7bf --- /dev/null +++ b/src/data/mappings/faraway-paladin.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 132473, + "anilistMangaId": 101521, + "title": "The Faraway Paladin", + "sourceNotes": "Cumulative episodes across S1 (12) + S2 \"The Lord of Rust Mountains\" (12, eps 13-24). Light-novel sourced (Kanata Yanagino), but the LN is on hiatus, so the community syncs the anime to the ongoing manga adaptation (Mutsumi Okubashi) — used here as the chapter basis. Manga ongoing (current ch. ~75, June 2026). S1 covers manga ch 1-28 (continue reading at Vol 6, ch 29); S2 covers ch 29-66 (continue at Vol 14, ch 67). Because the anime adapts the LN directly while the manga expands the same story more slowly, per-arc manga chapter ranges are approximate.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 28], + "arc": "The Boy in the City of the Dead" + }, + { + "episodes": [13, 24], + "chapters": [29, 66], + "arc": "The Lord of the Rust Mountains" + }, + { + "chapters": [67, 75], + "arc": "The Torch Port Ensemble (unadapted)" + } + ] +} From 52d972ba46ec0ce42f7c586110bc03a7790960a5 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:28 -0400 Subject: [PATCH 087/100] KSN: add `my-stepmoms-daughter-is-my-ex.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–13 - anime `136934` → manga `109422` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../my-stepmoms-daughter-is-my-ex.json | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/data/mappings/my-stepmoms-daughter-is-my-ex.json diff --git a/src/data/index.ts b/src/data/index.ts index 4d5f909..36d27c5 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -392,6 +392,7 @@ import insomniacsAfterSchool from "@/data/mappings/insomniacs-after-school.json" import kakushigoto from "@/data/mappings/kakushigoto.json"; import youAndIArePolarOpposites from "@/data/mappings/you-and-i-are-polar-opposites.json"; import farawayPaladin from "@/data/mappings/faraway-paladin.json"; +import myStepmomsDaughterIsMyEx from "@/data/mappings/my-stepmoms-daughter-is-my-ex.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -853,6 +854,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ kakushigoto, youAndIArePolarOpposites, farawayPaladin, + myStepmomsDaughterIsMyEx, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/my-stepmoms-daughter-is-my-ex.json b/src/data/mappings/my-stepmoms-daughter-is-my-ex.json new file mode 100644 index 0000000..85135ae --- /dev/null +++ b/src/data/mappings/my-stepmoms-daughter-is-my-ex.json @@ -0,0 +1,31 @@ +{ + "anilistAnimeId": 136934, + "anilistMangaId": 109422, + "title": "My Stepmom's Daughter Is My Ex", + "sourceNotes": "Source is Kyosuke Kamishiro's light novel (AniList id 109422, type MANGA / format NOVEL), which began on Kakuyomu in 2017 and in print under Kadokawa Sneaker Bunko in Dec 2018; 13 main volumes published as of late 2025. AniList lists no chapter/volume count for either source entry, and the official manga adaptation (id 110342) is paced far behind the anime, so this maps by LIGHT NOVEL VOLUME instead. IMPORTANT: the `chapters` tuples below hold LN VOLUME numbers, NOT chapter numbers. The 2022 single-cour TV anime (id 136934, 12 eps, Project No.9) adapts the LN non-linearly: it covers vols 1-2, SKIPS the Vol 3 arc (reported as vol-3 chapters 4-9), then adapts vol 4 and concludes around vol 5 (Mizuto and Yume's first kiss during the countryside summer-festival trip). The skipped Vol 3 is shown as a chapters-only entry with no episodes. Per-volume episode groupings are approximate estimates for this low-arc romcom. Vols 6-13 are unadapted. No theatrical films.", + "mappings": [ + { + "episodes": [1, 4], + "chapters": [1, 1], + "arc": "The Ex-Couple Become Step-Siblings (LN vol 1)" + }, + { + "episodes": [5, 8], + "chapters": [2, 2], + "arc": "Higashira Isana & Summer Break (LN vol 2)" + }, + { + "chapters": [3, 3], + "arc": "LN vol 3 (skipped by the anime)" + }, + { + "episodes": [9, 12], + "chapters": [4, 5], + "arc": "The Countryside Trip & First Kiss (LN vols 4-5)" + }, + { + "chapters": [6, 13], + "arc": "Post-anime volumes (LN vols 6-13, unadapted)" + } + ] +} From aa9585265191787bb6ae0a89dc01799cc47413a1 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:31 -0400 Subject: [PATCH 088/100] KSN: add `when-supernatural-battles-became-commonplace.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 6 arcs covering episodes 1–12 ↔ chapters 1–118 - anime `20646` → manga `85340` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 + ...pernatural-battles-became-commonplace.json | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/data/mappings/when-supernatural-battles-became-commonplace.json diff --git a/src/data/index.ts b/src/data/index.ts index 36d27c5..19c08a9 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -393,6 +393,7 @@ import kakushigoto from "@/data/mappings/kakushigoto.json"; import youAndIArePolarOpposites from "@/data/mappings/you-and-i-are-polar-opposites.json"; import farawayPaladin from "@/data/mappings/faraway-paladin.json"; import myStepmomsDaughterIsMyEx from "@/data/mappings/my-stepmoms-daughter-is-my-ex.json"; +import whenSupernaturalBattlesBecameCommonplace from "@/data/mappings/when-supernatural-battles-became-commonplace.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -855,6 +856,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ youAndIArePolarOpposites, farawayPaladin, myStepmomsDaughterIsMyEx, + whenSupernaturalBattlesBecameCommonplace, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/when-supernatural-battles-became-commonplace.json b/src/data/mappings/when-supernatural-battles-became-commonplace.json new file mode 100644 index 0000000..aa6f23a --- /dev/null +++ b/src/data/mappings/when-supernatural-battles-became-commonplace.json @@ -0,0 +1,37 @@ +{ + "anilistAnimeId": 20646, + "anilistMangaId": 85340, + "title": "When Supernatural Battles Became Commonplace", + "sourceNotes": "Single 12-episode 2014 Trigger adaptation of Kota Nozomi's light novel \"Inou-Battle wa Nichijou-kei no Naka de\" (source = the LN, AniList id 85340, format NOVEL, reported as 118 chapters across 13 volumes; series COMPLETE at Vol. 13, Jan 2018). The anime broadly adapts light novel Volumes 1-5, so chapter ranges here are approximate volume-proportional divisions of the 118-chapter count (~9 chapters per volume), NOT exact LN chapter boundaries. Trigger reordered several character arcs for pacing: notably Hatoko Kushikawa's Volume-2 emotional climax (\"Juggernaut On\" outburst) is pushed to the dramatic center at episodes 7-8, while the Chifuyu (Vol. 3) and Sayumi (Vol. 4) material fills the middle episodes. The episodes 11-12 finale (Mirei's possession by the imposter, Lucifirst, the \"Dark and Dark of the End\") is a partly anime-original/compressed climax. Volumes 6-13 are unadapted. Single cour, so episode numbers are not cumulative across seasons.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 9], + "arc": "Grateful Robber (Mirei Kudou joins)" + }, + { + "episodes": [3, 4], + "chapters": [10, 18], + "arc": "World Create (Chifuyu & Madoka)" + }, + { + "episodes": [5, 6], + "chapters": [19, 27], + "arc": "Sensitive Age & Vice Penalty (Tomoyo's Novel, Sayumi's Root of Origin)" + }, + { + "episodes": [7, 8], + "chapters": [28, 36], + "arc": "Juggernaut On (Hatoko's Outburst)" + }, + { + "episodes": [9, 12], + "chapters": [37, 45], + "arc": "Girls Approach & Usual Days (Confessions and the Imposter Finale)" + }, + { + "chapters": [46, 118], + "arc": "Post-Anime Volumes 6-13 (Unadapted)" + } + ] +} From ca8496394c4c8c66d5b6b88c632823cb38ff2430 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:34 -0400 Subject: [PATCH 089/100] KSN: add `my-deer-friend-nokotan.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–12 ↔ chapters 1–49 - anime `175977` → manga `125555` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/my-deer-friend-nokotan.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/my-deer-friend-nokotan.json diff --git a/src/data/index.ts b/src/data/index.ts index 19c08a9..4a52133 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -394,6 +394,7 @@ import youAndIArePolarOpposites from "@/data/mappings/you-and-i-are-polar-opposi import farawayPaladin from "@/data/mappings/faraway-paladin.json"; import myStepmomsDaughterIsMyEx from "@/data/mappings/my-stepmoms-daughter-is-my-ex.json"; import whenSupernaturalBattlesBecameCommonplace from "@/data/mappings/when-supernatural-battles-became-commonplace.json"; +import myDeerFriendNokotan from "@/data/mappings/my-deer-friend-nokotan.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -857,6 +858,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ farawayPaladin, myStepmomsDaughterIsMyEx, whenSupernaturalBattlesBecameCommonplace, + myDeerFriendNokotan, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/my-deer-friend-nokotan.json b/src/data/mappings/my-deer-friend-nokotan.json new file mode 100644 index 0000000..96bfd90 --- /dev/null +++ b/src/data/mappings/my-deer-friend-nokotan.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 175977, + "anilistMangaId": 125555, + "title": "My Deer Friend Nokotan", + "sourceNotes": "Single-cour ONA, 12 episodes (no prequel/sequel seasons, so episodes are non-cumulative). Source is Oshioshio's gag manga \"Shikanoko Nokonoko Koshitantan\" (AniList 125555), ongoing since 2019 — 8 tankobon volumes / roughly chapter 49 published as of late 2025 (AniList lists no chapter count). This is an episodic comedy with NO named story arcs; each episode bundles ~3 unrelated gag chapters and the adaptation reorders chapters freely without skipping any, so clean per-episode chapter boundaries do not exist. The anime covers chapters 1-31 (through Vol. 5) across episodes 1-11, with episode 12 containing largely anime-original content. Chapter ranges here are coarse/approximate given the 4-koma-style, non-linear gag source. The remaining published chapters (32 onward) are unadapted.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 31], + "arc": "Nokotan and the Hijiridani Deer Club" + }, + { + "chapters": [32, 49], + "arc": "Unadapted Chapters" + } + ] +} From 8e488a4085ad3dd209cc8d8b10141334e16fe5fd Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:37 -0400 Subject: [PATCH 090/100] KSN: add `kiss-x-sis.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–153 - anime `7593` → manga `33048` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/kiss-x-sis.json | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/kiss-x-sis.json diff --git a/src/data/index.ts b/src/data/index.ts index 4a52133..7fb9794 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -395,6 +395,7 @@ import farawayPaladin from "@/data/mappings/faraway-paladin.json"; import myStepmomsDaughterIsMyEx from "@/data/mappings/my-stepmoms-daughter-is-my-ex.json"; import whenSupernaturalBattlesBecameCommonplace from "@/data/mappings/when-supernatural-battles-became-commonplace.json"; import myDeerFriendNokotan from "@/data/mappings/my-deer-friend-nokotan.json"; +import kissXSis from "@/data/mappings/kiss-x-sis.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -859,6 +860,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ myStepmomsDaughterIsMyEx, whenSupernaturalBattlesBecameCommonplace, myDeerFriendNokotan, + kissXSis, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kiss-x-sis.json b/src/data/mappings/kiss-x-sis.json new file mode 100644 index 0000000..11c6d18 --- /dev/null +++ b/src/data/mappings/kiss-x-sis.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 7593, + "anilistMangaId": 33048, + "title": "kiss×sis (TV)", + "sourceNotes": "Single 12-episode TV season (Feel, 2010); anilistAnimeId 7593 is the only TV series (the earlier 2008 \"kiss×sis\" is a separate 12-part OVA side-adaptation, not mapped here). Sourced from Bow Ditama's completed ecchi harem-comedy manga (AniList 33048), which finished in 2021 at 154 chapters numbered 0-153 across 25 tankobon. This is episodic gag/fanservice comedy about Keita Suminoe and his twin stepsisters Ako and Riko with no continuous story arcs; the TV anime samples scattered early chapters non-sequentially rather than following a linear arc, so the per-episode chapter boundaries below are coarse approximations, not exact matches. A reader finishing the anime continues roughly from mid-series onward to the finale at ch. 153. No theatrical films exist (only the OVA line).", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 25], + "arc": "Keita & the Twins (episodic ecchi gags; approximate)" + }, + { + "episodes": [7, 12], + "chapters": [26, 50], + "arc": "Exams & Summer Antics (episodic; approximate)" + }, + { + "chapters": [51, 153], + "arc": "Remaining manga chapters (unadapted)" + } + ] +} From 44bba5cf8f1f38290141943fa7198737abdef659 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:40 -0400 Subject: [PATCH 091/100] KSN: add `romantic-killer.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–12 ↔ chapters 1–40 - anime `153930` → manga `113531` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/romantic-killer.json | 28 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/data/mappings/romantic-killer.json diff --git a/src/data/index.ts b/src/data/index.ts index 7fb9794..8112e98 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -396,6 +396,7 @@ import myStepmomsDaughterIsMyEx from "@/data/mappings/my-stepmoms-daughter-is-my import whenSupernaturalBattlesBecameCommonplace from "@/data/mappings/when-supernatural-battles-became-commonplace.json"; import myDeerFriendNokotan from "@/data/mappings/my-deer-friend-nokotan.json"; import kissXSis from "@/data/mappings/kiss-x-sis.json"; +import romanticKiller from "@/data/mappings/romantic-killer.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -861,6 +862,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ whenSupernaturalBattlesBecameCommonplace, myDeerFriendNokotan, kissXSis, + romanticKiller, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/romantic-killer.json b/src/data/mappings/romantic-killer.json new file mode 100644 index 0000000..243b49a --- /dev/null +++ b/src/data/mappings/romantic-killer.json @@ -0,0 +1,28 @@ +{ + "anilistAnimeId": 153930, + "anilistMangaId": 113531, + "title": "Romantic Killer", + "sourceNotes": "Single-cour Netflix ONA (12 episodes, all released 2022-10-27), so episode numbers are non-cumulative. Adapts Wataru Momose's manga essentially in full: the anime runs from Vol. 1 Ch. 1 through the finale near Ch. 39-40. Manga complete at 40 chapters across 4 volumes (Vol.1 ch.1-9, Vol.2 ch.10-20, Vol.3 ch.21-30, Vol.4 ch.31-40). Romantic Killer is an episodic romantic comedy with no official arc names, so ranges are segmented by volume and by the love-interest/story block each covers, and chapter boundaries are approximate (~3 chapters per episode).", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 9], + "arc": "Riri's Curse & Tsukasa Kazuki" + }, + { + "episodes": [4, 6], + "chapters": [10, 20], + "arc": "Junta Hayami, the Childhood Friend" + }, + { + "episodes": [7, 9], + "chapters": [21, 30], + "arc": "Hijiri Koganei" + }, + { + "episodes": [10, 12], + "chapters": [31, 40], + "arc": "Saki Shion & the Finale" + } + ] +} From 4abaadeb05af4a51aa4f7e2c0d6e02b04be0cd9a Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:43 -0400 Subject: [PATCH 092/100] KSN: add `kiss-him-not-me.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–12 ↔ chapters 1–60 - anime `21686` → manga `84779` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/kiss-him-not-me.json | 47 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/data/mappings/kiss-him-not-me.json diff --git a/src/data/index.ts b/src/data/index.ts index 8112e98..38ad6d4 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -397,6 +397,7 @@ import whenSupernaturalBattlesBecameCommonplace from "@/data/mappings/when-super import myDeerFriendNokotan from "@/data/mappings/my-deer-friend-nokotan.json"; import kissXSis from "@/data/mappings/kiss-x-sis.json"; import romanticKiller from "@/data/mappings/romantic-killer.json"; +import kissHimNotMe from "@/data/mappings/kiss-him-not-me.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -863,6 +864,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ myDeerFriendNokotan, kissXSis, romanticKiller, + kissHimNotMe, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kiss-him-not-me.json b/src/data/mappings/kiss-him-not-me.json new file mode 100644 index 0000000..ef2ce75 --- /dev/null +++ b/src/data/mappings/kiss-him-not-me.json @@ -0,0 +1,47 @@ +{ + "anilistAnimeId": 21686, + "anilistMangaId": 84779, + "title": "Kiss Him, Not Me", + "sourceNotes": "Single 12-episode TV series (Brain's Base, 2016) sourced from Junko's manga (complete at 60 chapters / 14 volumes, Bessatsu Friend 2013-2018). Episodes 1-5 follow the manga chronologically and end at chapter 12 (\"I Realized\"); from episode 6 onward the anime heavily reorders and cherry-picks chapters (e.g. ep6 draws on ch22-23, ep8 on ch28, ep9 jumps back to the ch25 beach material, ep11 to the ch16 survival game), so episode ranges for arcs after ch12 are approximate and non-monotonic. Arc groupings below follow the manga's chapter titles. The anime adapts roughly the first half of the manga (through ~ch28); chapters 29-60 (the post-transformation continuation) are unadapted.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 4], + "arc": "The Reverse Harem Forms" + }, + { + "episodes": [3, 4], + "chapters": [5, 8], + "arc": "Cosplay Festival & Christmas in the Holy Land" + }, + { + "episodes": [5, 5], + "chapters": [9, 12], + "arc": "Back to My Original Self" + }, + { + "episodes": [9, 11], + "chapters": [13, 16], + "arc": "Nishina and the Survival Game" + }, + { + "episodes": [10, 10], + "chapters": [17, 20], + "arc": "Brother Invasion" + }, + { + "episodes": [6, 12], + "chapters": [21, 24], + "arc": "Confessions & the Fujoshi Dispute" + }, + { + "episodes": [7, 9], + "chapters": [25, 28], + "arc": "Comiket Trip & Summer Beach" + }, + { + "chapters": [29, 60], + "arc": "Post-Transformation Continuation (unadapted)" + } + ] +} From 87fc33302e95ad25cecfb24f606ee9585ff9cd12 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:47 -0400 Subject: [PATCH 093/100] KSN: add `sailor-moon.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–200 ↔ chapters 1–61 - 3 movies - anime `530` → manga `30092` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/sailor-moon.json | 56 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/data/mappings/sailor-moon.json diff --git a/src/data/index.ts b/src/data/index.ts index 38ad6d4..3752d45 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -398,6 +398,7 @@ import myDeerFriendNokotan from "@/data/mappings/my-deer-friend-nokotan.json"; import kissXSis from "@/data/mappings/kiss-x-sis.json"; import romanticKiller from "@/data/mappings/romantic-killer.json"; import kissHimNotMe from "@/data/mappings/kiss-him-not-me.json"; +import sailorMoon from "@/data/mappings/sailor-moon.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -865,6 +866,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ kissXSis, romanticKiller, kissHimNotMe, + sailorMoon, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/sailor-moon.json b/src/data/mappings/sailor-moon.json new file mode 100644 index 0000000..aa03d30 --- /dev/null +++ b/src/data/mappings/sailor-moon.json @@ -0,0 +1,56 @@ +{ + "anilistAnimeId": 530, + "anilistMangaId": 30092, + "title": "Sailor Moon", + "sourceNotes": "Cumulative episodes across the five 90s TV series: Sailor Moon S1 (46) + Sailor Moon R (43) + Sailor Moon S (38) + Sailor Moon SuperS (39) + Sailor Moon Sailor Stars (34) = 200 episodes. Source manga is complete at 60 acts (AniList lists 61 chapters, counting a side-story extra), using the shinsouban/renewal 60-act numbering. The 90s anime is a loose adaptation with substantial filler, so the mapping is arc-level: each TV series corresponds to one manga arc rather than a tight 1:1 chapter cadence. Notable filler includes Sailor Moon R's opening Makaiju/Doom Tree episodes (anime-original) before the Black Moon story begins.", + "mappings": [ + { + "episodes": [1, 46], + "chapters": [1, 14], + "arc": "Dark Kingdom" + }, + { + "episodes": [47, 89], + "chapters": [15, 27], + "arc": "Black Moon" + }, + { + "episodes": [90, 127], + "chapters": [28, 38], + "arc": "Infinity (Death Busters)" + }, + { + "episodes": [128, 166], + "chapters": [39, 49], + "arc": "Dream (Dead Moon)" + }, + { + "episodes": [167, 200], + "chapters": [50, 61], + "arc": "Stars (Shadow Galactica)" + } + ], + "movies": [ + { + "anilistId": 531, + "title": "Sailor Moon R: The Movie", + "year": 1993, + "afterEpisode": 89, + "note": "Canon side-story feature in the classic continuity; original tale of Fiore and the Xenian flower, set after the Black Moon arc." + }, + { + "anilistId": 997, + "title": "Sailor Moon S the Movie: Hearts in Ice", + "year": 1994, + "afterEpisode": 127, + "note": "Canon side-story feature loosely based on Naoko Takeuchi's 'The Lover of Princess Kaguya' short; slots within the Sailor Moon S / Infinity period." + }, + { + "anilistId": 1240, + "title": "Sailor Moon SuperS the Movie: Black Dream Hole", + "year": 1995, + "afterEpisode": 166, + "note": "Canon original side-story feature in the classic continuity, set during the SuperS / Dream period." + } + ] +} From 9e84f438d0acbbe56b9382af5e02c767cdc8b45b Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:49 -0400 Subject: [PATCH 094/100] KSN: add `astra-lost-in-space.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–49 - anime `107663` → manga `87442` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/astra-lost-in-space.json | 33 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/astra-lost-in-space.json diff --git a/src/data/index.ts b/src/data/index.ts index 3752d45..31db5a1 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -399,6 +399,7 @@ import kissXSis from "@/data/mappings/kiss-x-sis.json"; import romanticKiller from "@/data/mappings/romantic-killer.json"; import kissHimNotMe from "@/data/mappings/kiss-him-not-me.json"; import sailorMoon from "@/data/mappings/sailor-moon.json"; +import astraLostInSpace from "@/data/mappings/astra-lost-in-space.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -867,6 +868,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ romanticKiller, kissHimNotMe, sailorMoon, + astraLostInSpace, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/astra-lost-in-space.json b/src/data/mappings/astra-lost-in-space.json new file mode 100644 index 0000000..a7859d8 --- /dev/null +++ b/src/data/mappings/astra-lost-in-space.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 107663, + "anilistMangaId": 87442, + "title": "ASTRA LOST IN SPACE", + "sourceNotes": "Single-cour 12-episode adaptation (Lerche, 2019) of Kenta Shinohara's completed manga; episodes are cumulative within one season. The manga is complete at 49 collected chapters across 5 tankobon volumes (Vol 1 \"Planet Camp\" ch 1-7, Vol 2 \"Star of Hope\" ch 8-18, Vol 3 \"Secrets\" ch 19-28, Vol 4 \"Revelation\" ch 29-38, Vol 5 \"Friend-Ship\" ch 39-49). AniList lists 53 chapters, reflecting the Shonen Jump+ digital chapter split; ranges here follow the 49-chapter collected/volume numbering. Boundaries are anchored by the direct title matches between volume finales and episode titles (ep 1 \"Planet Camp\", ep 4 \"Star of Hope\", ep 6 \"Secret\", ep 9 \"Revelation\", ep 12 \"Friend-Ship\"), so arcs are volume-aligned; episode 1 is a double-length premiere covering all of Volume 1.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 7], + "arc": "Planet Camp" + }, + { + "episodes": [2, 4], + "chapters": [8, 18], + "arc": "Star of Hope" + }, + { + "episodes": [5, 6], + "chapters": [19, 28], + "arc": "Secrets" + }, + { + "episodes": [7, 9], + "chapters": [29, 38], + "arc": "Revelation" + }, + { + "episodes": [10, 12], + "chapters": [39, 49], + "arc": "Friend-Ship" + } + ] +} From 1ac8761b9c8aea0bb70a2894721ce2f3e4184172 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:52 -0400 Subject: [PATCH 095/100] KSN: add `kono-oto-tomare.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 arcs covering episodes 1–26 ↔ chapters 1–152 - anime `103302` → manga `75143` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/kono-oto-tomare.json | 27 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/data/mappings/kono-oto-tomare.json diff --git a/src/data/index.ts b/src/data/index.ts index 31db5a1..b8c64cb 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -400,6 +400,7 @@ import romanticKiller from "@/data/mappings/romantic-killer.json"; import kissHimNotMe from "@/data/mappings/kiss-him-not-me.json"; import sailorMoon from "@/data/mappings/sailor-moon.json"; import astraLostInSpace from "@/data/mappings/astra-lost-in-space.json"; +import konoOtoTomare from "@/data/mappings/kono-oto-tomare.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -869,6 +870,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ kissHimNotMe, sailorMoon, astraLostInSpace, + konoOtoTomare, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/kono-oto-tomare.json b/src/data/mappings/kono-oto-tomare.json new file mode 100644 index 0000000..59ed3e3 --- /dev/null +++ b/src/data/mappings/kono-oto-tomare.json @@ -0,0 +1,27 @@ +{ + "anilistAnimeId": 103302, + "anilistMangaId": 75143, + "title": "Kono Oto Tomare!: Sounds of Life", + "sourceNotes": "Cumulative episodes across S1 (13) + S2 (13) = 26 episodes, adapting manga chapters 1-54 at roughly 2 chapters per episode with no filler. S1 (ep 1-13) covers ch 1-26, ending on \"Kuon\" at the Kantou regional festival; S2 (ep 14-26) covers ch 27-54, ending on the Tokise koto club's performance of \"Tenkyuu\" at the Kanagawa prefectural qualifiers (ch 52). Manga is ongoing in Shueisha's Jump SQ (current ch. ~152 as of May 2026, 33+ volumes); everything from ch 55 onward is unadapted. No theatrical films exist.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 13], + "arc": "Club Formation Arc" + }, + { + "episodes": [7, 13], + "chapters": [14, 26], + "arc": "Kantou Regional Festival Arc" + }, + { + "episodes": [14, 26], + "chapters": [27, 54], + "arc": "Kanagawa Preliminaries Arc" + }, + { + "chapters": [55, 152], + "arc": "Nationals Arc (unadapted)" + } + ] +} From 2e17fc47a10c75567807b34df8adb983a8611bc1 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:55 -0400 Subject: [PATCH 096/100] KSN: add `interviews-with-monster-girls.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3 arcs covering episodes 1–12 ↔ chapters 1–78 - anime `97592` → manga `86898` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ .../interviews-with-monster-girls.json | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/data/mappings/interviews-with-monster-girls.json diff --git a/src/data/index.ts b/src/data/index.ts index b8c64cb..0236f5f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -401,6 +401,7 @@ import kissHimNotMe from "@/data/mappings/kiss-him-not-me.json"; import sailorMoon from "@/data/mappings/sailor-moon.json"; import astraLostInSpace from "@/data/mappings/astra-lost-in-space.json"; import konoOtoTomare from "@/data/mappings/kono-oto-tomare.json"; +import interviewsWithMonsterGirls from "@/data/mappings/interviews-with-monster-girls.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -871,6 +872,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ sailorMoon, astraLostInSpace, konoOtoTomare, + interviewsWithMonsterGirls, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/interviews-with-monster-girls.json b/src/data/mappings/interviews-with-monster-girls.json new file mode 100644 index 0000000..eba12c5 --- /dev/null +++ b/src/data/mappings/interviews-with-monster-girls.json @@ -0,0 +1,22 @@ +{ + "anilistAnimeId": 97592, + "anilistMangaId": 86898, + "title": "Interviews with Monster Girls", + "sourceNotes": "Single 12-episode TV season (2017, A-1 Pictures), adapting Petos's episodic slice-of-life manga Demi-chan wa Kataritai (id 86898), which is complete at 78 chapters / 11 volumes. Episodic adaptation, roughly 2-3 chapters per episode — the anime samples and lightly reorders the early manga chapters rather than following continuous arcs, so per-episode chapter boundaries are approximate. The 12 episodes cover up to about chapter 34 (through volume 5). A canon ONA, \"The Demi-chans' Summer Break\" (2017), adapts a couple of stray chapters but is a non-theatrical special, so it is not listed as a film. No theatrical films exist, so no movies are listed. A reader continues past the anime from roughly chapter 35 to the finale at chapter 78.", + "mappings": [ + { + "episodes": [1, 6], + "chapters": [1, 16], + "arc": "Meeting the Demi-chans (Hikari, Kyouko, Yuki and Sakie; Takahashi's interviews begin) — roughly vols 1-2, approximate" + }, + { + "episodes": [7, 12], + "chapters": [17, 34], + "arc": "Understanding the Demi-chans (deepening bonds and everyday troubles through summer) — roughly vols 3-5, approximate" + }, + { + "chapters": [35, 78], + "arc": "Later Chapters to the Finale (unadapted; vols 5-11, approximate)" + } + ] +} From fb4e4de149d07151fb35cbbb644e52764ab8163d Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:25:58 -0400 Subject: [PATCH 097/100] KSN: add `a-sisters-all-you-need.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–14 - anime `98596` → manga `97894` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/a-sisters-all-you-need.json | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/data/mappings/a-sisters-all-you-need.json diff --git a/src/data/index.ts b/src/data/index.ts index 0236f5f..16bc766 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -402,6 +402,7 @@ import sailorMoon from "@/data/mappings/sailor-moon.json"; import astraLostInSpace from "@/data/mappings/astra-lost-in-space.json"; import konoOtoTomare from "@/data/mappings/kono-oto-tomare.json"; import interviewsWithMonsterGirls from "@/data/mappings/interviews-with-monster-girls.json"; +import aSistersAllYouNeed from "@/data/mappings/a-sisters-all-you-need.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -873,6 +874,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ astraLostInSpace, konoOtoTomare, interviewsWithMonsterGirls, + aSistersAllYouNeed, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/a-sisters-all-you-need.json b/src/data/mappings/a-sisters-all-you-need.json new file mode 100644 index 0000000..6894501 --- /dev/null +++ b/src/data/mappings/a-sisters-all-you-need.json @@ -0,0 +1,32 @@ +{ + "anilistAnimeId": 98596, + "anilistMangaId": 97894, + "title": "A Sister's All You Need.", + "sourceNotes": "Single-cour 2017 TV anime (Silver Link, 12 episodes; no additional seasons, so episode numbers are non-cumulative). Source is Yomi Hirasaka's light novel (AniList id 97894, type MANGA / format NOVEL), 14 main volumes complete March 2015 - February 2020. AniList reports 206 \"chapters\" for the novel but gives no clean per-volume chapter boundaries, and the official @comic manga adaptation lags far behind, so this maps by LIGHT NOVEL VOLUME instead. IMPORTANT: the `chapters` tuples below hold LN VOLUME numbers, NOT chapter numbers. The anime adapts LN vols 1-4 (this is the community consensus). Episode-to-volume groupings are even ~3-episodes-per-volume estimates: the show is a low-arc slice-of-life comedy about light novelists that also reorders and adds original material, so boundaries are approximate. The unadapted tail is vols 5-14. No theatrical films (a related 6-episode ONA side story and TV specials exist but are separate entries and not films).", + "mappings": [ + { + "episodes": [1, 3], + "chapters": [1, 1], + "arc": "Meeting Itsuki, Nayuta & the gang (LN vol 1)" + }, + { + "episodes": [4, 6], + "chapters": [2, 2], + "arc": "Work, research & rivalries (LN vol 2)" + }, + { + "episodes": [7, 9], + "chapters": [3, 3], + "arc": "Adventure, love & friendship (LN vol 3)" + }, + { + "episodes": [10, 12], + "chapters": [4, 4], + "arc": "Becoming the protagonist (LN vol 4)" + }, + { + "chapters": [5, 14], + "arc": "Post-anime volumes (LN vols 5-14, unadapted)" + } + ] +} From f1a1023f088468ef06cd13700876f29a0bfb1eca Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:26:01 -0400 Subject: [PATCH 098/100] KSN: add `yosuga-no-sora.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 5 arcs covering episodes 1–12 ↔ chapters 1–5 - anime `8861` → manga `45821` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/yosuga-no-sora.json | 33 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/data/mappings/yosuga-no-sora.json diff --git a/src/data/index.ts b/src/data/index.ts index 16bc766..1b8c45a 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -403,6 +403,7 @@ import astraLostInSpace from "@/data/mappings/astra-lost-in-space.json"; import konoOtoTomare from "@/data/mappings/kono-oto-tomare.json"; import interviewsWithMonsterGirls from "@/data/mappings/interviews-with-monster-girls.json"; import aSistersAllYouNeed from "@/data/mappings/a-sisters-all-you-need.json"; +import yosugaNoSora from "@/data/mappings/yosuga-no-sora.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -875,6 +876,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ konoOtoTomare, interviewsWithMonsterGirls, aSistersAllYouNeed, + yosugaNoSora, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/yosuga-no-sora.json b/src/data/mappings/yosuga-no-sora.json new file mode 100644 index 0000000..7bbede8 --- /dev/null +++ b/src/data/mappings/yosuga-no-sora.json @@ -0,0 +1,33 @@ +{ + "anilistAnimeId": 8861, + "anilistMangaId": 45821, + "title": "Yosuga no Sora: In Solitude Where We are Least Alone", + "sourceNotes": "Single 12-episode 2010 TV series (no sequel seasons, so episode numbers are already absolute). Source is CUFFS' 2008 visual novel Yosuga no Sora, which has no AniList media entry and no linear chapter numbering, so mappings use the VN's route (branch) structure as the \"chapter\" basis: 1=Common route, 2=Kazuha route, 3=Akira route, 4=Nao route, 5=Sora route. anilistMangaId points to the only printed AniList relation (id 45821), a 14-chapter manga that is a minor side-adaptation covering essentially the Sora/incest route only, not the full VN. The anime is an omnibus: episodes 1-2 form a shared common setup, then it branches per heroine (unique route episodes 3-4 Kazuha, 5-6 Akira, 8-9 Nao, 10-12 Sora, with ep 7 as the Nao/Sora foundation). Motoka Nogisaka's route appears only as comedic super-deformed omake segments at the end of each episode and is not tracked as a feature arc here. Route boundaries are approximate since the branches share early episodes.", + "mappings": [ + { + "episodes": [1, 2], + "chapters": [1, 1], + "arc": "Common Route" + }, + { + "episodes": [3, 4], + "chapters": [2, 2], + "arc": "Kazuha Migiwa Route" + }, + { + "episodes": [5, 6], + "chapters": [3, 3], + "arc": "Akira Amatsume Route" + }, + { + "episodes": [7, 9], + "chapters": [4, 4], + "arc": "Nao Yorihime Route" + }, + { + "episodes": [10, 12], + "chapters": [5, 5], + "arc": "Sora Kasugano Route" + } + ] +} From c118e56ca728e2bdfbcf6ed16fb5390fa8b6cb42 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:26:04 -0400 Subject: [PATCH 099/100] KSN: add `school-babysitters.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2 arcs covering episodes 1–12 ↔ chapters 1–151 - anime `98503` → manga `46922` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/school-babysitters.json | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/data/mappings/school-babysitters.json diff --git a/src/data/index.ts b/src/data/index.ts index 1b8c45a..56b2c8f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -404,6 +404,7 @@ import konoOtoTomare from "@/data/mappings/kono-oto-tomare.json"; import interviewsWithMonsterGirls from "@/data/mappings/interviews-with-monster-girls.json"; import aSistersAllYouNeed from "@/data/mappings/a-sisters-all-you-need.json"; import yosugaNoSora from "@/data/mappings/yosuga-no-sora.json"; +import schoolBabysitters from "@/data/mappings/school-babysitters.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -877,6 +878,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ interviewsWithMonsterGirls, aSistersAllYouNeed, yosugaNoSora, + schoolBabysitters, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/school-babysitters.json b/src/data/mappings/school-babysitters.json new file mode 100644 index 0000000..59be819 --- /dev/null +++ b/src/data/mappings/school-babysitters.json @@ -0,0 +1,17 @@ +{ + "anilistAnimeId": 98503, + "anilistMangaId": 46922, + "title": "School Babysitters", + "sourceNotes": "Single 12-episode TV season (2018); a 27-minute OVA (AniList 102969) was later bundled with the seventh BD/DVD and is not counted in the cumulative episode numbering. The manga (Gakuen Babysitters by Hari Tokeino, AniList 46922) is an episodic slice-of-life work with no named story arcs, and the anime adapts it NON-LINEARLY: per the community episode-to-chapter guide, episodes pull scattered chapters out of order (e.g. ep1=ch1, ep2=ch2+6, ep3=ch17+5, ep6=ch28+14, ep7=ch21+20), all drawn from roughly the first five volumes (chapters 1-28). Because selection is non-contiguous, the mapping uses one coarse range for the adapted material rather than fabricating per-episode contiguous boundaries; ranges are approximate. Manga ongoing (27 volumes as of Nov 2025, latest around chapter 151); the tail entry is chapters-only, unadapted.", + "mappings": [ + { + "episodes": [1, 12], + "chapters": [1, 28], + "arc": "Morinomiya Academy Daycare (Anime)" + }, + { + "chapters": [29, 151], + "arc": "Continuing Manga (Post-Anime)" + } + ] +} From 3ebac1fa92128577d905e9091e37b66484524364 Mon Sep 17 00:00:00 2001 From: CJ Rivas Date: Wed, 8 Jul 2026 09:26:07 -0400 Subject: [PATCH 100/100] KSN: add `pluto.json` arc mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 8 arcs covering episodes 1–8 ↔ chapters 1–65 - anime `99088` → manga `30745` - register in `src/data/index.ts` `ALL_MAPPINGS` --- src/data/index.ts | 2 ++ src/data/mappings/pluto.json | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/data/mappings/pluto.json diff --git a/src/data/index.ts b/src/data/index.ts index 56b2c8f..0a2ff27 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -405,6 +405,7 @@ import interviewsWithMonsterGirls from "@/data/mappings/interviews-with-monster- import aSistersAllYouNeed from "@/data/mappings/a-sisters-all-you-need.json"; import yosugaNoSora from "@/data/mappings/yosuga-no-sora.json"; import schoolBabysitters from "@/data/mappings/school-babysitters.json"; +import pluto from "@/data/mappings/pluto.json"; // JSON imports lose tuple types — `[1, 100]` becomes `number[]` instead of // `[number, number]`. `normalizeMapping` rebuilds tuples literally. @@ -879,6 +880,7 @@ const ALL_MAPPINGS: SeriesMapping[] = [ aSistersAllYouNeed, yosugaNoSora, schoolBabysitters, + pluto, ].map(normalizeMapping); export function findMappingByMediaId(mediaId: number): SeriesMapping | null { diff --git a/src/data/mappings/pluto.json b/src/data/mappings/pluto.json new file mode 100644 index 0000000..275173b --- /dev/null +++ b/src/data/mappings/pluto.json @@ -0,0 +1,48 @@ +{ + "anilistAnimeId": 99088, + "anilistMangaId": 30745, + "title": "PLUTO", + "sourceNotes": "Single-season ONA (8 episodes, ~60 min each) released on Netflix in 2023, adapting Naoki Urasawa's completed manga Pluto: Urasawa x Tezuka (65 chapters/\"Acts\" collected in 8 tankobon volumes, AniList id 30745). The adaptation is essentially one episode per manga volume, covering the entire manga. Per-volume act boundaries: V1 = Acts 1-7, V2 = 8-15, V3 = 16-23, V4 = 24-31, V5 = 32-39, V6 = 40-47, V7 = 48-55, V8 = 56-65. Pluto is a single continuous mystery rather than a multi-arc series, so mappings are labeled by source volume. Manga complete at 65 chapters.", + "mappings": [ + { + "episodes": [1, 1], + "chapters": [1, 7], + "arc": "Volume 1" + }, + { + "episodes": [2, 2], + "chapters": [8, 15], + "arc": "Volume 2" + }, + { + "episodes": [3, 3], + "chapters": [16, 23], + "arc": "Volume 3" + }, + { + "episodes": [4, 4], + "chapters": [24, 31], + "arc": "Volume 4" + }, + { + "episodes": [5, 5], + "chapters": [32, 39], + "arc": "Volume 5" + }, + { + "episodes": [6, 6], + "chapters": [40, 47], + "arc": "Volume 6" + }, + { + "episodes": [7, 7], + "chapters": [48, 55], + "arc": "Volume 7" + }, + { + "episodes": [8, 8], + "chapters": [56, 65], + "arc": "Volume 8" + } + ] +}