Skip to content

Commit

Permalink
feat(search): filter search results by year (#2460)
Browse files Browse the repository at this point in the history
* feat(search): filter search results by year

* fix: typo in endpoint, blame it on new brand of coffee

* feat(search): suggested changes
  • Loading branch information
danshilm committed Mar 14, 2022
1 parent 30644f6 commit 72c825d
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 23 deletions.
56 changes: 56 additions & 0 deletions server/api/themoviedb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ interface SearchOptions {
language?: string;
}

interface SingleSearchOptions extends SearchOptions {
year?: number;
}

interface DiscoverMovieOptions {
page?: number;
includeAdult?: boolean;
Expand Down Expand Up @@ -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 ({
personId,
language = 'en',
Expand Down
83 changes: 63 additions & 20 deletions server/lib/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
TmdbMovieResult,
TmdbPersonDetails,
TmdbPersonResult,
TmdbSearchMovieResponse,
TmdbSearchMultiResponse,
TmdbSearchTvResponse,
TmdbTvDetails,
TmdbTvResult,
} from '../api/themoviedb/interfaces';
Expand All @@ -13,14 +15,19 @@ import {
mapPersonDetailsToResult,
mapTvDetailsToResult,
} from '../models/Search';
import { isMovieDetails, isTvDetails } from '../utils/typeHelpers';

type SearchProviderId = 'TMDb' | 'IMDb' | 'TVDB';
import { isMovie, isMovieDetails, isTvDetails } from '../utils/typeHelpers';

interface SearchProvider {
id: SearchProviderId;
pattern: RegExp;
search: (id: string, language?: string) => Promise<TmdbSearchMultiResponse>;
search: ({
id,
language,
query,
}: {
id: string;
language?: string;
query?: string;
}) => Promise<TmdbSearchMultiResponse>;
}

const searchProviders: SearchProvider[] = [];
Expand All @@ -32,12 +39,8 @@ export const findSearchProvider = (
};

searchProviders.push({
id: 'TMDb',
pattern: new RegExp(/(?<=tmdb:)\d+/),
search: async (
id: string,
language?: string
): Promise<TmdbSearchMultiResponse> => {
search: async ({ id, language }) => {
const tmdb = new TheMovieDb();

const moviePromise = tmdb.getMovie({ movieId: parseInt(id), language });
Expand Down Expand Up @@ -85,12 +88,8 @@ searchProviders.push({
});

searchProviders.push({
id: 'IMDb',
pattern: new RegExp(/(?<=imdb:)(tt|nm)\d+/),
search: async (
id: string,
language?: string
): Promise<TmdbSearchMultiResponse> => {
search: async ({ id, language }) => {
const tmdb = new TheMovieDb();

const responses = await tmdb.getByExternalId({
Expand Down Expand Up @@ -127,12 +126,8 @@ searchProviders.push({
});

searchProviders.push({
id: 'TVDB',
pattern: new RegExp(/(?<=tvdb:)\d+/),
search: async (
id: string,
language?: string
): Promise<TmdbSearchMultiResponse> => {
search: async ({ id, language }) => {
const tmdb = new TheMovieDb();

const responses = await tmdb.getByExternalId({
Expand Down Expand Up @@ -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,
};
},
});
7 changes: 4 additions & 3 deletions server/routes/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ searchRoutes.get('/', async (req, res, next) => {
const [id] = queryString
.toLowerCase()
.match(searchProvider.pattern) as RegExpMatchArray;
results = await searchProvider.search(
results = await searchProvider.search({
id,
req.locale ?? (req.query.language as string)
);
language: req.locale ?? (req.query.language as string),
query: queryString,
});
} else {
const tmdb = new TheMovieDb();

Expand Down

0 comments on commit 72c825d

Please sign in to comment.