diff --git a/server/api/tvdb/index.ts b/server/api/tvdb/index.ts index 385444f0..0a4bc0e4 100644 --- a/server/api/tvdb/index.ts +++ b/server/api/tvdb/index.ts @@ -132,7 +132,29 @@ class Tvdb extends ExternalAPI implements TvShowIndexer { tvdbId: number; language?: string; }): Promise { - return await this.tmdb.getTvShow({ tvId: tvdbId, language: language }); + try { + const tmdbTvShow = await this.tmdb.getShowByTvdbId({ + tvdbId: tvdbId, + language, + }); + + try { + await this.refreshToken(); + + const validTvdbId = this.getTvdbIdFromTmdb(tmdbTvShow); + + if (this.isValidTvdbId(validTvdbId)) { + return this.enrichTmdbShowWithTvdbData(tmdbTvShow, validTvdbId); + } + + return tmdbTvShow; + } catch (error) { + return tmdbTvShow; + } + } catch (error) { + this.handleError('Failed to fetch TV show details', error); + throw error; + } } public async getTvShow({ @@ -143,18 +165,25 @@ class Tvdb extends ExternalAPI implements TvShowIndexer { language?: string; }): Promise { try { - await this.refreshToken(); const tmdbTvShow = await this.tmdb.getTvShow({ tvId, language }); - const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow); - if (this.isValidTvdbId(tvdbId)) { - return await this.enrichTmdbShowWithTvdbData(tmdbTvShow, tvdbId); + try { + await this.refreshToken(); + + const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow); + + if (this.isValidTvdbId(tvdbId)) { + return await this.enrichTmdbShowWithTvdbData(tmdbTvShow, tvdbId); + } + + return tmdbTvShow; + } catch (error) { + this.handleError('Failed to fetch TV show details', error); + return tmdbTvShow; } - - return tmdbTvShow; } catch (error) { this.handleError('Failed to fetch TV show details', error); - throw error; + return this.tmdb.getTvShow({ tvId, language }); } } @@ -167,26 +196,32 @@ class Tvdb extends ExternalAPI implements TvShowIndexer { seasonNumber: number; language?: string; }): Promise { - await this.refreshToken(); - if (seasonNumber === 0) { return this.createEmptySeasonResponse(tvId); } try { const tmdbTvShow = await this.tmdb.getTvShow({ tvId, language }); - const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow); - if (!this.isValidTvdbId(tvdbId)) { + try { + await this.refreshToken(); + + const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow); + + if (!this.isValidTvdbId(tvdbId)) { + return await this.tmdb.getTvSeason({ tvId, seasonNumber, language }); + } + + return await this.getTvdbSeasonData(tvdbId, seasonNumber, tvId); + } catch (error) { + this.handleError('Failed to fetch TV season details', error); return await this.tmdb.getTvSeason({ tvId, seasonNumber, language }); } - - return await this.getTvdbSeasonData(tvdbId, seasonNumber, tvId); } catch (error) { logger.error( `[TVDB] Failed to fetch TV season details: ${error.message}` ); - return await this.tmdb.getTvSeason({ tvId, seasonNumber, language }); + throw error; } } diff --git a/server/lib/scanners/jellyfin/index.ts b/server/lib/scanners/jellyfin/index.ts index 0b79ef84..c6281bf9 100644 --- a/server/lib/scanners/jellyfin/index.ts +++ b/server/lib/scanners/jellyfin/index.ts @@ -1,8 +1,12 @@ -import type { TvShowIndexer } from '@server/api/indexer'; import type { JellyfinLibraryItem } from '@server/api/jellyfin'; import JellyfinAPI from '@server/api/jellyfin'; +import { getMetadataProvider } from '@server/api/metadata'; import TheMovieDb from '@server/api/themoviedb'; -import type { TmdbTvDetails } from '@server/api/themoviedb/interfaces'; +import { ANIME_KEYWORD_ID } from '@server/api/themoviedb/constants'; +import type { + TmdbKeyword, + TmdbTvDetails, +} from '@server/api/themoviedb/interfaces'; import { MediaStatus, MediaType } from '@server/constants/media'; import { MediaServerType } from '@server/constants/server'; import { getRepository } from '@server/datasource'; @@ -31,7 +35,6 @@ interface SyncStatus { class JellyfinScanner { private sessionId: string; private tmdb: TheMovieDb; - private tvShowIndexer: TvShowIndexer; private jfClient: JellyfinAPI; private items: JellyfinLibraryItem[] = []; private progress = 0; @@ -195,6 +198,42 @@ class JellyfinScanner { } } + private async getTvShow({ + tmdbId, + tvdbId, + }: { + tmdbId?: number; + tvdbId?: number; + }): Promise { + let tvShow; + + if (tmdbId) { + tvShow = await this.tmdb.getTvShow({ + tvId: Number(tmdbId), + }); + } else if (tvdbId) { + tvShow = await this.tmdb.getShowByTvdbId({ + tvdbId: Number(tvdbId), + }); + } else { + throw new Error('No ID provided'); + } + + const indexer = tvShow.keywords.results.some( + (keyword: TmdbKeyword) => keyword.id === ANIME_KEYWORD_ID + ) + ? await getMetadataProvider('anime') + : await getMetadataProvider('tv'); + + if (!(indexer instanceof TheMovieDb)) { + tvShow = await indexer.getTvShow({ + tvId: Number(tmdbId), + }); + } + + return tvShow; + } + private async processShow(jellyfinitem: JellyfinLibraryItem) { const mediaRepository = getRepository(Media); @@ -215,8 +254,8 @@ class JellyfinScanner { if (metadata.ProviderIds.Tmdb) { try { - tvShow = await this.tvShowIndexer.getTvShow({ - tvId: Number(metadata.ProviderIds.Tmdb), + tvShow = await this.getTvShow({ + tmdbId: Number(metadata.ProviderIds.Tmdb), }); } catch { this.log('Unable to find TMDb ID for this title.', 'debug', { @@ -226,8 +265,8 @@ class JellyfinScanner { } if (!tvShow && metadata.ProviderIds.Tvdb) { try { - tvShow = await this.tvShowIndexer.getShowByTvdbId({ - tvdbId: Number(metadata.ProviderIds.Tvdb), + tvShow = await this.getTvShow({ + tvdbId: Number(metadata.ProviderIds.Tmdb), }); } catch { this.log('Unable to find TVDb ID for this title.', 'debug', {