930 lines
31 KiB
TypeScript
930 lines
31 KiB
TypeScript
import { AxiosRequestConfig } from 'axios';
|
|
import type { BaseItemDto, ItemsApiGetItemsRequest, PlaylistsApiMoveItemRequest, TimerInfoDto } from '@jellyfin/sdk/lib/generated-client';
|
|
import type { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
|
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
|
|
import { ItemFields } from '@jellyfin/sdk/lib/generated-client/models/item-fields';
|
|
import { ItemFilter } from '@jellyfin/sdk/lib/generated-client/models/item-filter';
|
|
import { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
|
|
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
|
import { getArtistsApi } from '@jellyfin/sdk/lib/utils/api/artists-api';
|
|
import { getFilterApi } from '@jellyfin/sdk/lib/utils/api/filter-api';
|
|
import { getGenresApi } from '@jellyfin/sdk/lib/utils/api/genres-api';
|
|
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
|
|
import { getMoviesApi } from '@jellyfin/sdk/lib/utils/api/movies-api';
|
|
import { getStudiosApi } from '@jellyfin/sdk/lib/utils/api/studios-api';
|
|
import { getTvShowsApi } from '@jellyfin/sdk/lib/utils/api/tv-shows-api';
|
|
import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api/user-library-api';
|
|
import { getPlaylistsApi } from '@jellyfin/sdk/lib/utils/api/playlists-api';
|
|
import { getLiveTvApi } from '@jellyfin/sdk/lib/utils/api/live-tv-api';
|
|
import { getPlaystateApi } from '@jellyfin/sdk/lib/utils/api/playstate-api';
|
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
|
import datetime from 'scripts/datetime';
|
|
import globalize from 'scripts/globalize';
|
|
|
|
import { JellyfinApiContext, useApi } from './useApi';
|
|
import { getAlphaPickerQuery, getFieldsQuery, getFiltersQuery, getLimitQuery } from 'utils/items';
|
|
import { getProgramSections, getSuggestionSections } from 'utils/sections';
|
|
import { LibraryViewSettings, ParentId } from 'types/library';
|
|
import { LibraryTab } from 'types/libraryTab';
|
|
import { Section, SectionApiMethod, SectionType } from 'types/sections';
|
|
|
|
const fetchGetItem = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id && parentId) {
|
|
const response = await getUserLibraryApi(api).getItem(
|
|
{
|
|
userId: user.Id,
|
|
itemId: parentId
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const useGetItem = (parentId: ParentId) => {
|
|
const currentApi = useApi();
|
|
const isLivetv = parentId === 'livetv';
|
|
return useQuery({
|
|
queryKey: ['Item', parentId],
|
|
queryFn: ({ signal }) => fetchGetItem(currentApi, parentId, { signal }),
|
|
enabled: !!parentId && !isLivetv
|
|
});
|
|
};
|
|
|
|
const fetchGetItems = async (
|
|
currentApi: JellyfinApiContext,
|
|
parametersOptions: ItemsApiGetItemsRequest,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getItemsApi(api).getItems(
|
|
{
|
|
userId: user.Id,
|
|
...parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const useGetItems = (parametersOptions: ItemsApiGetItemsRequest) => {
|
|
const currentApi = useApi();
|
|
return useQuery({
|
|
queryKey: [
|
|
'Items',
|
|
{
|
|
...parametersOptions
|
|
}
|
|
],
|
|
queryFn: ({ signal }) =>
|
|
fetchGetItems(currentApi, parametersOptions, { signal }),
|
|
cacheTime: parametersOptions.sortBy?.includes(ItemSortBy.Random) ? 0 : undefined
|
|
});
|
|
};
|
|
|
|
const fetchGetMovieRecommendations = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getMoviesApi(api).getMovieRecommendations(
|
|
{
|
|
userId: user.Id,
|
|
fields: [
|
|
ItemFields.PrimaryImageAspectRatio,
|
|
ItemFields.MediaSourceCount
|
|
],
|
|
parentId: parentId ?? undefined,
|
|
categoryLimit: 6,
|
|
itemLimit: 20
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const useGetMovieRecommendations = (isMovieRecommendationEnabled: boolean, parentId: ParentId) => {
|
|
const currentApi = useApi();
|
|
return useQuery({
|
|
queryKey: ['MovieRecommendations', isMovieRecommendationEnabled, parentId],
|
|
queryFn: ({ signal }) =>
|
|
isMovieRecommendationEnabled ? fetchGetMovieRecommendations(currentApi, parentId, { signal }) : []
|
|
});
|
|
};
|
|
|
|
const fetchGetGenres = async (
|
|
currentApi: JellyfinApiContext,
|
|
itemType: BaseItemKind[],
|
|
parentId: ParentId,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getGenresApi(api).getGenres(
|
|
{
|
|
userId: user.Id,
|
|
sortBy: [ItemSortBy.SortName],
|
|
sortOrder: [SortOrder.Ascending],
|
|
includeItemTypes: itemType,
|
|
enableTotalRecordCount: false,
|
|
parentId: parentId ?? undefined
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const useGetGenres = (itemType: BaseItemKind[], parentId: ParentId) => {
|
|
const currentApi = useApi();
|
|
return useQuery({
|
|
queryKey: ['Genres', parentId],
|
|
queryFn: ({ signal }) =>
|
|
fetchGetGenres(currentApi, itemType, parentId, { signal }),
|
|
enabled: !!parentId
|
|
});
|
|
};
|
|
|
|
const fetchGetStudios = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
itemType: BaseItemKind[],
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getStudiosApi(api).getStudios(
|
|
{
|
|
userId: user.Id,
|
|
includeItemTypes: itemType,
|
|
fields: [
|
|
ItemFields.DateCreated,
|
|
ItemFields.PrimaryImageAspectRatio
|
|
],
|
|
enableImageTypes: [ImageType.Thumb],
|
|
parentId: parentId ?? undefined,
|
|
enableTotalRecordCount: false
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
return response.data.Items;
|
|
}
|
|
};
|
|
|
|
export const useGetStudios = (parentId: ParentId, itemType: BaseItemKind[]) => {
|
|
const currentApi = useApi();
|
|
const isLivetv = parentId === 'livetv';
|
|
return useQuery({
|
|
queryKey: ['Studios', parentId, itemType],
|
|
queryFn: ({ signal }) =>
|
|
fetchGetStudios(currentApi, parentId, itemType, { signal }),
|
|
enabled: !!parentId && !isLivetv
|
|
});
|
|
};
|
|
|
|
const fetchGetQueryFiltersLegacy = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
itemType: BaseItemKind[],
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getFilterApi(api).getQueryFiltersLegacy(
|
|
{
|
|
userId: user.Id,
|
|
parentId: parentId ?? undefined,
|
|
includeItemTypes: itemType
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const useGetQueryFiltersLegacy = (
|
|
parentId: ParentId,
|
|
itemType: BaseItemKind[]
|
|
) => {
|
|
const currentApi = useApi();
|
|
const isLivetv = parentId === 'livetv';
|
|
return useQuery({
|
|
queryKey: ['QueryFiltersLegacy', parentId, itemType],
|
|
queryFn: ({ signal }) =>
|
|
fetchGetQueryFiltersLegacy(currentApi, parentId, itemType, {
|
|
signal
|
|
}),
|
|
enabled: !!parentId && !isLivetv
|
|
});
|
|
};
|
|
|
|
const fetchGetItemsViewByType = async (
|
|
currentApi: JellyfinApiContext,
|
|
viewType: LibraryTab,
|
|
parentId: ParentId,
|
|
itemType: BaseItemKind[],
|
|
libraryViewSettings: LibraryViewSettings,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
let response;
|
|
switch (viewType) {
|
|
case LibraryTab.AlbumArtists: {
|
|
response = await getArtistsApi(api).getAlbumArtists(
|
|
{
|
|
userId: user.Id,
|
|
parentId: parentId ?? undefined,
|
|
enableImageTypes: [libraryViewSettings.ImageType, ImageType.Backdrop],
|
|
...getFieldsQuery(viewType, libraryViewSettings),
|
|
...getFiltersQuery(viewType, libraryViewSettings),
|
|
...getLimitQuery(),
|
|
...getAlphaPickerQuery(libraryViewSettings),
|
|
sortBy: [libraryViewSettings.SortBy],
|
|
sortOrder: [libraryViewSettings.SortOrder],
|
|
includeItemTypes: itemType,
|
|
startIndex: libraryViewSettings.StartIndex
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
break;
|
|
}
|
|
case LibraryTab.Artists: {
|
|
response = await getArtistsApi(api).getArtists(
|
|
{
|
|
userId: user.Id,
|
|
parentId: parentId ?? undefined,
|
|
enableImageTypes: [libraryViewSettings.ImageType, ImageType.Backdrop],
|
|
...getFieldsQuery(viewType, libraryViewSettings),
|
|
...getFiltersQuery(viewType, libraryViewSettings),
|
|
...getLimitQuery(),
|
|
...getAlphaPickerQuery(libraryViewSettings),
|
|
sortBy: [libraryViewSettings.SortBy],
|
|
sortOrder: [libraryViewSettings.SortOrder],
|
|
includeItemTypes: itemType,
|
|
startIndex: libraryViewSettings.StartIndex
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
break;
|
|
}
|
|
case LibraryTab.Networks:
|
|
response = await getStudiosApi(api).getStudios(
|
|
{
|
|
userId: user.Id,
|
|
parentId: parentId ?? undefined,
|
|
...getFieldsQuery(viewType, libraryViewSettings),
|
|
includeItemTypes: itemType,
|
|
enableImageTypes: [ImageType.Thumb],
|
|
startIndex: libraryViewSettings.StartIndex
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
break;
|
|
case LibraryTab.Channels: {
|
|
response = await getLiveTvApi(api).getLiveTvChannels(
|
|
{
|
|
userId: user.Id,
|
|
fields: [ItemFields.PrimaryImageAspectRatio],
|
|
startIndex: libraryViewSettings.StartIndex,
|
|
isFavorite: libraryViewSettings.Filters?.Status?.includes(ItemFilter.IsFavorite) ?
|
|
true :
|
|
undefined,
|
|
enableImageTypes: [ImageType.Primary]
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
break;
|
|
}
|
|
case LibraryTab.SeriesTimers:
|
|
response = await getLiveTvApi(api).getSeriesTimers(
|
|
{
|
|
sortBy: 'SortName',
|
|
sortOrder: SortOrder.Ascending
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
break;
|
|
default: {
|
|
response = await getItemsApi(api).getItems(
|
|
{
|
|
userId: user.Id,
|
|
recursive: true,
|
|
imageTypeLimit: 1,
|
|
parentId: parentId ?? undefined,
|
|
enableImageTypes: [libraryViewSettings.ImageType, ImageType.Backdrop],
|
|
...getFieldsQuery(viewType, libraryViewSettings),
|
|
...getFiltersQuery(viewType, libraryViewSettings),
|
|
...getLimitQuery(),
|
|
...getAlphaPickerQuery(libraryViewSettings),
|
|
isFavorite: viewType === LibraryTab.Favorites ? true : undefined,
|
|
sortBy: [libraryViewSettings.SortBy],
|
|
sortOrder: [libraryViewSettings.SortOrder],
|
|
includeItemTypes: itemType,
|
|
startIndex: libraryViewSettings.StartIndex
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const useGetItemsViewByType = (
|
|
viewType: LibraryTab,
|
|
parentId: ParentId,
|
|
itemType: BaseItemKind[],
|
|
libraryViewSettings: LibraryViewSettings
|
|
) => {
|
|
const currentApi = useApi();
|
|
return useQuery({
|
|
queryKey: [
|
|
'ItemsViewByType',
|
|
viewType,
|
|
parentId,
|
|
itemType,
|
|
libraryViewSettings
|
|
],
|
|
queryFn: ({ signal }) =>
|
|
fetchGetItemsViewByType(
|
|
currentApi,
|
|
viewType,
|
|
parentId,
|
|
itemType,
|
|
libraryViewSettings,
|
|
{ signal }
|
|
),
|
|
refetchOnWindowFocus: false,
|
|
keepPreviousData : true,
|
|
enabled:
|
|
[
|
|
LibraryTab.Movies,
|
|
LibraryTab.Favorites,
|
|
LibraryTab.Collections,
|
|
LibraryTab.Trailers,
|
|
LibraryTab.Series,
|
|
LibraryTab.Episodes,
|
|
LibraryTab.Networks,
|
|
LibraryTab.Albums,
|
|
LibraryTab.AlbumArtists,
|
|
LibraryTab.Artists,
|
|
LibraryTab.Playlists,
|
|
LibraryTab.Songs,
|
|
LibraryTab.Books,
|
|
LibraryTab.Photos,
|
|
LibraryTab.Videos,
|
|
LibraryTab.Channels,
|
|
LibraryTab.SeriesTimers
|
|
].includes(viewType)
|
|
});
|
|
};
|
|
|
|
const fetchPlaylistsMoveItem = async (
|
|
currentApi: JellyfinApiContext,
|
|
requestParameters: PlaylistsApiMoveItemRequest
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getPlaylistsApi(api).moveItem({
|
|
...requestParameters
|
|
});
|
|
return response.data;
|
|
}
|
|
};
|
|
|
|
export const usePlaylistsMoveItemMutation = () => {
|
|
const currentApi = useApi();
|
|
return useMutation({
|
|
mutationFn: (requestParameters: PlaylistsApiMoveItemRequest) =>
|
|
fetchPlaylistsMoveItem(currentApi, requestParameters )
|
|
});
|
|
};
|
|
|
|
type GroupsUpcomingEpisodes = {
|
|
name: string;
|
|
items: BaseItemDto[];
|
|
};
|
|
|
|
function groupsUpcomingEpisodes(items: BaseItemDto[]) {
|
|
const groups: GroupsUpcomingEpisodes[] = [];
|
|
let currentGroupName = '';
|
|
let currentGroup: BaseItemDto[] = [];
|
|
|
|
for (const item of items) {
|
|
let dateText = '';
|
|
|
|
if (item.PremiereDate) {
|
|
try {
|
|
const premiereDate = datetime.parseISO8601Date(
|
|
item.PremiereDate,
|
|
true
|
|
);
|
|
dateText = datetime.isRelativeDay(premiereDate, -1) ?
|
|
globalize.translate('Yesterday') :
|
|
datetime.toLocaleDateString(premiereDate, {
|
|
weekday: 'long',
|
|
month: 'short',
|
|
day: 'numeric'
|
|
});
|
|
} catch (err) {
|
|
console.error('error parsing timestamp for upcoming tv shows');
|
|
}
|
|
}
|
|
|
|
if (dateText != currentGroupName) {
|
|
if (currentGroup.length) {
|
|
groups.push({
|
|
name: currentGroupName,
|
|
items: currentGroup
|
|
});
|
|
}
|
|
|
|
currentGroupName = dateText;
|
|
currentGroup = [item];
|
|
} else {
|
|
currentGroup.push(item);
|
|
}
|
|
}
|
|
return groups;
|
|
}
|
|
|
|
const fetchGetGroupsUpcomingEpisodes = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
const response = await getTvShowsApi(api).getUpcomingEpisodes(
|
|
{
|
|
userId: user.Id,
|
|
limit: 25,
|
|
fields: [ItemFields.AirTime],
|
|
parentId: parentId ?? undefined,
|
|
imageTypeLimit: 1,
|
|
enableImageTypes: [
|
|
ImageType.Primary,
|
|
ImageType.Backdrop,
|
|
ImageType.Thumb
|
|
]
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
const items = response.data.Items ?? [];
|
|
|
|
return groupsUpcomingEpisodes(items);
|
|
}
|
|
};
|
|
|
|
export const useGetGroupsUpcomingEpisodes = (parentId: ParentId) => {
|
|
const currentApi = useApi();
|
|
return useQuery({
|
|
queryKey: ['GroupsUpcomingEpisodes', parentId],
|
|
queryFn: ({ signal }) =>
|
|
fetchGetGroupsUpcomingEpisodes(currentApi, parentId, { signal }),
|
|
enabled: !!parentId
|
|
});
|
|
};
|
|
|
|
interface ToggleFavoriteMutationProp {
|
|
itemId: string;
|
|
favoriteState: boolean
|
|
}
|
|
|
|
const fetchUpdateFavoriteStatus = async (
|
|
currentApi: JellyfinApiContext,
|
|
itemId: string,
|
|
favoriteState: boolean
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
if (favoriteState) {
|
|
const response = await getUserLibraryApi(api).unmarkFavoriteItem({
|
|
userId: user.Id,
|
|
itemId: itemId
|
|
});
|
|
return response.data.IsFavorite;
|
|
} else {
|
|
const response = await getUserLibraryApi(api).markFavoriteItem({
|
|
userId: user.Id,
|
|
itemId: itemId
|
|
});
|
|
return response.data.IsFavorite;
|
|
}
|
|
}
|
|
};
|
|
|
|
export const useToggleFavoriteMutation = () => {
|
|
const currentApi = useApi();
|
|
return useMutation({
|
|
mutationFn: ({ itemId, favoriteState }: ToggleFavoriteMutationProp) =>
|
|
fetchUpdateFavoriteStatus(currentApi, itemId, favoriteState )
|
|
});
|
|
};
|
|
|
|
interface TogglePlayedMutationProp {
|
|
itemId: string;
|
|
playedState: boolean
|
|
}
|
|
|
|
const fetchUpdatePlayedState = async (
|
|
currentApi: JellyfinApiContext,
|
|
itemId: string,
|
|
playedState: boolean
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
if (playedState) {
|
|
const response = await getPlaystateApi(api).markUnplayedItem({
|
|
userId: user.Id,
|
|
itemId: itemId
|
|
});
|
|
return response.data.Played;
|
|
} else {
|
|
const response = await getPlaystateApi(api).markPlayedItem({
|
|
userId: user.Id,
|
|
itemId: itemId
|
|
});
|
|
return response.data.Played;
|
|
}
|
|
}
|
|
};
|
|
|
|
export const useTogglePlayedMutation = () => {
|
|
const currentApi = useApi();
|
|
return useMutation({
|
|
mutationFn: ({ itemId, playedState }: TogglePlayedMutationProp) =>
|
|
fetchUpdatePlayedState(currentApi, itemId, playedState )
|
|
});
|
|
};
|
|
|
|
export type GroupsTimers = {
|
|
name: string;
|
|
timerInfo: TimerInfoDto[];
|
|
};
|
|
|
|
function groupsTimers(timers: TimerInfoDto[], indexByDate?: boolean) {
|
|
const items = timers.map(function (t) {
|
|
t.Type = 'Timer';
|
|
return t;
|
|
});
|
|
const groups: GroupsTimers[] = [];
|
|
let currentGroupName = '';
|
|
let currentGroup: TimerInfoDto[] = [];
|
|
|
|
for (const item of items) {
|
|
let dateText = '';
|
|
|
|
if (indexByDate !== false && item.StartDate) {
|
|
try {
|
|
const premiereDate = datetime.parseISO8601Date(item.StartDate, true);
|
|
dateText = datetime.toLocaleDateString(premiereDate, {
|
|
weekday: 'long',
|
|
month: 'short',
|
|
day: 'numeric'
|
|
});
|
|
} catch (err) {
|
|
console.error('error parsing premiereDate:' + item.StartDate + '; error: ' + err);
|
|
}
|
|
}
|
|
|
|
if (dateText != currentGroupName) {
|
|
if (currentGroup.length) {
|
|
groups.push({
|
|
name: currentGroupName,
|
|
timerInfo: currentGroup
|
|
});
|
|
}
|
|
|
|
currentGroupName = dateText;
|
|
currentGroup = [item];
|
|
} else {
|
|
currentGroup.push(item);
|
|
}
|
|
}
|
|
|
|
if (currentGroup.length) {
|
|
groups.push({
|
|
name: currentGroupName,
|
|
timerInfo: currentGroup
|
|
});
|
|
}
|
|
return groups;
|
|
}
|
|
|
|
const fetchGetTimers = async (
|
|
currentApi: JellyfinApiContext,
|
|
indexByDate?: boolean,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api } = currentApi;
|
|
if (api) {
|
|
const response = await getLiveTvApi(api).getTimers(
|
|
{
|
|
isActive: false,
|
|
isScheduled: true
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
);
|
|
|
|
const timers = response.data.Items ?? [];
|
|
|
|
return groupsTimers(timers, indexByDate);
|
|
}
|
|
};
|
|
|
|
export const useGetTimers = (isUpcomingRecordingsEnabled: boolean, indexByDate?: boolean) => {
|
|
const currentApi = useApi();
|
|
return useQuery({
|
|
queryKey: ['Timers', isUpcomingRecordingsEnabled, indexByDate],
|
|
queryFn: ({ signal }) =>
|
|
isUpcomingRecordingsEnabled ? fetchGetTimers(currentApi, indexByDate, { signal }) : []
|
|
});
|
|
};
|
|
|
|
const fetchGetSectionItems = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
section: Section,
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
const { api, user } = currentApi;
|
|
if (api && user?.Id) {
|
|
let response;
|
|
switch (section.apiMethod) {
|
|
case SectionApiMethod.RecommendedPrograms: {
|
|
response = (
|
|
await getLiveTvApi(api).getRecommendedPrograms(
|
|
{
|
|
userId: user.Id,
|
|
limit: 12,
|
|
imageTypeLimit: 1,
|
|
enableImageTypes: [ImageType.Primary, ImageType.Thumb, ImageType.Backdrop],
|
|
enableTotalRecordCount: false,
|
|
fields: [
|
|
ItemFields.ChannelInfo,
|
|
ItemFields.PrimaryImageAspectRatio,
|
|
ItemFields.MediaSourceCount
|
|
],
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
case SectionApiMethod.LiveTvPrograms: {
|
|
response = (
|
|
await getLiveTvApi(api).getLiveTvPrograms(
|
|
{
|
|
userId: user.Id,
|
|
limit: 12,
|
|
imageTypeLimit: 1,
|
|
enableImageTypes: [ImageType.Primary, ImageType.Thumb, ImageType.Backdrop],
|
|
enableTotalRecordCount: false,
|
|
fields: [
|
|
ItemFields.ChannelInfo,
|
|
ItemFields.PrimaryImageAspectRatio
|
|
],
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
case SectionApiMethod.Recordings: {
|
|
response = (
|
|
await getLiveTvApi(api).getRecordings(
|
|
{
|
|
userId: user.Id,
|
|
enableImageTypes: [ImageType.Primary, ImageType.Thumb, ImageType.Backdrop],
|
|
enableTotalRecordCount: false,
|
|
fields: [
|
|
ItemFields.CanDelete,
|
|
ItemFields.PrimaryImageAspectRatio
|
|
],
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
case SectionApiMethod.RecordingFolders: {
|
|
response = (
|
|
await getLiveTvApi(api).getRecordingFolders(
|
|
{
|
|
userId: user.Id
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
case SectionApiMethod.NextUp: {
|
|
response = (
|
|
await getTvShowsApi(api).getNextUp(
|
|
{
|
|
userId: user.Id,
|
|
limit: 25,
|
|
fields: [
|
|
ItemFields.PrimaryImageAspectRatio,
|
|
ItemFields.MediaSourceCount
|
|
],
|
|
parentId: parentId ?? undefined,
|
|
imageTypeLimit: 1,
|
|
enableImageTypes: [
|
|
ImageType.Primary,
|
|
ImageType.Backdrop,
|
|
ImageType.Thumb
|
|
],
|
|
enableTotalRecordCount: false,
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
case SectionApiMethod.ResumeItems: {
|
|
response = (
|
|
await getItemsApi(api).getResumeItems(
|
|
{
|
|
userId: user.Id,
|
|
parentId: parentId ?? undefined,
|
|
fields: [
|
|
ItemFields.PrimaryImageAspectRatio,
|
|
ItemFields.MediaSourceCount
|
|
],
|
|
imageTypeLimit: 1,
|
|
enableImageTypes: [ImageType.Thumb],
|
|
enableTotalRecordCount: false,
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
case SectionApiMethod.LatestMedia: {
|
|
response = (
|
|
await getUserLibraryApi(api).getLatestMedia(
|
|
{
|
|
userId: user.Id,
|
|
fields: [
|
|
ItemFields.PrimaryImageAspectRatio,
|
|
ItemFields.MediaSourceCount
|
|
],
|
|
parentId: parentId ?? undefined,
|
|
imageTypeLimit: 1,
|
|
enableImageTypes: [ImageType.Primary],
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data;
|
|
break;
|
|
}
|
|
default: {
|
|
response = (
|
|
await getItemsApi(api).getItems(
|
|
{
|
|
userId: user.Id,
|
|
parentId: parentId ?? undefined,
|
|
recursive: true,
|
|
limit: 25,
|
|
enableTotalRecordCount: false,
|
|
...section.parametersOptions
|
|
},
|
|
{
|
|
signal: options?.signal
|
|
}
|
|
)
|
|
).data.Items;
|
|
break;
|
|
}
|
|
}
|
|
return response;
|
|
}
|
|
};
|
|
|
|
type SectionWithItems = {
|
|
section: Section;
|
|
items: BaseItemDto[];
|
|
};
|
|
|
|
const getSectionsWithItems = async (
|
|
currentApi: JellyfinApiContext,
|
|
parentId: ParentId,
|
|
sections: Section[],
|
|
sectionType?: SectionType[],
|
|
options?: AxiosRequestConfig
|
|
) => {
|
|
if (sectionType) {
|
|
sections = sections.filter((section) => sectionType.includes(section.type));
|
|
}
|
|
|
|
const updatedSectionWithItems: SectionWithItems[] = [];
|
|
|
|
for (const section of sections) {
|
|
try {
|
|
const items = await fetchGetSectionItems(
|
|
currentApi, parentId, section, options
|
|
);
|
|
|
|
if (items && items.length > 0) {
|
|
updatedSectionWithItems.push({
|
|
section,
|
|
items
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error occurred for section ${section.type}: ${error}`);
|
|
}
|
|
}
|
|
|
|
return updatedSectionWithItems;
|
|
};
|
|
|
|
export const useGetSuggestionSectionsWithItems = (
|
|
parentId: ParentId,
|
|
suggestionSectionType: SectionType[]
|
|
) => {
|
|
const currentApi = useApi();
|
|
const sections = getSuggestionSections();
|
|
return useQuery({
|
|
queryKey: ['SuggestionSectionWithItems', suggestionSectionType],
|
|
queryFn: ({ signal }) =>
|
|
getSectionsWithItems(currentApi, parentId, sections, suggestionSectionType, { signal }),
|
|
enabled: !!parentId
|
|
});
|
|
};
|
|
|
|
export const useGetProgramsSectionsWithItems = (
|
|
parentId: ParentId,
|
|
programSectionType: SectionType[]
|
|
) => {
|
|
const currentApi = useApi();
|
|
const sections = getProgramSections();
|
|
return useQuery({
|
|
queryKey: ['ProgramSectionWithItems', programSectionType],
|
|
queryFn: ({ signal }) =>
|
|
getSectionsWithItems(currentApi, parentId, sections, programSectionType, { signal })
|
|
});
|
|
};
|
|
|