Search also searches for releases and artists now

pull/3800/merge^2
Anatole Sot 3 months ago
parent ca2f346de5
commit 6bd18d91ab

@ -4416,6 +4416,8 @@ paths:
- $ref: '#/components/schemas/MovieResult'
- $ref: '#/components/schemas/TvResult'
- $ref: '#/components/schemas/PersonResult'
- $ref: '#/components/schemas/ArtistResult'
- $ref: '#/components/schemas/ReleaseResult'
/search/keyword:
get:
summary: Search for keywords

@ -1,3 +1,4 @@
import MusicBrainz from '@server/api/musicbrainz';
import TheMovieDb from '@server/api/themoviedb';
import type {
TmdbMovieDetails,
@ -10,6 +11,7 @@ import type {
TmdbTvDetails,
TmdbTvResult,
} from '@server/api/themoviedb/interfaces';
import type { MbSearchMultiResponse } from '@server/models/Search';
import {
mapMovieDetailsToResult,
mapPersonDetailsToResult,
@ -31,7 +33,7 @@ interface SearchProvider {
id: string;
language?: string;
query?: string;
}) => Promise<TmdbSearchMultiResponse>;
}) => Promise<TmdbSearchMultiResponse | MbSearchMultiResponse>;
}
const searchProviders: SearchProvider[] = [];
@ -214,3 +216,29 @@ searchProviders.push({
};
},
});
searchProviders.push({
pattern: new RegExp(
/(?<=mb:)[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/
),
search: async ({ id }) => {
const mb = new MusicBrainz();
const results = [];
try {
results.push(await mb.getArtist(id));
} catch (e) {
// ignore
}
try {
results.push(await mb.getRelease(id));
} catch (e) {
// ignore
}
return {
page: 1,
total_pages: 1,
total_results: results.length,
results,
};
},
});

@ -171,6 +171,27 @@ export type Results =
| WorkResult
| ArtistResult;
export type MbSearchMultiResponse = {
page: number;
total_pages: number;
total_results: number;
results: (mbRelease | mbArtist)[];
};
export type MixedSearchResponse = {
page: number;
total_pages: number;
total_results: number;
results: (
| mbArtist
| mbRelease
| TmdbMovieResult
| TmdbTvResult
| TmdbPersonResult
| TmdbCollectionResult
)[];
};
export const mapMovieResult = (
movieResult: TmdbMovieResult,
media?: Media
@ -390,7 +411,10 @@ export const mapSearchResults = async (
case 'work':
return mapWorkResult(result);
case 'artist':
return mapArtistResult(result);
return mapArtistResult(
result,
media?.find((req) => req.mbId === result.id)
);
default:
return result;
}

@ -4,6 +4,10 @@ import type { TmdbSearchMultiResponse } from '@server/api/themoviedb/interfaces'
import Media from '@server/entity/Media';
import { findSearchProvider } from '@server/lib/search';
import logger from '@server/logger';
import type {
MbSearchMultiResponse,
MixedSearchResponse,
} from '@server/models/Search';
import { mapSearchResults } from '@server/models/Search';
import { Router } from 'express';
@ -12,7 +16,10 @@ const searchRoutes = Router();
searchRoutes.get('/', async (req, res, next) => {
const queryString = req.query.query as string;
const searchProvider = findSearchProvider(queryString.toLowerCase());
let results: TmdbSearchMultiResponse;
let results:
| MixedSearchResponse
| TmdbSearchMultiResponse
| MbSearchMultiResponse;
try {
if (searchProvider) {
@ -32,11 +39,32 @@ searchRoutes.get('/', async (req, res, next) => {
page: Number(req.query.page),
language: (req.query.language as string) ?? req.locale,
});
const mb = new MusicBrainz();
const mbResults = await mb.searchMulti({
query: queryString,
page: Number(req.query.page),
});
const releaseResults = mbResults.releaseResults;
const artistResults = mbResults.artistResults;
results = {
...results,
results: [...results.results, ...releaseResults, ...artistResults],
};
}
const media = await Media.getRelatedMedia(
results.results.map((result) => result.id)
);
const mbIds = results.results
.filter((result) => typeof result.id === 'string')
.map((result) => result.id as string);
const tmdbIds = results.results
.filter((result) => typeof result.id === 'number')
.map((result) => result.id as number);
const media = await Media.getRelatedMedia(tmdbIds, mbIds);
return res.status(200).json({
page: results.page,

@ -37,6 +37,7 @@ type ListViewProps = {
isLoading?: boolean;
isReachingEnd?: boolean;
onScrollBottom: () => void;
force_big?: boolean;
};
const ListView = ({
@ -47,6 +48,7 @@ const ListView = ({
onScrollBottom,
isReachingEnd,
plexItems,
force_big = false,
}: ListViewProps) => {
const intl = useIntl();
useVerticalScroll(onScrollBottom, !isLoading && !isEmpty && !isReachingEnd);
@ -140,6 +142,7 @@ const ListView = ({
image={title.posterPath}
mediaType={title.mediaType}
canExpand
force_big={force_big}
/>
);
break;
@ -151,6 +154,7 @@ const ListView = ({
title={title.title}
mediaType={title.mediaType}
canExpand
force_big={force_big}
/>
);
break;

@ -4,8 +4,10 @@ import PageTitle from '@app/components/Common/PageTitle';
import useDiscover from '@app/hooks/useDiscover';
import Error from '@app/pages/_error';
import type {
ArtistResult,
MovieResult,
PersonResult,
ReleaseResult,
TvResult,
} from '@server/models/Search';
import { useRouter } from 'next/router';
@ -28,7 +30,9 @@ const Search = () => {
titles,
fetchMore,
error,
} = useDiscover<MovieResult | TvResult | PersonResult>(
} = useDiscover<
MovieResult | TvResult | PersonResult | ArtistResult | ReleaseResult
>(
`/api/v1/search`,
{
query: router.query.query,
@ -54,6 +58,7 @@ const Search = () => {
}
isReachingEnd={isReachingEnd}
onScrollBottom={fetchMore}
force_big={true}
/>
</>
);

@ -29,6 +29,7 @@ interface TitleCardProps {
canExpand?: boolean;
inProgress?: boolean;
type?: string;
force_big?: boolean;
}
const TitleCard = ({
@ -42,6 +43,7 @@ const TitleCard = ({
inProgress = false,
canExpand = false,
type,
force_big = false,
}: TitleCardProps) => {
const isTouch = useIsTouch();
const intl = useIntl();
@ -106,7 +108,11 @@ const TitleCard = ({
? 'scale-105 shadow-lg ring-gray-500'
: 'scale-100 shadow ring-gray-700'
}`}
style={tmdbOrMbId ? { paddingBottom: '150%' } : { aspectRatio: '1/1' }}
style={
tmdbOrMbId || force_big
? { paddingBottom: '150%' }
: { aspectRatio: '1/1' }
}
onMouseEnter={() => {
if (!isTouch) {
setShowDetail(true);

Loading…
Cancel
Save