Skip to content

Commit

Permalink
Merge pull request #510 from kgarner7/improve-navidrome-auth
Browse files Browse the repository at this point in the history
[bugfix]: Check for Navidrome authentication on startup
  • Loading branch information
jeffvli authored Mar 4, 2024
2 parents bf3431c + b2fce07 commit 8265ce4
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
54 changes: 54 additions & 0 deletions src/renderer/hooks/use-server-authenticated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useCurrentServer } from '/@/renderer/store';
import { AuthState, ServerListItem, ServerType } from '/@/renderer/types';
import { api } from '/@/renderer/api';
import { SongListSort, SortOrder } from '/@/renderer/api/types';
import { debounce } from 'lodash';

export const useServerAuthenticated = () => {
const priorServerId = useRef<string>();
const server = useCurrentServer();
const [ready, setReady] = useState(
server?.type === ServerType.NAVIDROME ? AuthState.LOADING : AuthState.VALID,
);

const authenticateNavidrome = useCallback(async (server: ServerListItem) => {
// This trick works because navidrome-api.ts will internally check for authentication
// failures and try to log in again (where available). So, all that's necessary is
// making one request first
try {
await api.controller.getSongList({
apiClientProps: { server },
query: {
limit: 1,
sortBy: SongListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
});

setReady(AuthState.VALID);
} catch (error) {
setReady(AuthState.INVALID);
}
}, []);

const debouncedAuth = debounce((server: ServerListItem) => {
authenticateNavidrome(server).catch(console.error);
}, 300);

useEffect(() => {
if (priorServerId.current !== server?.id) {
priorServerId.current = server?.id || '';

if (server?.type === ServerType.NAVIDROME) {
setReady(AuthState.LOADING);
debouncedAuth(server);
} else {
setReady(AuthState.VALID);
}
}
}, [debouncedAuth, server]);

return ready;
};
11 changes: 9 additions & 2 deletions src/renderer/router/app-outlet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import isElectron from 'is-electron';
import { Navigate, Outlet } from 'react-router-dom';
import { AppRoute } from '/@/renderer/router/routes';
import { useCurrentServer, useSetPlayerFallback } from '/@/renderer/store';
import { toast } from '/@/renderer/components';
import { Spinner, toast } from '/@/renderer/components';
import { useServerAuthenticated } from '/@/renderer/hooks/use-server-authenticated';
import { AuthState } from '/@/renderer/types';

const ipc = isElectron() ? window.electron.ipc : null;
const utils = isElectron() ? window.electron.utils : null;
Expand All @@ -12,6 +14,7 @@ const mpvPlayerListener = isElectron() ? window.electron.mpvPlayerListener : nul
export const AppOutlet = () => {
const currentServer = useCurrentServer();
const setFallback = useSetPlayerFallback();
const authState = useServerAuthenticated();

const isActionsRequired = useMemo(() => {
const isServerRequired = !currentServer;
Expand All @@ -37,7 +40,11 @@ export const AppOutlet = () => {
};
}, [setFallback]);

if (isActionsRequired) {
if (authState === AuthState.LOADING) {
return <Spinner container />;
}

if (isActionsRequired || authState === AuthState.INVALID) {
return (
<Navigate
replace
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,9 @@ export enum FontType {
}

export type TitleTheme = 'dark' | 'light' | 'system';

export enum AuthState {
INVALID = 'invalid',
LOADING = 'loading',
VALID = 'valid',
}

0 comments on commit 8265ce4

Please sign in to comment.