feat: anime profile support (#384)

closes #266
This commit is contained in:
sct
2020-12-18 14:32:40 +09:00
committed by GitHub
parent 1f0486eba2
commit 0972f40a4e
10 changed files with 222 additions and 14 deletions

View File

@@ -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');

View File

@@ -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;

View File

@@ -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,
});

View File

@@ -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,
});

View File

@@ -11,6 +11,11 @@ export interface ProductionCompany {
name: string;
}
export interface Keyword {
id: number;
name: string;
}
export interface Genre {
id: number;
name: string;

View File

@@ -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' });
}
});