mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 18:33:33 +00:00
add recently released to home page, refactor home route
This commit is contained in:
parent
7c24f7cba4
commit
1cbb3e56bc
5 changed files with 67 additions and 88 deletions
|
|
@ -411,6 +411,7 @@
|
||||||
"mostPlayed": "most played",
|
"mostPlayed": "most played",
|
||||||
"newlyAdded": "newly added releases",
|
"newlyAdded": "newly added releases",
|
||||||
"recentlyPlayed": "recently played",
|
"recentlyPlayed": "recently played",
|
||||||
|
"recentlyReleased": "recently released",
|
||||||
"title": "$t(common.home)"
|
"title": "$t(common.home)"
|
||||||
},
|
},
|
||||||
"itemDetail": {
|
"itemDetail": {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ const ALBUM_LIST_SORT_MAPPING: Record<AlbumListSort, AlbumListSortType | undefin
|
||||||
[AlbumListSort.RATING]: undefined,
|
[AlbumListSort.RATING]: undefined,
|
||||||
[AlbumListSort.RECENTLY_ADDED]: AlbumListSortType.NEWEST,
|
[AlbumListSort.RECENTLY_ADDED]: AlbumListSortType.NEWEST,
|
||||||
[AlbumListSort.RECENTLY_PLAYED]: AlbumListSortType.RECENT,
|
[AlbumListSort.RECENTLY_PLAYED]: AlbumListSortType.RECENT,
|
||||||
[AlbumListSort.RELEASE_DATE]: undefined,
|
[AlbumListSort.RELEASE_DATE]: AlbumListSortType.BY_YEAR,
|
||||||
[AlbumListSort.SONG_COUNT]: undefined,
|
[AlbumListSort.SONG_COUNT]: undefined,
|
||||||
[AlbumListSort.YEAR]: AlbumListSortType.BY_YEAR,
|
[AlbumListSort.YEAR]: AlbumListSortType.BY_YEAR,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
|
||||||
import { useMemo, useRef } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
|
||||||
import { FeatureCarousel } from '/@/renderer/components/feature-carousel/feature-carousel';
|
import { FeatureCarousel } from '/@/renderer/components/feature-carousel/feature-carousel';
|
||||||
import { MemoizedSwiperGridCarousel } from '/@/renderer/components/grid-carousel/grid-carousel';
|
import { MemoizedSwiperGridCarousel } from '/@/renderer/components/grid-carousel/grid-carousel';
|
||||||
import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area';
|
import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area';
|
||||||
|
|
@ -32,12 +30,16 @@ import {
|
||||||
} from '/@/shared/types/domain-types';
|
} from '/@/shared/types/domain-types';
|
||||||
import { Platform } from '/@/shared/types/types';
|
import { Platform } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
const BASE_QUERY_ARGS = {
|
||||||
|
limit: 15,
|
||||||
|
sortOrder: SortOrder.DESC,
|
||||||
|
startIndex: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const HomeRoute = () => {
|
const HomeRoute = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const scrollAreaRef = useRef<HTMLDivElement>(null);
|
const scrollAreaRef = useRef<HTMLDivElement>(null);
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
const itemsPerPage = 15;
|
|
||||||
const { windowBarStyle } = useWindowSettings();
|
const { windowBarStyle } = useWindowSettings();
|
||||||
const { homeFeature, homeItems } = useGeneralSettings();
|
const { homeFeature, homeItems } = useGeneralSettings();
|
||||||
|
|
||||||
|
|
@ -56,59 +58,66 @@ const HomeRoute = () => {
|
||||||
serverId: server?.id,
|
serverId: server?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isJellyfin = server?.type === ServerType.JELLYFIN;
|
||||||
|
|
||||||
const featureItemsWithImage = useMemo(() => {
|
const featureItemsWithImage = useMemo(() => {
|
||||||
return feature.data?.items?.filter((item) => item.imageUrl) ?? [];
|
return feature.data?.items?.filter((item) => item.imageUrl) ?? [];
|
||||||
}, [feature.data?.items]);
|
}, [feature.data?.items]);
|
||||||
|
|
||||||
|
const queriesEnabled = useMemo(() => {
|
||||||
|
return homeItems.reduce(
|
||||||
|
(previous: Record<HomeItem, boolean>, current) => ({
|
||||||
|
...previous,
|
||||||
|
[current.id]: !current.disabled,
|
||||||
|
}),
|
||||||
|
{} as Record<HomeItem, boolean>,
|
||||||
|
);
|
||||||
|
}, [homeItems]);
|
||||||
|
|
||||||
const random = useAlbumList({
|
const random = useAlbumList({
|
||||||
options: {
|
options: {
|
||||||
|
enabled: queriesEnabled[HomeItem.RANDOM],
|
||||||
staleTime: 1000 * 60 * 5,
|
staleTime: 1000 * 60 * 5,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
limit: itemsPerPage,
|
...BASE_QUERY_ARGS,
|
||||||
sortBy: AlbumListSort.RANDOM,
|
sortBy: AlbumListSort.RANDOM,
|
||||||
sortOrder: SortOrder.ASC,
|
|
||||||
startIndex: 0,
|
|
||||||
},
|
},
|
||||||
serverId: server?.id,
|
serverId: server?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const recentlyPlayed = useRecentlyPlayed({
|
const recentlyPlayed = useRecentlyPlayed({
|
||||||
options: {
|
options: {
|
||||||
|
enabled: queriesEnabled[HomeItem.RECENTLY_PLAYED] && !isJellyfin,
|
||||||
staleTime: 0,
|
staleTime: 0,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
limit: itemsPerPage,
|
...BASE_QUERY_ARGS,
|
||||||
sortBy: AlbumListSort.RECENTLY_PLAYED,
|
sortBy: AlbumListSort.RECENTLY_PLAYED,
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
startIndex: 0,
|
|
||||||
},
|
},
|
||||||
serverId: server?.id,
|
serverId: server?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const recentlyAdded = useAlbumList({
|
const recentlyAdded = useAlbumList({
|
||||||
options: {
|
options: {
|
||||||
|
enabled: queriesEnabled[HomeItem.RECENTLY_ADDED],
|
||||||
staleTime: 1000 * 60 * 5,
|
staleTime: 1000 * 60 * 5,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
limit: itemsPerPage,
|
...BASE_QUERY_ARGS,
|
||||||
sortBy: AlbumListSort.RECENTLY_ADDED,
|
sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
startIndex: 0,
|
|
||||||
},
|
},
|
||||||
serverId: server?.id,
|
serverId: server?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mostPlayedAlbums = useAlbumList({
|
const mostPlayedAlbums = useAlbumList({
|
||||||
options: {
|
options: {
|
||||||
enabled: server?.type === ServerType.SUBSONIC || server?.type === ServerType.NAVIDROME,
|
enabled: !isJellyfin && queriesEnabled[HomeItem.MOST_PLAYED],
|
||||||
staleTime: 1000 * 60 * 5,
|
staleTime: 1000 * 60 * 5,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
limit: itemsPerPage,
|
...BASE_QUERY_ARGS,
|
||||||
sortBy: AlbumListSort.PLAY_COUNT,
|
sortBy: AlbumListSort.PLAY_COUNT,
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
startIndex: 0,
|
|
||||||
},
|
},
|
||||||
serverId: server?.id,
|
serverId: server?.id,
|
||||||
});
|
});
|
||||||
|
|
@ -116,27 +125,38 @@ const HomeRoute = () => {
|
||||||
const mostPlayedSongs = useSongList(
|
const mostPlayedSongs = useSongList(
|
||||||
{
|
{
|
||||||
options: {
|
options: {
|
||||||
enabled: server?.type === ServerType.JELLYFIN,
|
enabled: isJellyfin && queriesEnabled[HomeItem.MOST_PLAYED],
|
||||||
staleTime: 1000 * 60 * 5,
|
staleTime: 1000 * 60 * 5,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
limit: itemsPerPage,
|
...BASE_QUERY_ARGS,
|
||||||
sortBy: SongListSort.PLAY_COUNT,
|
sortBy: SongListSort.PLAY_COUNT,
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
startIndex: 0,
|
|
||||||
},
|
},
|
||||||
serverId: server?.id,
|
serverId: server?.id,
|
||||||
},
|
},
|
||||||
300,
|
300,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const recentlyReleased = useAlbumList({
|
||||||
|
options: {
|
||||||
|
enabled: queriesEnabled[HomeItem.RECENTLY_RELEASED],
|
||||||
|
staleTime: 1000 * 60 * 5,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
...BASE_QUERY_ARGS,
|
||||||
|
sortBy: AlbumListSort.RELEASE_DATE,
|
||||||
|
},
|
||||||
|
serverId: server?.id,
|
||||||
|
});
|
||||||
|
|
||||||
const isLoading =
|
const isLoading =
|
||||||
random.isLoading ||
|
(random.isLoading && queriesEnabled[HomeItem.RANDOM]) ||
|
||||||
recentlyPlayed.isLoading ||
|
(recentlyPlayed.isLoading && queriesEnabled[HomeItem.RECENTLY_PLAYED] && !isJellyfin) ||
|
||||||
recentlyAdded.isLoading ||
|
(recentlyAdded.isLoading && queriesEnabled[HomeItem.RECENTLY_ADDED]) ||
|
||||||
(server?.type === ServerType.JELLYFIN && mostPlayedSongs.isLoading) ||
|
(recentlyReleased.isLoading && queriesEnabled[HomeItem.RECENTLY_RELEASED]) ||
|
||||||
((server?.type === ServerType.SUBSONIC || server?.type === ServerType.NAVIDROME) &&
|
(((isJellyfin && mostPlayedSongs.isLoading) ||
|
||||||
mostPlayedAlbums.isLoading);
|
(!isJellyfin && mostPlayedAlbums.isLoading)) &&
|
||||||
|
queriesEnabled[HomeItem.MOST_PLAYED]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Spinner container />;
|
return <Spinner container />;
|
||||||
|
|
@ -144,48 +164,35 @@ const HomeRoute = () => {
|
||||||
|
|
||||||
const carousels = {
|
const carousels = {
|
||||||
[HomeItem.MOST_PLAYED]: {
|
[HomeItem.MOST_PLAYED]: {
|
||||||
data:
|
data: isJellyfin ? mostPlayedSongs?.data?.items : mostPlayedAlbums?.data?.items,
|
||||||
server?.type === ServerType.JELLYFIN
|
itemType: isJellyfin ? LibraryItem.SONG : LibraryItem.ALBUM,
|
||||||
? mostPlayedSongs?.data?.items
|
query: isJellyfin ? mostPlayedSongs : mostPlayedAlbums,
|
||||||
: mostPlayedAlbums?.data?.items,
|
|
||||||
itemType: server?.type === ServerType.JELLYFIN ? LibraryItem.SONG : LibraryItem.ALBUM,
|
|
||||||
pagination: {
|
|
||||||
itemsPerPage,
|
|
||||||
},
|
|
||||||
sortBy:
|
|
||||||
server?.type === ServerType.JELLYFIN
|
|
||||||
? SongListSort.PLAY_COUNT
|
|
||||||
: AlbumListSort.PLAY_COUNT,
|
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
title: t('page.home.mostPlayed', { postProcess: 'sentenceCase' }),
|
title: t('page.home.mostPlayed', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
[HomeItem.RANDOM]: {
|
[HomeItem.RANDOM]: {
|
||||||
data: random?.data?.items,
|
data: random?.data?.items,
|
||||||
itemType: LibraryItem.ALBUM,
|
itemType: LibraryItem.ALBUM,
|
||||||
sortBy: AlbumListSort.RANDOM,
|
query: random,
|
||||||
sortOrder: SortOrder.ASC,
|
|
||||||
title: t('page.home.explore', { postProcess: 'sentenceCase' }),
|
title: t('page.home.explore', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
[HomeItem.RECENTLY_ADDED]: {
|
[HomeItem.RECENTLY_ADDED]: {
|
||||||
data: recentlyAdded?.data?.items,
|
data: recentlyAdded?.data?.items,
|
||||||
itemType: LibraryItem.ALBUM,
|
itemType: LibraryItem.ALBUM,
|
||||||
pagination: {
|
query: recentlyAdded,
|
||||||
itemsPerPage,
|
|
||||||
},
|
|
||||||
sortBy: AlbumListSort.RECENTLY_ADDED,
|
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
title: t('page.home.newlyAdded', { postProcess: 'sentenceCase' }),
|
title: t('page.home.newlyAdded', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
[HomeItem.RECENTLY_PLAYED]: {
|
[HomeItem.RECENTLY_PLAYED]: {
|
||||||
data: recentlyPlayed?.data?.items,
|
data: recentlyPlayed?.data?.items,
|
||||||
itemType: LibraryItem.ALBUM,
|
itemType: LibraryItem.ALBUM,
|
||||||
pagination: {
|
query: recentlyPlayed,
|
||||||
itemsPerPage,
|
|
||||||
},
|
|
||||||
sortBy: AlbumListSort.RECENTLY_PLAYED,
|
|
||||||
sortOrder: SortOrder.DESC,
|
|
||||||
title: t('page.home.recentlyPlayed', { postProcess: 'sentenceCase' }),
|
title: t('page.home.recentlyPlayed', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
|
[HomeItem.RECENTLY_RELEASED]: {
|
||||||
|
data: recentlyReleased?.data?.items,
|
||||||
|
itemType: LibraryItem.ALBUM,
|
||||||
|
query: recentlyReleased,
|
||||||
|
title: t('page.home.recentlyReleased', { postProcess: 'sentenceCase' }),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortedCarousel = homeItems
|
const sortedCarousel = homeItems
|
||||||
|
|
@ -193,7 +200,7 @@ const HomeRoute = () => {
|
||||||
if (item.disabled) {
|
if (item.disabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (server?.type === ServerType.JELLYFIN && item.id === HomeItem.RECENTLY_PLAYED) {
|
if (isJellyfin && item.id === HomeItem.RECENTLY_PLAYED) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,36 +211,6 @@ const HomeRoute = () => {
|
||||||
uniqueId: item.id,
|
uniqueId: item.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const invalidateCarouselQuery = (carousel: {
|
|
||||||
itemType: LibraryItem;
|
|
||||||
sortBy: AlbumListSort | SongListSort;
|
|
||||||
sortOrder: SortOrder;
|
|
||||||
}) => {
|
|
||||||
if (carousel.itemType === LibraryItem.ALBUM) {
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
exact: false,
|
|
||||||
queryKey: queryKeys.albums.list(server?.id, {
|
|
||||||
limit: itemsPerPage,
|
|
||||||
sortBy: carousel.sortBy,
|
|
||||||
sortOrder: carousel.sortOrder,
|
|
||||||
startIndex: 0,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carousel.itemType === LibraryItem.SONG) {
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
exact: false,
|
|
||||||
queryKey: queryKeys.songs.list(server?.id, {
|
|
||||||
limit: itemsPerPage,
|
|
||||||
sortBy: carousel.sortBy,
|
|
||||||
sortOrder: carousel.sortOrder,
|
|
||||||
startIndex: 0,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatedPage>
|
<AnimatedPage>
|
||||||
<NativeScrollArea
|
<NativeScrollArea
|
||||||
|
|
@ -266,7 +243,7 @@ const HomeRoute = () => {
|
||||||
slugs: [
|
slugs: [
|
||||||
{
|
{
|
||||||
idProperty:
|
idProperty:
|
||||||
server?.type === ServerType.JELLYFIN &&
|
isJellyfin &&
|
||||||
carousel.itemType === LibraryItem.SONG
|
carousel.itemType === LibraryItem.SONG
|
||||||
? 'albumId'
|
? 'albumId'
|
||||||
: 'id',
|
: 'id',
|
||||||
|
|
@ -297,8 +274,7 @@ const HomeRoute = () => {
|
||||||
slugs: [
|
slugs: [
|
||||||
{
|
{
|
||||||
idProperty:
|
idProperty:
|
||||||
server?.type === ServerType.JELLYFIN &&
|
isJellyfin && carousel.itemType === LibraryItem.SONG
|
||||||
carousel.itemType === LibraryItem.SONG
|
|
||||||
? 'albumId'
|
? 'albumId'
|
||||||
: 'id',
|
: 'id',
|
||||||
slugProperty: 'albumId',
|
slugProperty: 'albumId',
|
||||||
|
|
@ -310,7 +286,7 @@ const HomeRoute = () => {
|
||||||
<Group>
|
<Group>
|
||||||
<TextTitle order={3}>{carousel.title}</TextTitle>
|
<TextTitle order={3}>{carousel.title}</TextTitle>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
onClick={() => invalidateCarouselQuery(carousel)}
|
onClick={() => carousel.query.refetch()}
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
>
|
>
|
||||||
<Icon icon="refresh" />
|
<Icon icon="refresh" />
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const HOME_ITEMS: Array<[string, string]> = [
|
||||||
[HomeItem.RANDOM, 'page.home.explore'],
|
[HomeItem.RANDOM, 'page.home.explore'],
|
||||||
[HomeItem.RECENTLY_PLAYED, 'page.home.recentlyPlayed'],
|
[HomeItem.RECENTLY_PLAYED, 'page.home.recentlyPlayed'],
|
||||||
[HomeItem.RECENTLY_ADDED, 'page.home.newlyAdded'],
|
[HomeItem.RECENTLY_ADDED, 'page.home.newlyAdded'],
|
||||||
|
[HomeItem.RECENTLY_RELEASED, 'page.home.recentlyReleased'],
|
||||||
[HomeItem.MOST_PLAYED, 'page.home.mostPlayed'],
|
[HomeItem.MOST_PLAYED, 'page.home.mostPlayed'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ export enum HomeItem {
|
||||||
RANDOM = 'random',
|
RANDOM = 'random',
|
||||||
RECENTLY_ADDED = 'recentlyAdded',
|
RECENTLY_ADDED = 'recentlyAdded',
|
||||||
RECENTLY_PLAYED = 'recentlyPlayed',
|
RECENTLY_PLAYED = 'recentlyPlayed',
|
||||||
|
RECENTLY_RELEASED = 'recentlyReleased',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SortableItem<T> = {
|
export type SortableItem<T> = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue