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

Fix usages of item in location state

This commit is contained in:
Bill Thornton 2024-04-30 15:59:48 -04:00
parent 5dfefb0518
commit 23c15f8259
6 changed files with 144 additions and 92 deletions

View file

@ -6,7 +6,7 @@ import React, { type FC, useCallback } from 'react';
import Box from '@mui/material/Box';
import classNames from 'classnames';
import { useLocalStorage } from 'hooks/useLocalStorage';
import { useGetItem, useGetItemsViewByType } from 'hooks/useFetchItems';
import { useGetItemsViewByType } from 'hooks/useFetchItems';
import { getDefaultLibraryViewSettings, getSettingsKey } from 'utils/items';
import { CardShape } from 'utils/card';
import Loading from 'components/loading/LoadingComponent';
@ -28,6 +28,7 @@ import { LibraryTab } from 'types/libraryTab';
import { type LibraryViewSettings, type ParentId, ViewMode } from 'types/library';
import type { CardOptions } from 'types/cardOptions';
import type { ListOptions } from 'types/listOptions';
import { useItem } from 'hooks/useItem';
interface ItemsViewProps {
viewType: LibraryTab;
@ -79,7 +80,7 @@ const ItemsView: FC<ItemsViewProps> = ({
itemType,
libraryViewSettings
);
const { data: item } = useGetItem(parentId);
const { data: item } = useItem(parentId || undefined);
const getListOptions = useCallback(() => {
const listOptions: ListOptions = {

View file

@ -1,38 +1,41 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import ServerConnections from 'components/ServerConnections';
import { getItemQuery } from 'hooks/useItem';
import { toApi } from 'utils/jellyfin-apiclient/compat';
import { queryClient } from 'utils/query/queryClient';
import { playbackManager } from './playbackmanager';
interface PlaybackInfo {
item: BaseItemDto;
context?: string;
}
async function mirrorIfEnabled(serverId: string, itemId: string) {
if (playbackManager.enableDisplayMirroring()) {
const playerInfo = playbackManager.getPlayerInfo();
function mirrorItem(info: PlaybackInfo, player?: unknown) {
const { item } = info;
if (playerInfo && !playerInfo.isLocalPlayer && playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
const apiClient = ServerConnections.getApiClient(serverId);
const api = toApi(apiClient);
const userId = apiClient.getCurrentUserId();
try {
const item = await queryClient.fetchQuery(getItemQuery(
api,
userId,
itemId));
playbackManager.displayContent({
ItemName: item.Name,
ItemId: item.Id,
ItemType: item.Type,
Context: info.context
}, player);
}
function mirrorIfEnabled(info: PlaybackInfo) {
if (info && playbackManager.enableDisplayMirroring()) {
const playerInfo = playbackManager.getPlayerInfo();
if (playerInfo && !playerInfo.isLocalPlayer && playerInfo.supportedCommands.indexOf('DisplayContent') !== -1) {
mirrorItem(info, playbackManager.getCurrentPlayer());
ItemType: item.Type
}, playbackManager.getCurrentPlayer());
} catch (err) {
console.error('[DisplayMirrorManager] failed to mirror item', err);
}
}
}
}
document.addEventListener('viewshow', e => {
const state = e.detail.state || {};
const { item } = state;
if (e.detail?.params?.id && e.detail?.params?.serverId) {
const { serverId, id } = e.detail.params;
if (item?.ServerId) {
mirrorIfEnabled({ item });
void mirrorIfEnabled(serverId, id);
}
});

View file

@ -1,3 +1,4 @@
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import { Action, createHashHistory } from 'history';
import { appHost } from '../apphost';
@ -9,8 +10,11 @@ import loading from '../loading/loading';
import viewManager from '../viewManager/viewManager';
import ServerConnections from '../ServerConnections';
import alert from '../alert';
import { ConnectionState } from '../../utils/jellyfin-apiclient/ConnectionState.ts';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import { queryClient } from 'utils/query/queryClient';
import { getItemQuery } from 'hooks/useItem';
import { toApi } from 'utils/jellyfin-apiclient/compat';
import { ConnectionState } from 'utils/jellyfin-apiclient/ConnectionState.ts';
export const history = createHashHistory();
@ -183,10 +187,18 @@ class AppRouter {
showItem(item, serverId, options) {
// TODO: Refactor this so it only gets items, not strings.
if (typeof (item) === 'string') {
if (typeof item === 'string') {
const apiClient = serverId ? ServerConnections.getApiClient(serverId) : ServerConnections.currentApiClient();
apiClient.getItem(apiClient.getCurrentUserId(), item).then((itemObject) => {
const api = toApi(apiClient);
const userId = apiClient.getCurrentUserId();
queryClient
.fetchQuery(getItemQuery(api, userId, item))
.then(itemObject => {
this.showItem(itemObject, options);
})
.catch(err => {
console.error('[AppRouter] Failed to fetch item', err);
});
} else {
if (arguments.length === 2) {
@ -194,7 +206,7 @@ class AppRouter {
}
const url = this.getRouteUrl(item, options);
this.show(url, { item });
this.show(url);
}
}

View file

@ -1,6 +1,14 @@
import { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api';
import { getItemQuery } from 'hooks/useItem';
import { currentSettings as userSettings } from 'scripts/settings/userSettings';
import { ItemKind } from 'types/base/models/item-kind';
import Events from 'utils/events.ts';
import { toApi } from 'utils/jellyfin-apiclient/compat';
import { queryClient } from 'utils/query/queryClient';
import { playbackManager } from './playback/playbackmanager';
import * as userSettings from '../scripts/settings/userSettings';
import Events from '../utils/events.ts';
import ServerConnections from './ServerConnections';
let currentOwnerId;
@ -50,16 +58,34 @@ function stopIfPlaying() {
}
function enabled(mediaType) {
if (mediaType === 'Video') {
if (mediaType === MediaType.Video) {
return userSettings.enableThemeVideos();
}
return userSettings.enableThemeSongs();
}
const excludeTypes = ['CollectionFolder', 'UserView', 'Program', 'SeriesTimer', 'Person', 'TvChannel', 'Channel'];
const excludeTypes = [
ItemKind.CollectionFolder,
ItemKind.UserView,
ItemKind.Person,
ItemKind.Program,
ItemKind.TvChannel,
ItemKind.Channel,
ItemKind.SeriesTimer
];
async function loadThemeMedia(serverId, itemId) {
const apiClient = ServerConnections.getApiClient(serverId);
const api = toApi(apiClient);
const userId = apiClient.getCurrentUserId();
try {
const item = await queryClient.fetchQuery(getItemQuery(
api,
userId,
itemId));
function loadThemeMedia(item) {
if (item.CollectionType) {
stopIfPlaying();
return;
@ -70,24 +96,23 @@ function loadThemeMedia(item) {
return;
}
const apiClient = ServerConnections.getApiClient(item.ServerId);
apiClient.getThemeMedia(apiClient.getCurrentUserId(), item.Id, true).then(function (themeMediaResult) {
const result = userSettings.enableThemeVideos() && themeMediaResult.ThemeVideosResult.Items.length ? themeMediaResult.ThemeVideosResult : themeMediaResult.ThemeSongsResult;
const { data: themeMedia } = await getLibraryApi(api)
.getThemeMedia({ userId, itemId: item.Id, inheritFromParent: true });
const ownerId = result.OwnerId;
const result = userSettings.enableThemeVideos() && themeMedia.ThemeVideosResult?.Items?.length ? themeMedia.ThemeVideosResult : themeMedia.ThemeSongsResult;
if (ownerId !== currentOwnerId) {
playThemeMedia(result.Items, ownerId);
if (result.OwnerId !== currentOwnerId) {
playThemeMedia(result.Items, result.OwnerId);
}
} catch (err) {
console.error('[ThemeMediaPlayer] failed to load theme media', err);
}
});
}
document.addEventListener('viewshow', function (e) {
const state = e.detail.state || {};
const item = state.item;
if (item?.ServerId) {
loadThemeMedia(item);
document.addEventListener('viewshow', e => {
if (e.detail?.params?.id && e.detail?.params?.serverId) {
const { serverId, id } = e.detail.params;
void loadThemeMedia(serverId, id);
return;
}
@ -100,7 +125,7 @@ document.addEventListener('viewshow', function (e) {
}
}, true);
Events.on(playbackManager, 'playbackstart', function (e, player) {
Events.on(playbackManager, 'playbackstart', (_e, player) => {
const item = playbackManager.currentItem(player);
// User played something manually
if (currentThemeIds.indexOf(item.Id) == -1) {

View file

@ -28,36 +28,6 @@ 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,

41
src/hooks/useItem.ts Normal file
View file

@ -0,0 +1,41 @@
import type { Api } from '@jellyfin/sdk/lib/api';
import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api/user-library-api';
import { useQuery } from '@tanstack/react-query';
import type { AxiosRequestConfig } from 'axios';
import { queryOptions } from 'utils/query/queryOptions';
import { useApi } from './useApi';
const fetchItem = async (
api?: Api,
userId?: string,
itemId?: string,
options?: AxiosRequestConfig
) => {
if (!api) throw new Error('No API instance available');
if (!itemId) throw new Error('No item ID provided');
const response = await getUserLibraryApi(api)
.getItem({ userId, itemId }, options);
return response.data;
};
export const getItemQuery = (
api?: Api,
userId?: string,
itemId?: string
) => queryOptions({
queryKey: [ 'User', userId, 'Items', itemId ],
queryFn: ({ signal }) => fetchItem(api, userId, itemId, { signal }),
staleTime: 1000, // 1 second
enabled: !!api && !!userId && !!itemId
});
export const useItem = (
itemId?: string
) => {
const apiContext = useApi();
const { api, user } = apiContext;
return useQuery(getItemQuery(api, user?.Id, itemId));
};