1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/hooks/searchHook/useSearchItems.ts

510 lines
16 KiB
TypeScript
Raw Normal View History

2024-06-11 00:23:57 +03:00
import type { AxiosRequestConfig } from 'axios';
import type { Api } from '@jellyfin/sdk';
import type {
ArtistsApiGetArtistsRequest,
BaseItemDto,
ItemsApiGetItemsRequest,
PersonsApiGetPersonsRequest
} from '@jellyfin/sdk/lib/generated-client';
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import { ItemFields } from '@jellyfin/sdk/lib/generated-client/models/item-fields';
import { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
import { getPersonsApi } from '@jellyfin/sdk/lib/utils/api/persons-api';
import { getArtistsApi } from '@jellyfin/sdk/lib/utils/api/artists-api';
import { useQuery } from '@tanstack/react-query';
import { useApi } from '../useApi';
import type { CardOptions } from 'types/cardOptions';
import { CardShape } from 'utils/card';
const Parameters_OPTIONS = {
limit: 100,
fields: [
ItemFields.PrimaryImageAspectRatio,
ItemFields.CanDelete,
ItemFields.MediaSourceCount
],
enableTotalRecordCount: false,
imageTypeLimit: 1
};
const fetchItemsByType = async (
api: Api,
userId?: string,
params?: ItemsApiGetItemsRequest,
options?: AxiosRequestConfig
) => {
const response = await getItemsApi(api).getItems(
{
...Parameters_OPTIONS,
userId: userId,
recursive: true,
...params
},
options
);
return response.data;
};
const fetchPeople = async (
api: Api,
userId: string,
params?: PersonsApiGetPersonsRequest,
options?: AxiosRequestConfig
) => {
const response = await getPersonsApi(api).getPersons(
{
...Parameters_OPTIONS,
userId: userId,
...params
},
options
);
return response.data;
};
const fetchArtists = async (
api: Api,
userId: string,
params?: ArtistsApiGetArtistsRequest,
options?: AxiosRequestConfig
) => {
const response = await getArtistsApi(api).getArtists(
{
...Parameters_OPTIONS,
userId: userId,
...params
},
options
);
return response.data;
};
const isMovies = (collectionType: string) =>
collectionType === CollectionType.Movies;
const isMusic = (collectionType: string) =>
collectionType === CollectionType.Music;
const isTVShows = (collectionType: string) =>
collectionType === CollectionType.Tvshows;
const isLivetv = (collectionType: string) =>
collectionType === CollectionType.Livetv;
const Livetv_CARD_OPTIONS = {
preferThumb: true,
inheritThumb: false,
showParentTitleOrTitle: true,
showTitle: false,
coverImage: true,
overlayMoreButton: true,
showAirTime: true,
showAirDateTime: true,
showChannelName: true
};
export interface Section {
title: string
items: BaseItemDto[];
cardOptions?: CardOptions;
}
export const useSearchItems = (
parentId?: string,
collectionType?: string,
searchTerm?: string
) => {
const { api, user } = useApi();
const userId = user?.Id;
return useQuery({
queryKey: ['SearchItems', { parentId, collectionType, searchTerm }],
queryFn: async ({ signal }) => {
if (!api) throw new Error('No API instance available');
if (!userId) throw new Error('No User ID provided');
const sections: Section[] = [];
const addSection = (
title: string,
items: BaseItemDto[] | null | undefined,
cardOptions?: CardOptions
) => {
if (items && items?.length > 0) {
sections.push({ title, items, cardOptions });
}
};
// Livetv libraries
if (collectionType && isLivetv(collectionType)) {
// Movies row
const moviesData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
isMovie: true,
searchTerm: searchTerm
},
{ signal }
);
addSection('Movies', moviesData.Items, {
...Livetv_CARD_OPTIONS,
shape: CardShape.PortraitOverflow
});
// Episodes row
const episodesData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
isMovie: false,
isSeries: true,
isSports: false,
isKids: false,
isNews: false,
searchTerm: searchTerm
},
{ signal }
);
addSection('Episodes', episodesData.Items, {
...Livetv_CARD_OPTIONS
});
// Sports row
const sportsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
isSports: true,
searchTerm: searchTerm
},
{ signal }
);
addSection('Sports', sportsData.Items, {
...Livetv_CARD_OPTIONS
});
// Kids row
const kidsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
isKids: true,
searchTerm: searchTerm
},
{ signal }
);
addSection('Kids', kidsData.Items, {
...Livetv_CARD_OPTIONS
});
// News row
const newsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
isNews: true,
searchTerm: searchTerm
},
{ signal }
);
addSection('News', newsData.Items, {
...Livetv_CARD_OPTIONS
});
// Programs row
const programsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
isMovie: false,
isSeries: false,
isSports: false,
isKids: false,
isNews: false,
searchTerm: searchTerm
},
{ signal }
);
addSection('Programs', programsData.Items, {
...Livetv_CARD_OPTIONS
});
// Channels row
const channelsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.TvChannel],
searchTerm: searchTerm
},
{ signal }
);
addSection('Channels', channelsData.Items);
}
// Movie libraries
if (!collectionType || isMovies(collectionType)) {
// Movies row
const moviesData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Movie],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Movies', moviesData.Items, {
showYear: true
});
}
// TV Show libraries
if (!collectionType || isTVShows(collectionType)) {
// Shows row
const showsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Series],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Shows', showsData.Items, {
showYear: true
});
// Episodes row
const episodesData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Episode],
parentId: parentId,
isMissing: user?.Configuration?.DisplayMissingEpisodes,
searchTerm: searchTerm
},
{ signal }
);
addSection('Episodes', episodesData.Items, {
coverImage: true,
showParentTitle: true
});
}
// People are included for Movies and TV Shows
if (
!collectionType
|| isMovies(collectionType)
|| isTVShows(collectionType)
) {
// People row
const peopleData = await fetchPeople(
api,
userId,
{
searchTerm: searchTerm
},
{ signal }
);
addSection('People', peopleData.Items, {
coverImage: true
});
}
// Music libraries
if (!collectionType || isMusic(collectionType)) {
// Playlists row
const playlistsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Playlist],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Playlists', playlistsData.Items);
// Artists row
const artistsData = await fetchArtists(
api,
userId,
{
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Artists', artistsData.Items, {
coverImage: true
});
// Albums row
const albumsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.MusicAlbum],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Albums', albumsData.Items, {
showYear: true
});
// Songs row
const songsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Audio],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Songs', songsData.Items, {
showParentTitle: true,
shape: CardShape.SquareOverflow
});
}
// Other libraries do not support in-library search currently
if (!collectionType) {
// Videos row
const videosData = await fetchItemsByType(
api,
userId,
{
mediaTypes: [MediaType.Video],
excludeItemTypes: [
BaseItemKind.Movie,
BaseItemKind.Episode,
BaseItemKind.TvChannel
],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Videos', videosData.Items, {
showParentTitle: true
});
// Programs row
const programsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.LiveTvProgram],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Programs', programsData.Items, {
...Livetv_CARD_OPTIONS
});
// Channels row
const channelsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.TvChannel],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Channels', channelsData.Items);
// Photo Albums row
const photoAlbumsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.PhotoAlbum],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('PhotoAlbums', photoAlbumsData.Items);
// Photos row
const photosData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Photo],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Photos', photosData.Items);
// Audio Books row
const audioBooksData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.AudioBook],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('AudioBooks', audioBooksData.Items);
// Books row
const booksData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.Book],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Books', booksData.Items);
// Collections row
const collectionsData = await fetchItemsByType(
api,
userId,
{
includeItemTypes: [BaseItemKind.BoxSet],
parentId: parentId,
searchTerm: searchTerm
},
{ signal }
);
addSection('Collections', collectionsData.Items);
}
return sections;
},
enabled: !!api && !!userId
});
};