fix: disambiguate tmdb ids by media type across lookups (#2577)

This commit is contained in:
fallenbagel
2026-03-14 23:47:21 +05:00
committed by GitHub
parent d25d0ca570
commit 0be18968b4
22 changed files with 479 additions and 70 deletions

View File

@@ -89,18 +89,29 @@ blocklistRoutes.get(
type: 'or',
}),
async (req, res, next) => {
const mediaType = req.query.mediaType;
if (mediaType !== MediaType.MOVIE && mediaType !== MediaType.TV) {
return next({
status: 400,
message: 'Invalid or missing mediaType query parameter.',
});
}
try {
const blocklisteRepository = getRepository(Blocklist);
const blocklistItem = await blocklisteRepository.findOneOrFail({
where: { tmdbId: Number(req.params.id) },
where: {
tmdbId: Number(req.params.id),
mediaType,
},
});
return res.status(200).send(blocklistItem);
} catch (e) {
if (e instanceof EntityNotFoundError) {
return next({
status: 401,
status: 404,
message: e.message,
});
}
@@ -153,11 +164,22 @@ blocklistRoutes.delete(
type: 'or',
}),
async (req, res, next) => {
const mediaType = req.query.mediaType;
if (mediaType !== MediaType.MOVIE && mediaType !== MediaType.TV) {
return next({
status: 400,
message: 'Invalid or missing mediaType query parameter.',
});
}
try {
const blocklisteRepository = getRepository(Blocklist);
const blocklistItem = await blocklisteRepository.findOneOrFail({
where: { tmdbId: Number(req.params.id) },
where: {
tmdbId: Number(req.params.id),
mediaType,
},
});
await blocklisteRepository.remove(blocklistItem);
@@ -165,7 +187,10 @@ blocklistRoutes.delete(
const mediaRepository = getRepository(Media);
const mediaItem = await mediaRepository.findOneOrFail({
where: { tmdbId: Number(req.params.id) },
where: {
tmdbId: Number(req.params.id),
mediaType: req.query.mediaType as MediaType,
},
});
await mediaRepository.remove(mediaItem);
@@ -174,7 +199,7 @@ blocklistRoutes.delete(
} catch (e) {
if (e instanceof EntityNotFoundError) {
return next({
status: 401,
status: 404,
message: e.message,
});
}

View File

@@ -1,4 +1,5 @@
import TheMovieDb from '@server/api/themoviedb';
import { MediaType } from '@server/constants/media';
import Media from '@server/entity/Media';
import logger from '@server/logger';
import { mapCollection } from '@server/models/Collection';
@@ -17,7 +18,10 @@ collectionRoutes.get<{ id: string }>('/:id', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
collection.parts.map((part) => part.id)
collection.parts.map((part) => ({
tmdbId: part.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json(mapCollection(collection, media));

View File

@@ -124,7 +124,10 @@ discoverRoutes.get('/movies', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
let keywordData: TmdbKeyword[] = [];
@@ -193,7 +196,10 @@ discoverRoutes.get<{ language: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({
@@ -251,7 +257,10 @@ discoverRoutes.get<{ genreId: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({
@@ -299,7 +308,10 @@ discoverRoutes.get<{ studioId: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({
@@ -349,7 +361,10 @@ discoverRoutes.get('/movies/upcoming', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({
@@ -417,7 +432,10 @@ discoverRoutes.get('/tv', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
let keywordData: TmdbKeyword[] = [];
@@ -485,7 +503,10 @@ discoverRoutes.get<{ language: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
return res.status(200).json({
@@ -543,7 +564,10 @@ discoverRoutes.get<{ genreId: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
return res.status(200).json({
@@ -591,7 +615,10 @@ discoverRoutes.get<{ networkId: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
return res.status(200).json({
@@ -641,7 +668,10 @@ discoverRoutes.get('/tv/upcoming', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
return res.status(200).json({
@@ -711,7 +741,10 @@ discoverRoutes.get('/trending', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: isMovie(result) ? MediaType.MOVIE : MediaType.TV,
}))
);
return res.status(200).json({
@@ -755,7 +788,10 @@ discoverRoutes.get<{ keywordId: string }>(
const media = await Media.getRelatedMedia(
req.user,
data.results.map((result) => result.id)
data.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({

View File

@@ -27,6 +27,7 @@ movieRoutes.get('/:id', async (req, res, next) => {
const onUserWatchlist = await getRepository(Watchlist).exist({
where: {
tmdbId: Number(req.params.id),
mediaType: MediaType.MOVIE,
requestedBy: {
id: req.user?.id,
},
@@ -67,7 +68,10 @@ movieRoutes.get('/:id/recommendations', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
results.results.map((result) => result.id)
results.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({
@@ -109,7 +113,10 @@ movieRoutes.get('/:id/similar', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
results.results.map((result) => result.id)
results.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.MOVIE,
}))
);
return res.status(200).json({

View File

@@ -43,12 +43,22 @@ personRoutes.get('/:id/combined_credits', async (req, res, next) => {
const castMedia = await Media.getRelatedMedia(
req.user,
combinedCredits.cast.map((result) => result.id)
combinedCredits.cast
.filter((result) => result.media_type)
.map((result) => ({
tmdbId: result.id,
mediaType: result.media_type!,
}))
);
const crewMedia = await Media.getRelatedMedia(
req.user,
combinedCredits.crew.map((result) => result.id)
combinedCredits.crew
.filter((result) => result.media_type)
.map((result) => ({
tmdbId: result.id,
mediaType: result.media_type!,
}))
);
return res.status(200).json({

View File

@@ -35,7 +35,10 @@ searchRoutes.get('/', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
results.results.map((result) => result.id)
results.results.map((result) => ({
tmdbId: result.id,
mediaType: result.media_type,
}))
);
return res.status(200).json({

View File

@@ -35,6 +35,7 @@ tvRoutes.get('/:id', async (req, res, next) => {
const onUserWatchlist = await getRepository(Watchlist).exist({
where: {
tmdbId: Number(req.params.id),
mediaType: MediaType.TV,
requestedBy: {
id: req.user?.id,
},
@@ -110,7 +111,10 @@ tvRoutes.get('/:id/recommendations', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
results.results.map((result) => result.id)
results.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
return res.status(200).json({
@@ -151,7 +155,10 @@ tvRoutes.get('/:id/similar', async (req, res, next) => {
const media = await Media.getRelatedMedia(
req.user,
results.results.map((result) => result.id)
results.results.map((result) => ({
tmdbId: result.id,
mediaType: MediaType.TV,
}))
);
return res.status(200).json({

View File

@@ -7,6 +7,7 @@ import logger from '@server/logger';
import { Router } from 'express';
import { QueryFailedError } from 'typeorm';
import { MediaType } from '@server/constants/media';
import { watchlistCreate } from '@server/interfaces/api/watchlistCreate';
const watchlistRoutes = Router();
@@ -57,12 +58,24 @@ watchlistRoutes.delete('/:tmdbId', async (req, res, next) => {
});
}
try {
await Watchlist.deleteWatchlist(Number(req.params.tmdbId), req.user);
const mediaType = req.query.mediaType;
if (mediaType !== MediaType.MOVIE && mediaType !== MediaType.TV) {
return next({
status: 400,
message: 'Invalid mediaType query parameter.',
});
}
await Watchlist.deleteWatchlist(
Number(req.params.tmdbId),
mediaType,
req.user
);
return res.status(204).send();
} catch (e) {
if (e instanceof NotFoundError) {
return next({
status: 401,
status: 404,
message: e.message,
});
}