mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-06 20:10:12 +02:00
feat: add regex filter setting for sidebar playlists (#1589)
* added regex filter for sidebar playlists --------- Co-authored-by: jeffvli <jeffvictorli@gmail.com>
This commit is contained in:
@@ -979,6 +979,9 @@
|
||||
"sidebarPlaylistList": "sidebar playlist list",
|
||||
"sidebarPlaylistSorting_description": "allows manual playlist sorting in the sidebar using drag and drop instead of the default server order",
|
||||
"sidebarPlaylistSorting": "sidebar playlist sorting",
|
||||
"sidebarPlaylistListFilterRegex_description": "hide playlists in the sidebar that match this regular expression",
|
||||
"sidebarPlaylistListFilterRegex_placeholder": "e.g. ^Daily Mix.*",
|
||||
"sidebarPlaylistListFilterRegex": "playlist filter regex",
|
||||
"sidePlayQueueStyle_description": "sets the style of the side play queue",
|
||||
"sidePlayQueueStyle_optionAttached": "attached",
|
||||
"sidePlayQueueStyle_optionDetached": "detached",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeEvent, memo } from 'react';
|
||||
import { ChangeEvent, memo, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SidebarReorder } from '/@/renderer/features/settings/components/general/sidebar-reorder';
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
} from '/@/renderer/features/settings/components/settings-section';
|
||||
import { useGeneralSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import { Switch } from '/@/shared/components/switch/switch';
|
||||
import { TextInput } from '/@/shared/components/text-input/text-input';
|
||||
import { useDebouncedCallback } from '/@/shared/hooks/use-debounced-callback';
|
||||
|
||||
export const SidebarSettings = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
@@ -38,6 +40,22 @@ export const SidebarSettings = memo(() => {
|
||||
});
|
||||
};
|
||||
|
||||
const [localFilterRegex, setLocalFilterRegex] = useState(
|
||||
settings.sidebarPlaylistListFilterRegex,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setLocalFilterRegex(settings.sidebarPlaylistListFilterRegex);
|
||||
}, [settings.sidebarPlaylistListFilterRegex]);
|
||||
|
||||
const debouncedSetFilterRegex = useDebouncedCallback((value: string) => {
|
||||
setSettings({
|
||||
general: {
|
||||
sidebarPlaylistListFilterRegex: value,
|
||||
},
|
||||
});
|
||||
}, 500);
|
||||
|
||||
const options: SettingOption[] = [
|
||||
{
|
||||
control: (
|
||||
@@ -52,6 +70,26 @@ export const SidebarSettings = memo(() => {
|
||||
}),
|
||||
title: t('setting.sidebarPlaylistList', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<TextInput
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
setLocalFilterRegex(value);
|
||||
debouncedSetFilterRegex(value);
|
||||
}}
|
||||
placeholder={t('setting.sidebarPlaylistListFilterRegex_placeholder', {
|
||||
postProcess: 'sentenceCase',
|
||||
})}
|
||||
value={localFilterRegex}
|
||||
/>
|
||||
),
|
||||
description: t('setting.sidebarPlaylistListFilterRegex', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
title: t('setting.sidebarPlaylistListFilterRegex', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<Switch
|
||||
|
||||
@@ -25,6 +25,12 @@ import {
|
||||
usePermissions,
|
||||
useSidebarPlaylistSorting,
|
||||
} from '/@/renderer/store';
|
||||
import {
|
||||
useCurrentServer,
|
||||
useCurrentServerId,
|
||||
usePermissions,
|
||||
useSidebarPlaylistListFilterRegex,
|
||||
} from '/@/renderer/store';
|
||||
import { formatDurationString } from '/@/renderer/utils';
|
||||
import { Accordion } from '/@/shared/components/accordion/accordion';
|
||||
import { ActionIcon, ActionIconGroup } from '/@/shared/components/action-icon/action-icon';
|
||||
@@ -357,6 +363,7 @@ export const SidebarPlaylistList = () => {
|
||||
const { t } = useTranslation();
|
||||
const server = useCurrentServer();
|
||||
const sidebarPlaylistSorting = useSidebarPlaylistSorting();
|
||||
const filterRegex = useSidebarPlaylistListFilterRegex();
|
||||
|
||||
const playlistsQuery = useQuery(
|
||||
playlistsQueries.list({
|
||||
@@ -400,10 +407,23 @@ export const SidebarPlaylistList = () => {
|
||||
return { ...base, items: playlistsQuery.data?.items };
|
||||
}
|
||||
|
||||
let regex: null | RegExp = null;
|
||||
if (filterRegex) {
|
||||
try {
|
||||
regex = new RegExp(filterRegex, 'i');
|
||||
} catch {
|
||||
// Invalid regex, ignore filtering
|
||||
}
|
||||
}
|
||||
|
||||
const ownedPlaylistItems: Array<Playlist> = [];
|
||||
|
||||
for (const playlist of playlistsQuery.data?.items ?? []) {
|
||||
if (!playlist.owner || playlist.owner === server.username) {
|
||||
// Filter out playlists that match the regex
|
||||
if (regex && regex.test(playlist.name)) {
|
||||
continue;
|
||||
}
|
||||
ownedPlaylistItems.push(playlist);
|
||||
}
|
||||
}
|
||||
@@ -429,6 +449,7 @@ export const SidebarPlaylistList = () => {
|
||||
server.username,
|
||||
sidebarPlaylistSorting,
|
||||
playlistOrder,
|
||||
filterRegex,
|
||||
]);
|
||||
|
||||
const handleReorder = (
|
||||
@@ -533,6 +554,7 @@ export const SidebarSharedPlaylistList = () => {
|
||||
const { t } = useTranslation();
|
||||
const server = useCurrentServer();
|
||||
const sidebarPlaylistSorting = useSidebarPlaylistSorting();
|
||||
const filterRegex = useSidebarPlaylistListFilterRegex();
|
||||
|
||||
const playlistsQuery = useQuery(
|
||||
playlistsQueries.list({
|
||||
@@ -580,10 +602,23 @@ export const SidebarSharedPlaylistList = () => {
|
||||
return { ...base, items: playlistsQuery.data?.items };
|
||||
}
|
||||
|
||||
let regex: null | RegExp = null;
|
||||
if (filterRegex) {
|
||||
try {
|
||||
regex = new RegExp(filterRegex, 'i');
|
||||
} catch {
|
||||
// Invalid regex, ignore filtering
|
||||
}
|
||||
}
|
||||
|
||||
const sharedPlaylistItems: Array<Playlist> = [];
|
||||
|
||||
for (const playlist of playlistsQuery.data?.items ?? []) {
|
||||
if (playlist.owner && playlist.owner !== server.username) {
|
||||
// Filter out playlists that match the regex
|
||||
if (regex && regex.test(playlist.name)) {
|
||||
continue;
|
||||
}
|
||||
sharedPlaylistItems.push(playlist);
|
||||
}
|
||||
}
|
||||
@@ -609,6 +644,7 @@ export const SidebarSharedPlaylistList = () => {
|
||||
server.username,
|
||||
sidebarPlaylistSorting,
|
||||
playlistOrder,
|
||||
filterRegex,
|
||||
]);
|
||||
|
||||
const handleReorder = (
|
||||
|
||||
@@ -454,6 +454,7 @@ export const GeneralSettingsSchema = z.object({
|
||||
sidebarItems: z.array(SidebarItemTypeSchema),
|
||||
sidebarPanelOrder: z.array(SidebarPanelTypeSchema),
|
||||
sidebarPlaylistList: z.boolean(),
|
||||
sidebarPlaylistListFilterRegex: z.string(),
|
||||
sidebarPlaylistSorting: z.boolean(),
|
||||
sideQueueType: SideQueueTypeSchema,
|
||||
skipButtons: SkipButtonsSchema,
|
||||
@@ -1030,6 +1031,7 @@ const initialState: SettingsState = {
|
||||
sidebarItems,
|
||||
sidebarPanelOrder: ['queue', 'lyrics', 'visualizer'],
|
||||
sidebarPlaylistList: true,
|
||||
sidebarPlaylistListFilterRegex: '',
|
||||
sidebarPlaylistSorting: false,
|
||||
sideQueueType: 'sideQueue',
|
||||
skipButtons: {
|
||||
@@ -2193,6 +2195,9 @@ export const useSidebarPlaylistList = () =>
|
||||
export const useSidebarPlaylistSorting = () =>
|
||||
useSettingsStore((state) => state.general.sidebarPlaylistSorting, shallow);
|
||||
|
||||
export const useSidebarPlaylistListFilterRegex = () =>
|
||||
useSettingsStore((state) => state.general.sidebarPlaylistListFilterRegex, shallow);
|
||||
|
||||
export const useSidebarItems = () =>
|
||||
useSettingsStore((state) => state.general.sidebarItems, shallow);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user