@@ -632,7 +632,9 @@ async function batchConvertImdbToTmdbIds(imdbIds, userBearerToken = DEFAULT_TMDB
632632async function fetchTmdbMetadata ( tmdbId , type , language = 'en-US' , userBearerToken = DEFAULT_TMDB_BEARER_TOKEN ) {
633633 if ( ! tmdbId ) return null ;
634634
635- const cacheKey = `tmdb_${ type } _${ tmdbId } _${ language } ` ;
635+ // Include version in cache key to invalidate old cached data with incorrect episode numbering
636+ const EPISODE_NUMBERING_VERSION = 'v2' ;
637+ const cacheKey = `tmdb_${ type } _${ tmdbId } _${ language } _${ EPISODE_NUMBERING_VERSION } ` ;
636638 const cachedResult = tmdbCache . get ( cacheKey ) ;
637639 if ( cachedResult ) {
638640 return cachedResult === 'null' ? null : cachedResult ;
@@ -789,13 +791,85 @@ function convertTmdbToStremioFormat(tmdbData, type) {
789791 if ( ! isMovie && tmdbData . seasons_with_episodes ) {
790792
791793
794+ // Detect if this is likely an anime with absolute episode numbering
795+ // This happens when TMDB uses continuous numbering across seasons
796+ let isAnimeWithAbsoluteNumbering = false ;
797+ let totalEpisodesProcessed = 0 ;
798+
799+ // Check if any season has episodes with numbers that seem to be absolute rather than season-relative
800+ for ( const season of tmdbData . seasons_with_episodes ) {
801+ if ( season . episodes && season . episodes . length > 0 ) {
802+ const firstEpisode = season . episodes [ 0 ] ;
803+ const lastEpisode = season . episodes [ season . episodes . length - 1 ] ;
804+
805+ // If the first episode number is much higher than 1 and doesn't match the expected pattern
806+ // for season-relative numbering, this is likely absolute numbering
807+ if ( firstEpisode . episode_number > season . episodes . length * 2 ) {
808+ isAnimeWithAbsoluteNumbering = true ;
809+ console . log ( `[TMDB] Absolute numbering detected: Season ${ season . season_number } starts with episode ${ firstEpisode . episode_number } but has ${ season . episodes . length } episodes` ) ;
810+ break ;
811+ }
812+
813+ // If we see episodes with numbers like 100+ in what should be early seasons
814+ if ( season . season_number <= 5 && firstEpisode . episode_number >= 100 ) {
815+ isAnimeWithAbsoluteNumbering = true ;
816+ console . log ( `[TMDB] Absolute numbering detected: Season ${ season . season_number } has episodes starting from ${ firstEpisode . episode_number } ` ) ;
817+ break ;
818+ }
819+
820+ // Additional check: if episode numbers don't reset between seasons
821+ if ( totalEpisodesProcessed > 0 && firstEpisode . episode_number > totalEpisodesProcessed + 10 ) {
822+ // There's a gap, but if the gap is too large, it's probably absolute numbering
823+ isAnimeWithAbsoluteNumbering = true ;
824+ console . log ( `[TMDB] Absolute numbering detected: Episode numbering gap between seasons (expected ~${ totalEpisodesProcessed + 1 } , got ${ firstEpisode . episode_number } )` ) ;
825+ break ;
826+ } else if ( totalEpisodesProcessed > 0 && firstEpisode . episode_number > totalEpisodesProcessed ) {
827+ // Episodes continue from previous season without resetting - clear sign of absolute numbering
828+ isAnimeWithAbsoluteNumbering = true ;
829+ console . log ( `[TMDB] Absolute numbering detected: Episodes continue from previous season (${ totalEpisodesProcessed } -> ${ firstEpisode . episode_number } )` ) ;
830+ break ;
831+ }
832+
833+ totalEpisodesProcessed += season . episodes . length ;
834+ }
835+ }
836+
837+ // Additional check for series with many episodes in later seasons starting with high numbers
838+ // This catches cases like One Piece where early detection might miss it
839+ if ( ! isAnimeWithAbsoluteNumbering ) {
840+ for ( const season of tmdbData . seasons_with_episodes ) {
841+ if ( season . episodes && season . episodes . length > 10 ) { // Only check seasons with substantial episode counts
842+ const avgEpisodeNumber = season . episodes . reduce ( ( sum , ep ) => sum + ep . episode_number , 0 ) / season . episodes . length ;
843+ // If the average episode number is much higher than what we'd expect for season-relative numbering
844+ if ( avgEpisodeNumber > season . season_number * 50 ) { // Very conservative threshold
845+ isAnimeWithAbsoluteNumbering = true ;
846+ console . log ( `[TMDB] Absolute numbering detected: Season ${ season . season_number } has average episode number ${ avgEpisodeNumber . toFixed ( 1 ) } ` ) ;
847+ break ;
848+ }
849+ }
850+ }
851+ }
852+
853+ console . log ( `[TMDB] Processing ${ tmdbData . name } - Anime absolute numbering detected: ${ isAnimeWithAbsoluteNumbering } ` ) ;
854+
792855 tmdbData . seasons_with_episodes . forEach ( season => {
793856 if ( season . episodes && Array . isArray ( season . episodes ) ) {
794- season . episodes . forEach ( episode => {
857+ season . episodes . forEach ( ( episode , episodeIndex ) => {
858+ // Calculate proper episode number for the season
859+ let seasonEpisodeNumber = episode . episode_number ;
860+
861+ if ( isAnimeWithAbsoluteNumbering ) {
862+ // For anime with absolute numbering, use the position within the season
863+ // rather than the absolute episode number
864+ seasonEpisodeNumber = episodeIndex + 1 ;
865+
866+ console . log ( `[TMDB] Converted episode ${ episode . episode_number } to season ${ season . season_number } episode ${ seasonEpisodeNumber } for ${ tmdbData . name } ` ) ;
867+ }
868+
795869 // Use IMDB ID for episode IDs if available, otherwise use TMDB format
796870 const episodeId = imdbId && imdbId . startsWith ( 'tt' ) ?
797- `${ imdbId } :${ season . season_number } :${ episode . episode_number } ` :
798- `${ tmdbId } :${ season . season_number } :${ episode . episode_number } ` ;
871+ `${ imdbId } :${ season . season_number } :${ seasonEpisodeNumber } ` :
872+ `${ tmdbId } :${ season . season_number } :${ seasonEpisodeNumber } ` ;
799873
800874 // Format air date if available
801875 let airDateFormatted = null ;
@@ -805,22 +879,24 @@ function convertTmdbToStremioFormat(tmdbData, type) {
805879
806880 videos . push ( {
807881 id : episodeId ,
808- name : episode . name || `Episode ${ episode . episode_number } ` ,
882+ name : episode . name || `Episode ${ seasonEpisodeNumber } ` ,
809883 season : season . season_number ,
810- number : episode . episode_number ,
811- episode : episode . episode_number ,
884+ number : seasonEpisodeNumber , // Use season-relative number
885+ episode : seasonEpisodeNumber , // Use season-relative number
812886 thumbnail : episode . still_path ? `https://image.tmdb.org/t/p/w500${ episode . still_path } ` : undefined ,
813887 overview : episode . overview || "" ,
814888 description : episode . overview || "" ,
815889 rating : episode . vote_average ? parseFloat ( episode . vote_average ) . toFixed ( 1 ) : "0" ,
816890 firstAired : airDateFormatted ,
817- released : airDateFormatted
891+ released : airDateFormatted ,
892+ // Keep absolute number as additional metadata for reference
893+ absoluteNumber : isAnimeWithAbsoluteNumbering ? episode . episode_number : undefined
818894 } ) ;
819895 } ) ;
820896 }
821897 } ) ;
822898
823- // Sort episodes by season and episode number
899+ // Sort episodes by season and episode number (now using season-relative numbers)
824900 videos . sort ( ( a , b ) => {
825901 if ( a . season !== b . season ) {
826902 return a . season - b . season ;
@@ -1099,16 +1175,62 @@ function clearTmdbCaches() {
10991175 imdbToTmdbCache . clear ( ) ;
11001176}
11011177
1178+ // Test function to verify anime episode numbering fix (for development/debugging)
1179+ async function testAnimeEpisodeNumbering ( tmdbId = 37854 , bearerToken = null ) {
1180+ console . log ( `[TMDB Test] Testing anime episode numbering for TMDB ID: ${ tmdbId } ` ) ;
1181+
1182+ try {
1183+ const metadata = await fetchTmdbMetadata ( tmdbId , 'series' , 'en-US' , bearerToken ) ;
1184+
1185+ if ( metadata && metadata . videos && metadata . videos . length > 0 ) {
1186+ console . log ( `[TMDB Test] Found ${ metadata . videos . length } episodes for ${ metadata . name } ` ) ;
1187+
1188+ // Show sample episodes from different seasons
1189+ const sampleEpisodes = metadata . videos . filter ( ( ep , index ) =>
1190+ index < 5 || // First 5 episodes
1191+ ( ep . season === 22 && ep . episode <= 50 ) || // Season 22 episodes 1-50
1192+ ep . episode > 1000 // High numbered episodes
1193+ ) . slice ( 0 , 20 ) ;
1194+
1195+ console . log ( `[TMDB Test] Sample episodes:` ) ;
1196+ sampleEpisodes . forEach ( ep => {
1197+ console . log ( ` Season ${ ep . season } Episode ${ ep . episode } : ${ ep . name } (ID: ${ ep . id } )${ ep . absoluteNumber ? ` [Absolute: ${ ep . absoluteNumber } ]` : '' } ` ) ;
1198+ } ) ;
1199+
1200+ // Check for the specific case mentioned in the issue
1201+ const season22Episodes = metadata . videos . filter ( ep => ep . season === 22 && ep . episode >= 45 && ep . episode <= 50 ) ;
1202+ if ( season22Episodes . length > 0 ) {
1203+ console . log ( `[TMDB Test] Season 22 episodes 45-50 for verification:` ) ;
1204+ season22Episodes . forEach ( ep => {
1205+ console . log ( ` S22E${ ep . episode } : ${ ep . name } (ID: ${ ep . id } )${ ep . absoluteNumber ? ` [Absolute: ${ ep . absoluteNumber } ]` : '' } ` ) ;
1206+ } ) ;
1207+ }
1208+
1209+ return metadata ;
1210+ } else {
1211+ console . log ( `[TMDB Test] No episodes found for series ${ tmdbId } ` ) ;
1212+ return null ;
1213+ }
1214+ } catch ( error ) {
1215+ console . error ( `[TMDB Test] Error testing anime episode numbering:` , error . message ) ;
1216+ return null ;
1217+ }
1218+ }
1219+
11021220module . exports = {
1103- validateTMDBKey,
1221+ createTmdbRequestToken,
1222+ createTmdbSession,
1223+ getTmdbAccountDetails,
11041224 getTmdbAuthUrl,
11051225 authenticateTmdb,
11061226 fetchTmdbLists,
11071227 fetchTmdbListItems,
1228+ validateTMDBKey,
11081229 convertImdbToTmdbId,
11091230 batchConvertImdbToTmdbIds,
11101231 fetchTmdbMetadata,
11111232 batchFetchTmdbMetadata,
11121233 fetchTmdbGenres,
1113- clearTmdbCaches
1234+ clearTmdbCaches,
1235+ testAnimeEpisodeNumbering // Export test function
11141236} ;
0 commit comments