Skip to content

Commit

Permalink
fix(requests): handle when tvdbid is null (#657)
Browse files Browse the repository at this point in the history
Co-authored-by: sct <sctsnipe@gmail.com>
  • Loading branch information
ankarhem and sct committed Jan 22, 2021
1 parent a3fe4e6 commit 2da0da8
Show file tree
Hide file tree
Showing 14 changed files with 508 additions and 94 deletions.
151 changes: 151 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,135 @@ components:
type: array
items:
$ref: '#/components/schemas/MovieResult'
SonarrSeries:
type: object
properties:
title:
type: string
example: COVID-25
sortTitle:
type: string
example: covid 25
seasonCount:
type: number
example: 1
status:
type: string
example: upcoming
overview:
type: string
example: The thread is picked up again by Marianne Schmidt which ...
network:
type: string
example: CBS
airTime:
type: string
example: 02:15
images:
type: array
items:
type: object
properties:
coverType:
type: string
example: banner
url:
type: string
example: /sonarr/MediaCoverProxy/6467f05d9872726ad08cbf920e5fee4bf69198682260acab8eab5d3c2c958e92/5c8f116c6aa5c.jpg
remotePoster:
type: string
example: https://artworks.thetvdb.com/banners/posters/5c8f116129983.jpg
seasons:
type: array
items:
type: object
properties:
seasonNumber:
type: number
example: 1
monitored:
type: boolean
example: true
year:
type: number
example: 2015
path:
type: string
profileId:
type: number
languageProfileId:
type: number
seasonFolder:
type: boolean
monitored:
type: boolean
useSceneNumbering:
type: boolean
runtime:
type: number
tvdbId:
type: number
example: 12345
tvRageId:
type: number
tvMazeId:
type: number
firstAired:
type: string
lastInfoSync:
type: string
nullable: true
seriesType:
type: string
cleanTitle:
type: string
imdbId:
type: string
titleSlug:
type: string
certification:
type: string
genres:
type: array
items:
type: string
tags:
type: array
items:
type: string
added:
type: string
ratings:
type: array
items:
type: object
properties:
votes:
type: number
value:
type: number
qualityProfileId:
type: number
id:
type: number
nullable: true
rootFolderPath:
type: string
nullable: true
addOptions:
type: array
items:
type: object
properties:
ignoreEpisodesWithFiles:
type: boolean
nullable: true
ignoreEpisodesWithoutFiles:
type: boolean
nullable: true
searchForMissingEpisodes:
type: boolean
nullable: true
securitySchemes:
cookieAuth:
type: apiKey
Expand Down Expand Up @@ -3193,6 +3322,28 @@ paths:
$ref: '#/components/schemas/SonarrSettings'
profiles:
$ref: '#/components/schemas/ServiceProfile'
/service/sonarr/lookup/{tmdbId}:
get:
summary: Returns a list of series from sonarr
description: Returns a list of series returned by searching for the name in sonarr
tags:
- service
parameters:
- in: path
name: tmdbId
required: true
schema:
type: number
example: 0
responses:
'200':
description: Request successful
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/SonarrSeries'

security:
- cookieAuth: []
Expand Down
Binary file added public/images/overseerr_poster_not_found.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions server/api/sonarr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,28 @@ class SonarrAPI {
});
}

public async getSeriesByTitle(title: string): Promise<SonarrSeries[]> {
try {
const response = await this.axios.get<SonarrSeries[]>('/series/lookup', {
params: {
term: title,
},
});

if (!response.data[0]) {
throw new Error('No series found');
}

return response.data;
} catch (e) {
logger.error('Error retrieving series by series title', {
label: 'Sonarr API',
message: e.message,
});
throw new Error('No series found');
}
}

