mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 10:23:33 +00:00
Tag filter support
- Jellyfin: Uses `/items/filters` to get list of boolean tags. Notably, does not use this same filter for genres. Separate filter for song/album - Navidrome: Uses `/api/tags`, which appears to be album-level as multiple independent selects. Same filter for song/album
This commit is contained in:
parent
b0d86ee5c9
commit
e1aa8d74f3
17 changed files with 360 additions and 16 deletions
|
|
@ -14,6 +14,7 @@ import { MultiSelect, NumberInput, SpinnerIcon, Switch, Text } from '/@/renderer
|
|||
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { AlbumListFilter, useListStoreActions } from '/@/renderer/store';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
|
||||
interface JellyfinAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
|
|
@ -53,6 +54,18 @@ export const JellyfinAlbumFilters = ({
|
|||
}));
|
||||
}, [genreListQuery.data]);
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
query: {
|
||||
folder: filter?.musicFolderId,
|
||||
type: LibraryItem.SONG,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
|
||||
const selectedTags = useMemo(() => {
|
||||
return filter?._custom?.jellyfin?.Tags?.split('|');
|
||||
}, [filter?._custom?.jellyfin?.Tags]);
|
||||
|
||||
const toggleFilters = [
|
||||
{
|
||||
label: t('filter.isFavorited', { postProcess: 'sentenceCase' }),
|
||||
|
|
@ -150,6 +163,24 @@ export const JellyfinAlbumFilters = ({
|
|||
onFilterChange(updatedFilters);
|
||||
};
|
||||
|
||||
const handleTagFilter = debounce((e: string[] | undefined) => {
|
||||
const updatedFilters = setFilter({
|
||||
customFilters,
|
||||
data: {
|
||||
_custom: {
|
||||
...filter?._custom,
|
||||
jellyfin: {
|
||||
...filter?._custom?.jellyfin,
|
||||
Tags: e?.join('|') || undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
itemType: LibraryItem.SONG,
|
||||
key: pageKey,
|
||||
}) as AlbumListFilter;
|
||||
onFilterChange(updatedFilters);
|
||||
}, 250);
|
||||
|
||||
return (
|
||||
<Stack p="0.8rem">
|
||||
{toggleFilters.map((filter) => (
|
||||
|
|
@ -213,6 +244,19 @@ export const JellyfinAlbumFilters = ({
|
|||
onSearchChange={setAlbumArtistSearchTerm}
|
||||
/>
|
||||
</Group>
|
||||
{tagsQuery.data?.boolTags?.length && (
|
||||
<Group grow>
|
||||
<MultiSelect
|
||||
clearable
|
||||
searchable
|
||||
data={tagsQuery.data.boolTags}
|
||||
defaultValue={selectedTags}
|
||||
label={t('common.tags', { postProcess: 'sentenceCase' })}
|
||||
width={250}
|
||||
onChange={handleTagFilter}
|
||||
/>
|
||||
</Group>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
SortOrder,
|
||||
} from '/@/renderer/api/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
|
||||
interface NavidromeAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
|
|
@ -63,6 +64,13 @@ export const NavidromeAlbumFilters = ({
|
|||
onFilterChange(updatedFilters);
|
||||
}, 250);
|
||||
|
||||
const tagsQuery = useTagList({
|
||||
query: {
|
||||
type: LibraryItem.SONG,
|
||||
},
|
||||
serverId,
|
||||
});
|
||||
|
||||
const toggleFilters = [
|
||||
{
|
||||
label: t('filter.isRated', { postProcess: 'sentenceCase' }),
|
||||
|
|
@ -200,6 +208,25 @@ export const NavidromeAlbumFilters = ({
|
|||
onFilterChange(updatedFilters);
|
||||
};
|
||||
|
||||
const handleTagFilter = debounce((tag: string, e: string | null) => {
|
||||
const updatedFilters = setFilter({
|
||||
customFilters,
|
||||
data: {
|
||||
_custom: {
|
||||
...filter._custom,
|
||||
navidrome: {
|
||||
...filter._custom?.navidrome,
|
||||
[tag]: e || undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
itemType: LibraryItem.SONG,
|
||||
key: pageKey,
|
||||
}) as AlbumListFilter;
|
||||
|
||||
onFilterChange(updatedFilters);
|
||||
}, 250);
|
||||
|
||||
return (
|
||||
<Stack p="0.8rem">
|
||||
{toggleFilters.map((filter) => (
|
||||
|
|
@ -248,6 +275,25 @@ export const NavidromeAlbumFilters = ({
|
|||
onSearchChange={setAlbumArtistSearchTerm}
|
||||
/>
|
||||
</Group>
|
||||
{tagsQuery.data?.enumTags?.length &&
|
||||
tagsQuery.data.enumTags.map((tag) => (
|
||||
<Group
|
||||
key={tag.name}
|
||||
grow
|
||||
>
|
||||
<Select
|
||||
clearable
|
||||
searchable
|
||||
data={tag.options}
|
||||
defaultValue={
|
||||
filter._custom?.navidrome?.[tag.name] as string | undefined
|
||||
}
|
||||
label={tag.name}
|
||||
width={150}
|
||||
onChange={(value) => handleTagFilter(tag.name, value)}
|
||||
/>
|
||||
</Group>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue