mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(search): filter search results by year (#2460)
* feat(search): filter search results by year * fix: typo in endpoint, blame it on new brand of coffee * feat(search): suggested changes
This commit is contained in:

committed by
GitHub

parent
30644f65ea
commit
72c825d2a5
@@ -28,6 +28,10 @@ interface SearchOptions {
|
|||||||
language?: string;
|
language?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SingleSearchOptions extends SearchOptions {
|
||||||
|
year?: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface DiscoverMovieOptions {
|
interface DiscoverMovieOptions {
|
||||||
page?: number;
|
page?: number;
|
||||||
includeAdult?: boolean;
|
includeAdult?: boolean;
|
||||||
@@ -116,6 +120,58 @@ class TheMovieDb extends ExternalAPI {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public searchMovies = async ({
|
||||||
|
query,
|
||||||
|
page = 1,
|
||||||
|
includeAdult = false,
|
||||||
|
language = 'en',
|
||||||
|
year,
|
||||||
|
}: SingleSearchOptions): Promise<TmdbSearchMovieResponse> => {
|
||||||
|
try {
|
||||||
|
const data = await this.get<TmdbSearchMovieResponse>('/search/movie', {
|
||||||
|
params: { query, page, include_adult: includeAdult, language, year },
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
page: 1,
|
||||||
|
results: [],
|
||||||
|
total_pages: 1,
|
||||||
|
total_results: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public searchTvShows = async ({
|
||||||
|
query,
|
||||||
|
page = 1,
|
||||||
|
includeAdult = false,
|
||||||
|
language = 'en',
|
||||||
|
year,
|
||||||
|
}: SingleSearchOptions): Promise<TmdbSearchTvResponse> => {
|
||||||
|
try {
|
||||||
|
const data = await this.get<TmdbSearchTvResponse>('/search/tv', {
|
||||||
|
params: {
|
||||||
|
query,
|
||||||
|
page,
|
||||||
|
include_adult: includeAdult,
|
||||||
|
language,
|
||||||
|
first_air_date_year: year,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
page: 1,
|
||||||
|
results: [],
|
||||||
|
total_pages: 1,
|
||||||
|
total_results: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public getPerson = async ({
|
public getPerson = async ({
|
||||||
personId,
|
personId,
|
||||||
language = 'en',
|
language = 'en',
|
||||||
|
@@ -4,7 +4,9 @@ import {
|
|||||||
TmdbMovieResult,
|
TmdbMovieResult,
|
||||||
TmdbPersonDetails,
|
TmdbPersonDetails,
|
||||||
TmdbPersonResult,
|
TmdbPersonResult,
|
||||||
|
TmdbSearchMovieResponse,
|
||||||
TmdbSearchMultiResponse,
|
TmdbSearchMultiResponse,
|
||||||
|
TmdbSearchTvResponse,
|
||||||
TmdbTvDetails,
|
TmdbTvDetails,
|
||||||
TmdbTvResult,
|
TmdbTvResult,
|
||||||
} from '../api/themoviedb/interfaces';
|
} from '../api/themoviedb/interfaces';
|
||||||
@@ -13,14 +15,19 @@ import {
|
|||||||
mapPersonDetailsToResult,
|
mapPersonDetailsToResult,
|
||||||
mapTvDetailsToResult,
|
mapTvDetailsToResult,
|
||||||
} from '../models/Search';
|
} from '../models/Search';
|
||||||
import { isMovieDetails, isTvDetails } from '../utils/typeHelpers';
|
import { isMovie, isMovieDetails, isTvDetails } from '../utils/typeHelpers';
|
||||||
|
|
||||||
type SearchProviderId = 'TMDb' | 'IMDb' | 'TVDB';
|
|
||||||
|
|
||||||
interface SearchProvider {
|
interface SearchProvider {
|
||||||
id: SearchProviderId;
|
|
||||||
pattern: RegExp;
|
pattern: RegExp;
|
||||||
search: (id: string, language?: string) => Promise<TmdbSearchMultiResponse>;
|
search: ({
|
||||||
|
id,
|
||||||
|
language,
|
||||||
|
query,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
language?: string;
|
||||||
|
query?: string;
|
||||||
|
}) => Promise<TmdbSearchMultiResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchProviders: SearchProvider[] = [];
|
const searchProviders: SearchProvider[] = [];
|
||||||
@@ -32,12 +39,8 @@ export const findSearchProvider = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
searchProviders.push({
|
searchProviders.push({
|
||||||
id: 'TMDb',
|
|
||||||
pattern: new RegExp(/(?<=tmdb:)\d+/),
|
pattern: new RegExp(/(?<=tmdb:)\d+/),
|
||||||
search: async (
|
search: async ({ id, language }) => {
|
||||||
id: string,
|
|
||||||
language?: string
|
|
||||||
): Promise<TmdbSearchMultiResponse> => {
|
|
||||||
const tmdb = new TheMovieDb();
|
const tmdb = new TheMovieDb();
|
||||||
|
|
||||||
const moviePromise = tmdb.getMovie({ movieId: parseInt(id), language });
|
const moviePromise = tmdb.getMovie({ movieId: parseInt(id), language });
|
||||||
@@ -85,12 +88,8 @@ searchProviders.push({
|
|||||||
});
|
});
|
||||||
|
|
||||||
searchProviders.push({
|
searchProviders.push({
|
||||||
id: 'IMDb',
|
|
||||||
pattern: new RegExp(/(?<=imdb:)(tt|nm)\d+/),
|
pattern: new RegExp(/(?<=imdb:)(tt|nm)\d+/),
|
||||||
search: async (
|
search: async ({ id, language }) => {
|
||||||
id: string,
|
|
||||||
language?: string
|
|
||||||
): Promise<TmdbSearchMultiResponse> => {
|
|
||||||
const tmdb = new TheMovieDb();
|
const tmdb = new TheMovieDb();
|
||||||
|
|
||||||
const responses = await tmdb.getByExternalId({
|
const responses = await tmdb.getByExternalId({
|
||||||
@@ -127,12 +126,8 @@ searchProviders.push({
|
|||||||
});
|
});
|
||||||
|
|
||||||
searchProviders.push({
|
searchProviders.push({
|
||||||
id: 'TVDB',
|
|
||||||
pattern: new RegExp(/(?<=tvdb:)\d+/),
|
pattern: new RegExp(/(?<=tvdb:)\d+/),
|
||||||
search: async (
|
search: async ({ id, language }) => {
|
||||||
id: string,
|
|
||||||
language?: string
|
|
||||||
): Promise<TmdbSearchMultiResponse> => {
|
|
||||||
const tmdb = new TheMovieDb();
|
const tmdb = new TheMovieDb();
|
||||||
|
|
||||||
const responses = await tmdb.getByExternalId({
|
const responses = await tmdb.getByExternalId({
|
||||||
@@ -167,3 +162,51 @@ searchProviders.push({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
searchProviders.push({
|
||||||
|
pattern: new RegExp(/(?<=year:)\d{4}/),
|
||||||
|
search: async ({ id: year, query }) => {
|
||||||
|
const tmdb = new TheMovieDb();
|
||||||
|
|
||||||
|
const moviesPromise = tmdb.searchMovies({
|
||||||
|
query: query?.replace(new RegExp(/year:\d{4}/), '') ?? '',
|
||||||
|
year: parseInt(year),
|
||||||
|
});
|
||||||
|
const tvShowsPromise = tmdb.searchTvShows({
|
||||||
|
query: query?.replace(new RegExp(/year:\d{4}/), '') ?? '',
|
||||||
|
year: parseInt(year),
|
||||||
|
});
|
||||||
|
|
||||||
|
const responses = await Promise.allSettled([moviesPromise, tvShowsPromise]);
|
||||||
|
|
||||||
|
const successfulResponses = responses.filter(
|
||||||
|
(r) => r.status === 'fulfilled'
|
||||||
|
) as
|
||||||
|
| (
|
||||||
|
| PromiseFulfilledResult<TmdbSearchMovieResponse>
|
||||||
|
| PromiseFulfilledResult<TmdbSearchTvResponse>
|
||||||
|
)[];
|
||||||
|
|
||||||
|
const results: (TmdbMovieResult | TmdbTvResult)[] = [];
|
||||||
|
|
||||||
|
if (successfulResponses.length) {
|
||||||
|
successfulResponses.forEach((response) => {
|
||||||
|
response.value.results.forEach((result) =>
|
||||||
|
// set the media_type here since the search endpoints don't return it
|
||||||
|
results.push(
|
||||||
|
isMovie(result)
|
||||||
|
? { ...result, media_type: 'movie' }
|
||||||
|
: { ...result, media_type: 'tv' }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
page: 1,
|
||||||
|
total_pages: 1,
|
||||||
|
total_results: results.length,
|
||||||
|
results,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
@@ -18,10 +18,11 @@ searchRoutes.get('/', async (req, res, next) => {
|
|||||||
const [id] = queryString
|
const [id] = queryString
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.match(searchProvider.pattern) as RegExpMatchArray;
|
.match(searchProvider.pattern) as RegExpMatchArray;
|
||||||
results = await searchProvider.search(
|
results = await searchProvider.search({
|
||||||
id,
|
id,
|
||||||
req.locale ?? (req.query.language as string)
|
language: req.locale ?? (req.query.language as string),
|
||||||
);
|
query: queryString,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const tmdb = new TheMovieDb();
|
const tmdb = new TheMovieDb();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user