From 07367a22d7caba59be06b2b4741ce9e385fe356b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=81nis=20L?= Date: Tue, 27 Oct 2026 12:23:07 +0200 Subject: [PATCH] fix miruro seasons --- providers/miruro.js | 13 +++++++++++++ src/miruro/extractor.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/providers/miruro.js b/providers/miruro.js index 720d312..0e814e5 100644 --- a/providers/miruro.js +++ b/providers/miruro.js @@ -816,6 +816,19 @@ async function resolveSeasonEpisode(seed, mapping, identifier, season, episode) if (fromTags) { return { anime: seed, episode: fromTags }; } + const continuation = related.filter((anime) => !isMovieFormat(anime) && seasonOf(anime) != null && seasonOf(anime) >= requestedSeason && entryBelongsToRequest(anime, mapping, identifier)).sort((first, second) => seasonOf(first) - seasonOf(second) || clusterPosition(first) - clusterPosition(second)); + let offset = 0; + for (const anime of continuation) { + const episodes = anime.id === seed.id ? seedEpisodes : await listEpisodes(anime.id); + if (episodes.length === 0) { + continue; + } + const index = requestedEpisode - 1 - offset; + if (index >= 0 && index < episodes.length) { + return { anime, episode: episodes[index] }; + } + offset += episodes.length; + } const local = seedEpisodes.find((item) => Number(item.episode_number) === requestedEpisode); return local ? { anime: seed, episode: local } : null; } diff --git a/src/miruro/extractor.js b/src/miruro/extractor.js index c74769e..860648a 100644 --- a/src/miruro/extractor.js +++ b/src/miruro/extractor.js @@ -446,6 +446,39 @@ async function resolveSeasonEpisode(seed, mapping, identifier, season, episode) return { anime: seed, episode: fromTags }; } + // TMDB sometimes keeps one season while the catalog splits the same run + // into several seasons (The Ramparts of Ice: TMDB S1 episode 15 is catalog + // season 2 episode 1). Walk catalog seasons at or after the requested one + // in order, carrying an episode offset, so those episodes stay reachable. + const continuation = related + .filter((anime) => ( + !isMovieFormat(anime) && + seasonOf(anime) != null && + seasonOf(anime) >= requestedSeason && + entryBelongsToRequest(anime, mapping, identifier) + )) + .sort((first, second) => ( + seasonOf(first) - seasonOf(second) || + clusterPosition(first) - clusterPosition(second) + )); + let offset = 0; + + for (const anime of continuation) { + const episodes = anime.id === seed.id ? seedEpisodes : await listEpisodes(anime.id); + + if (episodes.length === 0) { + continue; + } + + const index = requestedEpisode - 1 - offset; + + if (index >= 0 && index < episodes.length) { + return { anime, episode: episodes[index] }; + } + + offset += episodes.length; + } + const local = seedEpisodes.find((item) => Number(item.episode_number) === requestedEpisode); return local ? { anime: seed, episode: local } : null;