mirror of
https://github.com/sct/overseerr.git
synced 2025-12-25 16:15:06 +01:00
@@ -6,7 +6,7 @@ interface SonarrSeason {
|
||||
monitored: boolean;
|
||||
}
|
||||
|
||||
interface SonarrSeries {
|
||||
export interface SonarrSeries {
|
||||
title: string;
|
||||
sortTitle: string;
|
||||
seasonCount: number;
|
||||
@@ -33,7 +33,7 @@ interface SonarrSeries {
|
||||
tvMazeId: number;
|
||||
firstAired: string;
|
||||
lastInfoSync?: string;
|
||||
seriesType: string;
|
||||
seriesType: 'standard' | 'daily' | 'anime';
|
||||
cleanTitle: string;
|
||||
imdbId: string;
|
||||
titleSlug: string;
|
||||
@@ -78,6 +78,7 @@ interface AddSeriesOptions {
|
||||
seasons: number[];
|
||||
seasonFolder: boolean;
|
||||
rootFolderPath: string;
|
||||
seriesType: SonarrSeries['seriesType'];
|
||||
monitored?: boolean;
|
||||
searchNow?: boolean;
|
||||
}
|
||||
@@ -153,6 +154,7 @@ class SonarrAPI {
|
||||
seasonFolder: options.seasonFolder,
|
||||
monitored: options.monitored,
|
||||
rootFolderPath: options.rootFolderPath,
|
||||
seriesType: options.seriesType,
|
||||
addOptions: {
|
||||
ignoreEpisodesWithFiles: true,
|
||||
searchForMissingEpisodes: options.searchNow,
|
||||
@@ -164,7 +166,7 @@ class SonarrAPI {
|
||||
} catch (e) {
|
||||
logger.error('Something went wrong adding a series to Sonarr', {
|
||||
label: 'Sonarr API',
|
||||
message: e.message,
|
||||
errorMessage: e.message,
|
||||
error: e,
|
||||
});
|
||||
throw new Error('Failed to add series');
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
export const ANIME_KEYWORD_ID = 210024;
|
||||
|
||||
interface SearchOptions {
|
||||
query: string;
|
||||
page?: number;
|
||||
@@ -258,6 +260,11 @@ export interface TmdbTvDetails {
|
||||
name: string;
|
||||
origin_country: string;
|
||||
}[];
|
||||
spoken_languages: {
|
||||
english_name: string;
|
||||
iso_639_1: string;
|
||||
name: string;
|
||||
}[];
|
||||
seasons: TmdbTvSeasonResult[];
|
||||
status: string;
|
||||
type: string;
|
||||
@@ -268,6 +275,14 @@ export interface TmdbTvDetails {
|
||||
crew: TmdbCreditCrew[];
|
||||
};
|
||||
external_ids: TmdbExternalIds;
|
||||
keywords: {
|
||||
results: TmdbKeyword[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface TmdbKeyword {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface TmdbPersonDetail {
|
||||
@@ -437,7 +452,10 @@ class TheMovieDb {
|
||||
}): Promise<TmdbTvDetails> => {
|
||||
try {
|
||||
const response = await this.axios.get<TmdbTvDetails>(`/tv/${tvId}`, {
|
||||
params: { language, append_to_response: 'credits,external_ids' },
|
||||
params: {
|
||||
language,
|
||||
append_to_response: 'credits,external_ids,keywords',
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
|
||||
@@ -15,11 +15,11 @@ import { User } from './User';
|
||||
import Media from './Media';
|
||||
import { MediaStatus, MediaRequestStatus, MediaType } from '../constants/media';
|
||||
import { getSettings } from '../lib/settings';
|
||||
import TheMovieDb from '../api/themoviedb';
|
||||
import TheMovieDb, { ANIME_KEYWORD_ID } from '../api/themoviedb';
|
||||
import RadarrAPI from '../api/radarr';
|
||||
import logger from '../logger';
|
||||
import SeasonRequest from './SeasonRequest';
|
||||
import SonarrAPI from '../api/sonarr';
|
||||
import SonarrAPI, { SonarrSeries } from '../api/sonarr';
|
||||
import notificationManager, { Notification } from '../lib/notifications';
|
||||
|
||||
@Entity()
|
||||
@@ -336,14 +336,32 @@ export class MediaRequest {
|
||||
throw new Error('Series was missing tvdb id');
|
||||
}
|
||||
|
||||
let seriesType: SonarrSeries['seriesType'] = 'standard';
|
||||
|
||||
// Change series type to anime if the anime keyword is present on tmdb
|
||||
if (
|
||||
series.keywords.results.some(
|
||||
(keyword) => keyword.id === ANIME_KEYWORD_ID
|
||||
)
|
||||
) {
|
||||
seriesType = 'anime';
|
||||
}
|
||||
|
||||
// Run this asynchronously so we don't wait for it on the UI side
|
||||
sonarr.addSeries({
|
||||
profileId: sonarrSettings.activeProfileId,
|
||||
rootFolderPath: sonarrSettings.activeDirectory,
|
||||
profileId:
|
||||
seriesType === 'anime' && sonarrSettings.activeAnimeProfileId
|
||||
? sonarrSettings.activeAnimeProfileId
|
||||
: sonarrSettings.activeProfileId,
|
||||
rootFolderPath:
|
||||
seriesType === 'anime' && sonarrSettings.activeAnimeDirectory
|
||||
? sonarrSettings.activeAnimeDirectory
|
||||
: sonarrSettings.activeDirectory,
|
||||
title: series.name,
|
||||
tvdbid: series.external_ids.tvdb_id,
|
||||
seasons: this.seasons.map((season) => season.seasonNumber),
|
||||
seasonFolder: sonarrSettings.enableSeasonFolders,
|
||||
seriesType,
|
||||
monitored: true,
|
||||
searchNow: true,
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
mapCrew,
|
||||
ExternalIds,
|
||||
mapExternalIds,
|
||||
Keyword,
|
||||
} from './common';
|
||||
import {
|
||||
TmdbTvEpisodeResult,
|
||||
@@ -45,6 +46,12 @@ export interface SeasonWithEpisodes extends Season {
|
||||
externalIds: ExternalIds;
|
||||
}
|
||||
|
||||
interface SpokenLanguage {
|
||||
englishName: string;
|
||||
iso_639_1: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface TvDetails {
|
||||
id: number;
|
||||
backdropPath?: string;
|
||||
@@ -74,6 +81,7 @@ export interface TvDetails {
|
||||
overview: string;
|
||||
popularity: number;
|
||||
productionCompanies: ProductionCompany[];
|
||||
spokenLanguages: SpokenLanguage[];
|
||||
seasons: Season[];
|
||||
status: string;
|
||||
type: string;
|
||||
@@ -84,6 +92,7 @@ export interface TvDetails {
|
||||
crew: Crew[];
|
||||
};
|
||||
externalIds: ExternalIds;
|
||||
keywords: Keyword[];
|
||||
mediaInfo?: Media;
|
||||
}
|
||||
|
||||
@@ -161,6 +170,11 @@ export const mapTvDetails = (
|
||||
originCountry: company.origin_country,
|
||||
logoPath: company.logo_path,
|
||||
})),
|
||||
spokenLanguages: show.spoken_languages.map((language) => ({
|
||||
englishName: language.english_name,
|
||||
iso_639_1: language.iso_639_1,
|
||||
name: language.name,
|
||||
})),
|
||||
seasons: show.seasons.map(mapSeasonResult),
|
||||
status: show.status,
|
||||
type: show.type,
|
||||
@@ -179,5 +193,9 @@ export const mapTvDetails = (
|
||||
crew: show.credits.crew.map(mapCrew),
|
||||
},
|
||||
externalIds: mapExternalIds(show.external_ids),
|
||||
keywords: show.keywords.results.map((keyword) => ({
|
||||
id: keyword.id,
|
||||
name: keyword.name,
|
||||
})),
|
||||
mediaInfo: media,
|
||||
});
|
||||
|
||||
@@ -11,6 +11,11 @@ export interface ProductionCompany {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Keyword {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Genre {
|
||||
id: number;
|
||||
name: string;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { mapTvDetails, mapSeasonWithEpisodes } from '../models/Tv';
|
||||
import { mapTvResult } from '../models/Search';
|
||||
import Media from '../entity/Media';
|
||||
import RottenTomatoes from '../api/rottentomatoes';
|
||||
import logger from '../logger';
|
||||
|
||||
const tvRoutes = Router();
|
||||
|
||||
@@ -19,6 +20,10 @@ tvRoutes.get('/:id', async (req, res, next) => {
|
||||
|
||||
return res.status(200).json(mapTvDetails(tv, media));
|
||||
} catch (e) {
|
||||
logger.error('Failed to get tv show', {
|
||||
label: 'API',
|
||||
errorMessage: e.message,
|
||||
});
|
||||
return next({ status: 404, message: 'TV Show does not exist' });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user