mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat: throw 404 when movie/tv show doesnt exist
also adds site webmanifest for mobile icons and title changes for tv/movie pages
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
RelationCount,
|
||||
} from 'typeorm';
|
||||
import { Permission, hasPermission } from '../lib/permissions';
|
||||
import { MediaRequest } from './MediaRequest';
|
||||
@@ -38,6 +39,9 @@ export class User {
|
||||
@Column()
|
||||
public avatar: string;
|
||||
|
||||
@RelationCount((user: User) => user.requests)
|
||||
public requestCount: number;
|
||||
|
||||
@OneToMany(() => MediaRequest, (request) => request.requestedBy)
|
||||
public requests: MediaRequest[];
|
||||
|
||||
|
10
server/interfaces/api/common.ts
Normal file
10
server/interfaces/api/common.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
interface PageInfo {
|
||||
pages: number;
|
||||
page: number;
|
||||
results: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export interface PaginatedResponse {
|
||||
pageInfo: PageInfo;
|
||||
}
|
@@ -1,11 +1,6 @@
|
||||
import type Media from '../../entity/Media';
|
||||
import { PaginatedResponse } from './common';
|
||||
|
||||
export interface MediaResultsResponse {
|
||||
pageInfo: {
|
||||
pages: number;
|
||||
page: number;
|
||||
results: number;
|
||||
pageSize: number;
|
||||
};
|
||||
export interface MediaResultsResponse extends PaginatedResponse {
|
||||
results: Media[];
|
||||
}
|
||||
|
6
server/interfaces/api/requestInterfaces.ts
Normal file
6
server/interfaces/api/requestInterfaces.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { PaginatedResponse } from './common';
|
||||
import type { MediaRequest } from '../../entity/MediaRequest';
|
||||
|
||||
export interface RequestResultsResponse extends PaginatedResponse {
|
||||
results: MediaRequest[];
|
||||
}
|
@@ -8,17 +8,21 @@ import RottenTomatoes from '../api/rottentomatoes';
|
||||
|
||||
const movieRoutes = Router();
|
||||
|
||||
movieRoutes.get('/:id', async (req, res) => {
|
||||
movieRoutes.get('/:id', async (req, res, next) => {
|
||||
const tmdb = new TheMovieDb();
|
||||
|
||||
const movie = await tmdb.getMovie({
|
||||
movieId: Number(req.params.id),
|
||||
language: req.query.language as string,
|
||||
});
|
||||
try {
|
||||
const movie = await tmdb.getMovie({
|
||||
movieId: Number(req.params.id),
|
||||
language: req.query.language as string,
|
||||
});
|
||||
|
||||
const media = await Media.getMedia(movie.id);
|
||||
const media = await Media.getMedia(movie.id);
|
||||
|
||||
return res.status(200).json(mapMovieDetails(movie, media));
|
||||
return res.status(200).json(mapMovieDetails(movie, media));
|
||||
} catch (e) {
|
||||
return next({ status: 404, message: 'Movie does not exist' });
|
||||
}
|
||||
});
|
||||
|
||||
movieRoutes.get('/:id/recommendations', async (req, res) => {
|
||||
@@ -74,27 +78,27 @@ movieRoutes.get('/:id/similar', async (req, res) => {
|
||||
});
|
||||
|
||||
movieRoutes.get('/:id/ratings', async (req, res, next) => {
|
||||
const tmdb = new TheMovieDb();
|
||||
const rtapi = new RottenTomatoes();
|
||||
try {
|
||||
const tmdb = new TheMovieDb();
|
||||
const rtapi = new RottenTomatoes();
|
||||
|
||||
const movie = await tmdb.getMovie({
|
||||
movieId: Number(req.params.id),
|
||||
});
|
||||
const movie = await tmdb.getMovie({
|
||||
movieId: Number(req.params.id),
|
||||
});
|
||||
|
||||
if (!movie) {
|
||||
const rtratings = await rtapi.getMovieRatings(
|
||||
movie.title,
|
||||
Number(movie.release_date.slice(0, 4))
|
||||
);
|
||||
|
||||
if (!rtratings) {
|
||||
return next({ status: 404, message: 'Unable to retrieve ratings' });
|
||||
}
|
||||
|
||||
return res.status(200).json(rtratings);
|
||||
} catch (e) {
|
||||
return next({ status: 404, message: 'Movie does not exist' });
|
||||
}
|
||||
|
||||
const rtratings = await rtapi.getMovieRatings(
|
||||
movie.title,
|
||||
Number(movie.release_date.slice(0, 4))
|
||||
);
|
||||
|
||||
if (!rtratings) {
|
||||
return next({ status: 404, message: 'Unable to retrieve ratings' });
|
||||
}
|
||||
|
||||
return res.status(200).json(rtratings);
|
||||
});
|
||||
|
||||
export default movieRoutes;
|
||||
|
@@ -8,12 +8,16 @@ import Media from '../entity/Media';
|
||||
import { MediaStatus, MediaRequestStatus, MediaType } from '../constants/media';
|
||||
import SeasonRequest from '../entity/SeasonRequest';
|
||||
import logger from '../logger';
|
||||
import { RequestResultsResponse } from '../interfaces/api/requestInterfaces';
|
||||
|
||||
const requestRoutes = Router();
|
||||
|
||||
requestRoutes.get('/', async (req, res, next) => {
|
||||
const requestRepository = getRepository(MediaRequest);
|
||||
try {
|
||||
const pageSize = Number(req.query.take) ?? 20;
|
||||
const skip = Number(req.query.skip) ?? 0;
|
||||
|
||||
let statusFilter:
|
||||
| MediaRequestStatus
|
||||
| FindOperator<MediaRequestStatus>
|
||||
@@ -51,23 +55,33 @@ requestRoutes.get('/', async (req, res, next) => {
|
||||
break;
|
||||
}
|
||||
|
||||
const requests = req.user?.hasPermission(Permission.MANAGE_REQUESTS)
|
||||
? await requestRepository.find({
|
||||
const [requests, requestCount] = req.user?.hasPermission(
|
||||
Permission.MANAGE_REQUESTS
|
||||
)
|
||||
? await requestRepository.findAndCount({
|
||||
order: sortFilter,
|
||||
relations: ['media', 'modifiedBy'],
|
||||
where: { status: statusFilter },
|
||||
take: Number(req.query.take) ?? 20,
|
||||
skip: Number(req.query.skip) ?? 0,
|
||||
skip,
|
||||
})
|
||||
: await requestRepository.find({
|
||||
: await requestRepository.findAndCount({
|
||||
where: { requestedBy: { id: req.user?.id }, status: statusFilter },
|
||||
relations: ['media', 'modifiedBy'],
|
||||
order: sortFilter,
|
||||
take: Number(req.query.limit) ?? 20,
|
||||
skip: Number(req.query.skip) ?? 0,
|
||||
skip,
|
||||
});
|
||||
|
||||
return res.status(200).json(requests);
|
||||
return res.status(200).json({
|
||||
pageInfo: {
|
||||
pages: Math.ceil(requestCount / pageSize),
|
||||
pageSize,
|
||||
results: requestCount,
|
||||
page: Math.ceil(skip / pageSize) + 1,
|
||||
},
|
||||
results: requests,
|
||||
} as RequestResultsResponse);
|
||||
} catch (e) {
|
||||
next({ status: 500, message: e.message });
|
||||
}
|
||||
|
@@ -8,17 +8,20 @@ import RottenTomatoes from '../api/rottentomatoes';
|
||||
|
||||
const tvRoutes = Router();
|
||||
|
||||
tvRoutes.get('/:id', async (req, res) => {
|
||||
tvRoutes.get('/:id', async (req, res, next) => {
|
||||
const tmdb = new TheMovieDb();
|
||||
try {
|
||||
const tv = await tmdb.getTvShow({
|
||||
tvId: Number(req.params.id),
|
||||
language: req.query.language as string,
|
||||
});
|
||||
|
||||
const tv = await tmdb.getTvShow({
|
||||
tvId: Number(req.params.id),
|
||||
language: req.query.language as string,
|
||||
});
|
||||
const media = await Media.getMedia(tv.id);
|
||||
|
||||
const media = await Media.getMedia(tv.id);
|
||||
|
||||
return res.status(200).json(mapTvDetails(tv, media));
|
||||
return res.status(200).json(mapTvDetails(tv, media));
|
||||
} catch (e) {
|
||||
return next({ status: 404, message: 'TV Show does not exist' });
|
||||
}
|
||||
});
|
||||
|
||||
tvRoutes.get('/:id/season/:seasonNumber', async (req, res) => {
|
||||
|
@@ -8,7 +8,7 @@ const router = Router();
|
||||
router.get('/', async (req, res) => {
|
||||
const userRepository = getRepository(User);
|
||||
|
||||
const users = await userRepository.find({ relations: ['requests'] });
|
||||
const users = await userRepository.find();
|
||||
|
||||
return res.status(200).json(User.filterMany(users));
|
||||
});
|
||||
|
Reference in New Issue
Block a user