fix: error during get episodes

This commit is contained in:
TOomaAh
2024-10-20 16:17:42 +02:00
parent b88606a1df
commit 377c6a40a8
8 changed files with 113 additions and 90 deletions

View File

@@ -22,4 +22,6 @@ export interface TvShowIndexer {
seasonNumber: number;
language?: string;
}): Promise<TmdbSeasonWithEpisodes>;
getSeasonIdentifier(req: any): number;
}

View File

@@ -198,6 +198,10 @@ class TheMovieDb extends ExternalAPI implements TvShowIndexer {
}
};
getSeasonIdentifier(req: any): number {
return req.params.seasonNumber;
}
public searchTvShows = async ({
query,
page = 1,
@@ -342,6 +346,12 @@ class TheMovieDb extends ExternalAPI implements TvShowIndexer {
}
);
data.episodes = data.episodes.map((episode) => {
if (episode.still_path !== '') {
episode.still_path = `https://image.tmdb.org/t/p/original/${episode.still_path}`;
}
return episode;
});
return data;
} catch (e) {
throw new Error(`[TMDB] Failed to fetch TV show details: ${e.message}`);

View File

@@ -13,9 +13,9 @@ import cacheManager from '@server/lib/cache';
import logger from '@server/logger';
class Tvdb extends ExternalAPI implements TvShowIndexer {
static instance: Tvdb;
private tmdb: TheMovieDb = new TheMovieDb();
private constructor() {
public constructor() {
super(
'https://skyhook.sonarr.tv/v1/tvdb/shows',
{},
@@ -29,18 +29,6 @@ class Tvdb extends ExternalAPI implements TvShowIndexer {
);
}
public static async getInstance() {
if (!this.instance) {
this.instance = new Tvdb();
await this.instance.login();
logger.info(
'Tvdb instance created with token => ' +
this.instance.defaultHeaders.Authorization
);
}
return this.instance;
}
async login() {
try {
return await this.get<TvdbLoginResponse>('/en/445009', {});
@@ -51,65 +39,66 @@ class Tvdb extends ExternalAPI implements TvShowIndexer {
public getTvShow = async ({
tvId,
language = 'en',
}: {
tvId: number;
language?: string;
}): Promise<TmdbTvDetails> => {
try {
const tmdb = new TheMovieDb();
const tmdbTvShow = await tmdb.getTvShow({ tvId: tvId });
const tmdbTvShow = await this.tmdb.getTvShow({ tvId: tvId });
const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow);
const tvdbId = tmdbTvShow.external_ids.tvdb_id;
if (!tvdbId) {
if (tvdbId === -1) {
return tmdbTvShow;
}
const data = await this.get<TvdbTvShowDetail>(
`/${language}/${tvdbId}`,
{},
43200
);
try {
const data = await this.get<TvdbTvShowDetail>(
`/en/${tvdbId}`,
{},
43200
);
const correctSeasons = data.seasons.filter((value) => {
return value.seasonNumber !== 0;
});
const correctSeasons = data.seasons.filter((value) => {
return value.seasonNumber !== 0;
});
tmdbTvShow.seasons = [];
tmdbTvShow.seasons = [];
for (const season of correctSeasons) {
if (season.seasonNumber) {
logger.info(`Fetching TV season ${season.seasonNumber}`);
for (const season of correctSeasons) {
if (season.seasonNumber) {
logger.info(`Fetching TV season ${season.seasonNumber}`);
try {
const seasonData = {
id: tvdbId,
episode_count: data.episodes.filter((value) => {
return value.seasonNumber === season.seasonNumber;
}).length,
name: `${season.seasonNumber}`,
overview: '',
season_number: season.seasonNumber,
poster_path: '',
air_date: '',
image: '',
};
try {
const seasonData = {
id: tvdbId,
episode_count: data.episodes.filter((value) => {
return value.seasonNumber === season.seasonNumber;
}).length,
name: `${season.seasonNumber}`,
overview: '',
season_number: season.seasonNumber,
poster_path: '',
air_date: '',
image: '',
};
tmdbTvShow.seasons.push(seasonData);
} catch (error) {
logger.error(
`Failed to get season ${season.seasonNumber} for TV show ${tvdbId}: ${error.message}`,
{
label: 'Tvdb',
message: `Failed to get season ${season.seasonNumber} for TV show ${tvdbId}`,
}
);
tmdbTvShow.seasons.push(seasonData);
} catch (error) {
logger.error(
`Failed to get season ${season.seasonNumber} for TV show ${tvdbId}: ${error.message}`,
{
label: 'Tvdb',
message: `Failed to get season ${season.seasonNumber} for TV show ${tvdbId}`,
}
);
}
}
}
}
return tmdbTvShow;
return tmdbTvShow;
} catch (e) {
return tmdbTvShow;
}
} catch (error) {
throw new Error(
`[TVDB] Failed to fetch TV show details: ${error.message}`
@@ -117,6 +106,14 @@ class Tvdb extends ExternalAPI implements TvShowIndexer {
}
};
private getTvdbIdFromTmdb(tmdbTvShow: TmdbTvDetails) {
try {
return tmdbTvShow.external_ids.tvdb_id || -1;
} catch (e) {
return -1;
}
}
public getTvSeason = async ({
tvId,
seasonNumber,
@@ -139,9 +136,16 @@ class Tvdb extends ExternalAPI implements TvShowIndexer {
season_number: 0,
};
}
const tmdbTvShow = await this.tmdb.getTvShow({ tvId: tvId });
const tvdbId = this.getTvdbIdFromTmdb(tmdbTvShow);
if (tvdbId === -1) {
return await this.tmdb.getTvSeason({ tvId, seasonNumber, language });
}
try {
const tvdbSeason = await this.get<TvdbTvShowDetail>(
`/en/${tvId}`,
`/en/${tvdbId}`,
{ lang: language },
43200
);
@@ -150,11 +154,11 @@ class Tvdb extends ExternalAPI implements TvShowIndexer {
.filter((value) => {
return value.seasonNumber === seasonNumber;
})
.map((episode) => ({
.map((episode, index) => ({
id: episode.tvdbId,
air_date: episode.airDate,
episode_number: episode.episodeNumber,
name: episode.title || '',
name: episode.title || `Episode ${index + 1}`,
overview: episode.overview || '',
season_number: episode.seasonNumber,
production_code: '',
@@ -176,11 +180,16 @@ class Tvdb extends ExternalAPI implements TvShowIndexer {
season_number: episodes.length,
};
} catch (error) {
throw new Error(
logger.error(
`[TVDB] Failed to fetch TV season details: ${error.message}`
);
return await this.tmdb.getTvSeason({ tvId, seasonNumber, language });
}
};
getSeasonIdentifier(req: any): number {
return req.params.seasonId;
}
}
export default Tvdb;

View File

@@ -1,3 +1,6 @@
import type { TvShowIndexer } from '@server/api/indexer';
import TheMovieDb from '@server/api/indexer/themoviedb';
import Tvdb from '@server/api/indexer/tvdb';
import { MediaServerType } from '@server/constants/server';
import { Permission } from '@server/lib/permissions';
import { runMigrations } from '@server/lib/settings/migrator';
@@ -787,4 +790,13 @@ export const getSettings = (initialSettings?: AllSettings): Settings => {
return settings;
};
export const getIndexer = (): TvShowIndexer => {
const settings = getSettings();
if (settings.tvdb.use) {
return new Tvdb();
} else {
return new TheMovieDb();
}
};
export default Settings;

View File

@@ -28,7 +28,7 @@ tvdbRoutes.put('/', (req, res) => {
tvdbRoutes.post('/test', async (req, res, next) => {
try {
const tvdb = await Tvdb.getInstance();
const tvdb = new Tvdb();
await tvdb.login();
return res.status(200).json({ message: 'Successfully connected to Tvdb' });
} catch (e) {

View File

@@ -1,11 +1,10 @@
import TheMovieDb from '@server/api/indexer/themoviedb';
import Tvdb from '@server/api/indexer/tvdb';
import RottenTomatoes from '@server/api/rating/rottentomatoes';
import { MediaType } from '@server/constants/media';
import { getRepository } from '@server/datasource';
import Media from '@server/entity/Media';
import { Watchlist } from '@server/entity/Watchlist';
import { getSettings } from '@server/lib/settings';
import { getIndexer } from '@server/lib/settings';
import logger from '@server/logger';
import { mapTvResult } from '@server/models/Search';
import { mapSeasonWithEpisodes, mapTvDetails } from '@server/models/Tv';
@@ -14,15 +13,10 @@ import { Router } from 'express';
const tvRoutes = Router();
tvRoutes.get('/:id', async (req, res, next) => {
const settings = getSettings();
let tmdb;
if (settings.tvdb.use) {
tmdb = await Tvdb.getInstance();
} else {
tmdb = new TheMovieDb();
}
const indexer = getIndexer();
try {
const tv = await tmdb.getTvShow({
const tv = await indexer.getTvShow({
tvId: Number(req.params.id),
language: (req.query.language as string) ?? req.locale,
});
@@ -42,7 +36,9 @@ tvRoutes.get('/:id', async (req, res, next) => {
// TMDB issue where it doesnt fallback to English when no overview is available in requested locale.
if (!data.overview) {
const tvEnglish = await tmdb.getTvShow({ tvId: Number(req.params.id) });
const tvEnglish = await indexer.getTvShow({
tvId: Number(req.params.id),
});
data.overview = tvEnglish.overview;
}
@@ -62,20 +58,13 @@ tvRoutes.get('/:id', async (req, res, next) => {
tvRoutes.get('/:id/season/:seasonNumber/:seasonId', async (req, res, next) => {
try {
const settings = getSettings();
let tmdb;
let seasonIdentifier;
if (settings.tvdb.use) {
tmdb = await Tvdb.getInstance();
seasonIdentifier = req.params.seasonId;
} else {
tmdb = new TheMovieDb();
seasonIdentifier = req.params.seasonNumber;
}
const indexer = getIndexer();
const seasonIdentifier = indexer.getSeasonIdentifier(req);
const season = await tmdb.getTvSeason({
const season = await indexer.getTvSeason({
tvId: Number(req.params.id),
seasonNumber: Number(seasonIdentifier),
seasonId: seasonIdentifier,
seasonNumber: Number(req.params.seasonNumber),
});
return res.status(200).json(mapSeasonWithEpisodes(season));

View File

@@ -1,6 +1,7 @@
import Button from '@app/components/Common/Button';
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
import PageTitle from '@app/components/Common/PageTitle';
import SettingsBadge from '@app/components/Settings/SettingsBadge';
import globalMessages from '@app/i18n/globalMessages';
import defineMessages from '@app/utils/defineMessages';
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
@@ -17,13 +18,11 @@ const messages = defineMessages('components.Settings', {
apikey: 'API Key',
pin: 'PIN',
enable: 'Enable',
enableTip: 'Enable Tvdb (only for season and episode)',
enableTip:
'Enable Tvdb (only for season and episode).' +
' Due to a limitation of the api used, only English is available.',
});
/*interface SettingsTvdbProps {
onEdit: () => void;
}*/
const SettingsTvdb = () => {
const intl = useIntl();
const [isTesting, setIsTesting] = useState(false);
@@ -111,6 +110,8 @@ const SettingsTvdb = () => {
<span className="mr-2">
{intl.formatMessage(messages.enable)}
</span>
<SettingsBadge badgeType="experimental" />
<span className="label-tip">
{intl.formatMessage(messages.enableTip)}
</span>

View File

@@ -61,7 +61,7 @@ const Season = ({ seasonNumber, tvId, seasonId }: SeasonProps) => {
<CachedImage
type="tmdb"
className="rounded-lg object-contain"
src={`https://image.tmdb.org/t/p/original/${episode.stillPath}`}
src={episode.stillPath}
alt=""
fill
/>