public async getSeriesByTvdbId(id: number): Promise<SonarrSeries> {
try {
const response = await this.axios.get<SonarrSeries[]>('/series/lookup', {
Expand Down
24 changes: 16 additions & 8 deletions server/entity/MediaRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,12 @@ export class MediaRequest {
});
logger.info('Sent request to Radarr', { label: 'Media Request' });
} catch (e) {
throw new Error(
`[MediaRequest] Request failed to send to radarr: ${e.message}`
);
const errorMessage = `Request failed to send to radarr: ${e.message}`;
logger.error('Request failed to send to Radarr', {
label: 'Media Request',
errorMessage,
});
throw new Error(errorMessage);
}
}
}
Expand Down Expand Up @@ -501,8 +504,10 @@ export class MediaRequest {
}:${sonarrSettings.port}${sonarrSettings.baseUrl ?? ''}/api`,
});
const series = await tmdb.getTvShow({ tvId: media.tmdbId });
const tvdbId = series.external_ids.tvdb_id ?? media.tvdbId;

if (!series.external_ids.tvdb_id) {
if (!tvdbId) {
this.handleRemoveParentUpdate();
throw new Error('Series was missing tvdb id');
}

Expand Down Expand Up @@ -550,7 +555,7 @@ export class MediaRequest {
profileId: qualityProfile,
rootFolderPath: rootFolder,
title: series.name,
tvdbid: series.external_ids.tvdb_id,
tvdbid: tvdbId,
seasons: this.seasons.map((season) => season.seasonNumber),
seasonFolder: sonarrSettings.enableSeasonFolders,
seriesType,
Expand Down Expand Up @@ -590,9 +595,12 @@ export class MediaRequest {
});
logger.info('Sent request to Sonarr', { label: 'Media Request' });
} catch (e) {
throw new Error(
`[MediaRequest] Request failed to send to sonarr: ${e.message}`
);
const errorMessage = `Request failed to send to sonarr: ${e.message}`;
logger.error('Request failed to send to Sonarr', {
label: 'Media Request',
errorMessage,
});
throw new Error(errorMessage);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion server/routes/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ requestRoutes.post(
if (!media) {
media = new Media({
tmdbId: tmdbMedia.id,
tvdbId: tmdbMedia.external_ids.tvdb_id,
tvdbId: req.body.tvdbId ?? tmdbMedia.external_ids.tvdb_id,
status: !req.body.is4k ? MediaStatus.PENDING : MediaStatus.UNKNOWN,
status4k: req.body.is4k ? MediaStatus.PENDING : MediaStatus.UNKNOWN,
mediaType: req.body.mediaType,
Expand Down
54 changes: 52 additions & 2 deletions server/routes/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
ServiceCommonServerWithDetails,
} from '../interfaces/api/serviceInterfaces';
import { getSettings } from '../lib/settings';
import TheMovieDb from '../api/themoviedb';
import logger from '../logger';

const serviceRoutes = Router();

Expand Down Expand Up @@ -100,13 +102,13 @@ serviceRoutes.get<{ sonarrId: string }>(
const settings = getSettings();

const sonarrSettings = settings.sonarr.find(
(radarr) => radarr.id === Number(req.params.sonarrId)
(sonarr) => sonarr.id === Number(req.params.sonarrId)
);

if (!sonarrSettings) {
return next({
status: 404,
message: 'Radarr server with provided ID does not exist.',
message: 'Sonarr server with provided ID does not exist.',
});
}

Expand Down Expand Up @@ -145,4 +147,52 @@ serviceRoutes.get<{ sonarrId: string }>(
}
);

serviceRoutes.get<{ tmdbId: string }>(
'/sonarr/lookup/:tmdbId',
async (req, res, next) => {
const settings = getSettings();
const tmdb = new TheMovieDb();

const sonarrSettings = settings.sonarr[0];

if (!sonarrSettings) {
logger.error('No sonarr server has been setup', {
label: 'Media Request',
});
return next({
status: 404,
message: 'No sonarr server has been setup',
});
}

const sonarr = new SonarrAPI({
apiKey: sonarrSettings.apiKey,
url: `${sonarrSettings.useSsl ? 'https' : 'http'}://${
sonarrSettings.hostname
}:${sonarrSettings.port}${sonarrSettings.baseUrl ?? ''}/api`,
});

try {
const tv = await tmdb.getTvShow({
tvId: Number(req.params.tmdbId),
language: req.query.language as string,
});

const response = await sonarr.getSeriesByTitle(tv.name);

return res.status(200).json(response);
} catch (e) {
logger.error('Failed to fetch tvdb search results', {
label: 'Media Request',
message: e.message,
});

return next({
status: 500,
message: 'Something went wrong trying to fetch series information',
});
}
}
);

export default serviceRoutes;
6 changes: 5 additions & 1 deletion src/components/MovieDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
<div className="flex flex-col items-center pt-4 lg:flex-row lg:items-end">
<div className="lg:mr-4">
<img
src={`//image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`}
src={
data.posterPath
? `//image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`
: '/images/overseerr_poster_not_found.png'
}
alt=""
className="w-32 rounded shadow md:rounded-lg md:shadow-2xl md:w-44 lg:w-52"
/>
Expand Down

0 comments on commit 2da0da8

Please sign in to comment.