mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 21:10:12 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba835bec3e | |||
| 9850874dfd | |||
| 51a8285ba2 | |||
| e12150d026 | |||
| 54bc241984 | |||
| a698f83c45 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"description": "A modern self-hosted music player.",
|
"description": "A modern self-hosted music player.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"subsonic",
|
"subsonic",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 5100;
|
z-index: 200;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 5100;
|
z-index: 200;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { SubsonicAlbumFilters } from '/@/renderer/features/albums/components/sub
|
|||||||
import { useAlbumListFilters } from '/@/renderer/features/albums/hooks/use-album-list-filters';
|
import { useAlbumListFilters } from '/@/renderer/features/albums/hooks/use-album-list-filters';
|
||||||
import { ComponentErrorBoundary } from '/@/renderer/features/shared/components/component-error-boundary';
|
import { ComponentErrorBoundary } from '/@/renderer/features/shared/components/component-error-boundary';
|
||||||
import { FilterButton } from '/@/renderer/features/shared/components/filter-button';
|
import { FilterButton } from '/@/renderer/features/shared/components/filter-button';
|
||||||
|
import { SaveAsCollectionButton } from '/@/renderer/features/shared/components/save-as-collection-button';
|
||||||
import { JellyfinSongFilters } from '/@/renderer/features/songs/components/jellyfin-song-filters';
|
import { JellyfinSongFilters } from '/@/renderer/features/songs/components/jellyfin-song-filters';
|
||||||
import { NavidromeSongFilters } from '/@/renderer/features/songs/components/navidrome-song-filters';
|
import { NavidromeSongFilters } from '/@/renderer/features/songs/components/navidrome-song-filters';
|
||||||
import { SubsonicSongFilters } from '/@/renderer/features/songs/components/subsonic-song-filters';
|
import { SubsonicSongFilters } from '/@/renderer/features/songs/components/subsonic-song-filters';
|
||||||
@@ -18,6 +19,7 @@ import { Button } from '/@/shared/components/button/button';
|
|||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Modal } from '/@/shared/components/modal/modal';
|
import { Modal } from '/@/shared/components/modal/modal';
|
||||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||||
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { useDisclosure } from '/@/shared/hooks/use-disclosure';
|
import { useDisclosure } from '/@/shared/hooks/use-disclosure';
|
||||||
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||||
@@ -103,6 +105,12 @@ export const ListFiltersModal = ({ isActive, itemType }: ListFiltersProps) => {
|
|||||||
disableArtistFilter={disableArtistFilter}
|
disableArtistFilter={disableArtistFilter}
|
||||||
disableGenreFilter={disableGenreFilter}
|
disableGenreFilter={disableGenreFilter}
|
||||||
/>
|
/>
|
||||||
|
<Stack p="md">
|
||||||
|
<SaveAsCollectionButton
|
||||||
|
fullWidth
|
||||||
|
itemType={itemType as LibraryItem.ALBUM | LibraryItem.SONG}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export const SaveAsCollectionButton = ({ fullWidth, itemType }: SaveAsCollection
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover onClose={handlers.close} opened={isOpen} position="bottom-start" width={320}>
|
<Popover onClose={handlers.close} opened={isOpen} width="target">
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
{fullWidth ? (
|
{fullWidth ? (
|
||||||
<Button fullWidth onClick={handleOpen} variant="default">
|
<Button fullWidth onClick={handleOpen} variant="default">
|
||||||
|
|||||||
@@ -479,7 +479,8 @@ const VisualizerInner = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const CurrentPresetDisplay = () => {
|
const CurrentPresetDisplay = () => {
|
||||||
const currentPreset = useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
const currentPreset = useSettingsStore((store) => store.visualizer.butterchurn.currentPreset);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text className={styles['preset-overlay']} isNoSelect size="sm">
|
<Text className={styles['preset-overlay']} isNoSelect size="sm">
|
||||||
{currentPreset}
|
{currentPreset}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { closeAllModals, openModal } from '@mantine/modals';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import packageJson from '../../package.json';
|
import packageJson from '../../package.json';
|
||||||
@@ -12,32 +12,67 @@ import { Center } from '/@/shared/components/center/center';
|
|||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
|
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
|
||||||
|
import { Select } from '/@/shared/components/select/select';
|
||||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||||
import { Stack } from '/@/shared/components/stack/stack';
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
||||||
|
|
||||||
|
const GITHUB_RELEASES_URL = 'https://api.github.com/repos/jeffvli/feishin/releases';
|
||||||
|
const RELEASES_TO_FETCH = 5;
|
||||||
|
|
||||||
|
interface GitHubRelease {
|
||||||
|
body: null | string;
|
||||||
|
name: null | string;
|
||||||
|
published_at: string;
|
||||||
|
tag_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface ReleaseNotesContentProps {
|
interface ReleaseNotesContentProps {
|
||||||
onDismiss: () => void;
|
onDismiss: () => void;
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseVersionFromTag(tagName: string): string {
|
||||||
|
return tagName.startsWith('v') ? tagName.slice(1) : tagName;
|
||||||
|
}
|
||||||
|
|
||||||
const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) => {
|
const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [selectedVersion, setSelectedVersion] = useState(version);
|
||||||
|
|
||||||
|
// Fetch list of recent releases for the selector
|
||||||
|
const { data: releasesList = [] } = useQuery({
|
||||||
|
queryFn: async () => {
|
||||||
|
const response = await axios.get<GitHubRelease[]>(GITHUB_RELEASES_URL, {
|
||||||
|
params: { per_page: RELEASES_TO_FETCH },
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
queryKey: ['github-releases-list'],
|
||||||
|
retry: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const releaseOptions = useMemo(() => {
|
||||||
|
const versions = releasesList.map((r) => parseVersionFromTag(r.tag_name));
|
||||||
|
if (!versions.includes(version)) {
|
||||||
|
versions.unshift(version);
|
||||||
|
}
|
||||||
|
return versions.slice(0, RELEASES_TO_FETCH).map((v) => ({ label: v, value: v }));
|
||||||
|
}, [releasesList, version]);
|
||||||
|
|
||||||
// Fetch release notes from GitHub API
|
|
||||||
const {
|
const {
|
||||||
data: releaseData,
|
data: releaseData,
|
||||||
isError,
|
isError,
|
||||||
isLoading,
|
isLoading,
|
||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const response = await axios.get(
|
const response = await axios.get<GitHubRelease>(
|
||||||
`https://api.github.com/repos/jeffvli/feishin/releases/tags/v${version}`,
|
`${GITHUB_RELEASES_URL}/tags/v${selectedVersion}`,
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
queryKey: ['github-release', version],
|
queryKey: ['github-release', selectedVersion],
|
||||||
retry: 2,
|
retry: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,7 +84,7 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
|||||||
'https://api.github.com/markdown',
|
'https://api.github.com/markdown',
|
||||||
{
|
{
|
||||||
mode: 'gfm',
|
mode: 'gfm',
|
||||||
text: releaseData.body,
|
text: releaseData?.body ?? '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -103,11 +138,19 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
|||||||
if (isError || !releaseData) {
|
if (isError || !releaseData) {
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
|
{releaseOptions.length > 1 && (
|
||||||
|
<Select
|
||||||
|
data={releaseOptions}
|
||||||
|
label={t('common.version', { postProcess: 'sentenceCase' })}
|
||||||
|
onChange={(v) => v && setSelectedVersion(v)}
|
||||||
|
value={selectedVersion}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Text size="sm">{t('error.genericError', { postProcess: 'sentenceCase' })}</Text>
|
<Text size="sm">{t('error.genericError', { postProcess: 'sentenceCase' })}</Text>
|
||||||
<Group justify="flex-end">
|
<Group justify="flex-end">
|
||||||
<Button
|
<Button
|
||||||
component="a"
|
component="a"
|
||||||
href={`https://github.com/jeffvli/feishin/releases/tag/v${version}`}
|
href={`https://github.com/jeffvli/feishin/releases/tag/v${selectedVersion}`}
|
||||||
onClick={onDismiss}
|
onClick={onDismiss}
|
||||||
rightSection={<Icon icon="externalLink" />}
|
rightSection={<Icon icon="externalLink" />}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -125,6 +168,14 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
|
{releaseOptions.length > 1 && (
|
||||||
|
<Select
|
||||||
|
data={releaseOptions}
|
||||||
|
label={t('common.version', { postProcess: 'sentenceCase' })}
|
||||||
|
onChange={(v) => v && setSelectedVersion(v)}
|
||||||
|
value={selectedVersion}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
style={{
|
style={{
|
||||||
height: '400px',
|
height: '400px',
|
||||||
@@ -140,7 +191,7 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
|||||||
<Group justify="flex-end">
|
<Group justify="flex-end">
|
||||||
<Button
|
<Button
|
||||||
component="a"
|
component="a"
|
||||||
href={`https://github.com/jeffvli/feishin/releases/tag/v${version}`}
|
href={`https://github.com/jeffvli/feishin/releases/tag/v${selectedVersion}`}
|
||||||
onClick={onDismiss}
|
onClick={onDismiss}
|
||||||
rightSection={<Icon icon="externalLink" />}
|
rightSection={<Icon icon="externalLink" />}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 5000;
|
z-index: 195;
|
||||||
height: 65px;
|
height: 65px;
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user