improve app logging

- consolidate electron-log and expand support-oriented logging
- consolidate log levels to info / trace only
- add system/server diagnostics exporter
This commit is contained in:
jeffvli
2026-07-20 22:25:44 -07:00
parent 99258c92fc
commit cbf8037099
45 changed files with 1429 additions and 1067 deletions
@@ -16,8 +16,7 @@ import {
usePlayerStore,
useSettingsStore,
} from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { LyricSource, ServerType } from '/@/shared/types/domain-types';
import { FontType, Platform, PlayerStyle, PlayerType } from '/@/shared/types/types';
@@ -275,10 +274,7 @@ export const useAppTracker = () => {
if (lastTrackedDate !== todayUTC) {
appTrackerInFlight = true;
const properties = getProperties();
logFn.info(logMsg[LogCategory.ANALYTICS].appTracked, {
category: LogCategory.ANALYTICS,
meta: { properties, todayUTC },
});
logger.debug('Analytics sent', { properties, todayUTC });
trackAppViewMutation(undefined, {
onError: () => {},
@@ -295,10 +291,7 @@ export const useAppTracker = () => {
appTrackerLastSentDate = utcDate;
localStorage.setItem('analytics_app_tracker_timestamp', utcDate);
logFn.debug(logMsg[LogCategory.ANALYTICS].appTracked, {
category: LogCategory.ANALYTICS,
meta: { properties },
});
logger.debug('Analytics sent', { properties });
},
});
}
@@ -4,9 +4,7 @@ import { useLocation } from 'react-router';
import { isAnalyticsDisabled } from '/@/renderer/features/analytics/hooks/use-analytics-disabled';
import { getRoutePattern } from '/@/renderer/features/analytics/utils/get-route-pattern';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
const trackPageView = (routePattern: string) => {
window.umami?.track((props) => ({
language: props.language,
@@ -28,10 +26,7 @@ export const usePageTracker = () => {
trackPageViewMutation(routePattern, {
onSettled: () => {
logFn.debug(logMsg[LogCategory.ANALYTICS].pageViewTracked, {
category: LogCategory.ANALYTICS,
meta: { route: routePattern },
});
logger.debug('Page view tracked', { route: routePattern });
},
});
}, [routePattern, trackPageViewMutation]);
@@ -22,8 +22,7 @@ import {
useTimestampStoreBase,
} from '/@/renderer/store';
import { sentenceCase } from '/@/renderer/utils';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { useDebouncedCallback } from '/@/shared/hooks/use-debounced-callback';
import { LibraryItem, QueueSong, ServerType } from '/@/shared/types/domain-types';
import { PlayerStatus } from '/@/shared/types/types';
@@ -112,13 +111,10 @@ export const useDiscordRpc = () => {
reason = 'paused_with_show_paused_disabled';
}
logFn.debug(logMsg[LogCategory.EXTERNAL].discordRpcActivityCleared, {
category: LogCategory.EXTERNAL,
meta: {
reason,
status: current[2],
trigger,
},
logger.debug('Activity was cleared for Discord RPC', {
reason,
status: current[2],
trigger,
});
return discordRpc?.clearActivity();
}
@@ -151,24 +147,20 @@ export const useDiscordRpc = () => {
const isConnected = await discordRpc?.isConnected();
if (!isConnected) {
logFn.debug(logMsg[LogCategory.EXTERNAL].discordRpcInitialized, {
category: LogCategory.EXTERNAL,
meta: { clientId: discordSettings.clientId },
logger.info('Discord RPC was initialized', {
clientId: discordSettings.clientId,
});
previousEnabledRef.current = true;
await discordRpc?.initialize(discordSettings.clientId);
}
logFn.debug(logMsg[LogCategory.EXTERNAL].discordRpcSetActivity, {
category: LogCategory.EXTERNAL,
meta: {
currentStatus: current[2],
reason: 'radio',
showAsListening: discordSettings.showAsListening,
stationName: stationName || 'Radio',
title,
trigger,
},
logger.debug('Activity was set for Discord RPC', {
currentStatus: current[2],
reason: 'radio',
showAsListening: discordSettings.showAsListening,
stationName: stationName || 'Radio',
title,
trigger,
});
discordRpc?.setActivity(activity);
return;
@@ -179,13 +171,10 @@ export const useDiscordRpc = () => {
}
if (trackChanged) {
logFn.debug(logMsg[LogCategory.EXTERNAL].discordRpcTrackChanged, {
category: LogCategory.EXTERNAL,
meta: {
artistName: song.artists?.[0]?.name,
songId: song._uniqueId,
songName: song.name,
},
logger.debug('Track was changed for Discord RPC', {
artistName: song.artists?.[0]?.name,
songId: song._uniqueId,
songName: song.name,
});
setlastUniqueId(song._uniqueId);
}
@@ -319,11 +308,8 @@ export const useDiscordRpc = () => {
// Initialize if needed
const isConnected = await discordRpc?.isConnected();
if (!isConnected) {
logFn.debug(logMsg[LogCategory.EXTERNAL].discordRpcInitialized, {
category: LogCategory.EXTERNAL,
meta: {
clientId: discordSettings.clientId,
},
logger.info('Discord RPC was initialized', {
clientId: discordSettings.clientId,
});
previousEnabledRef.current = true;
@@ -331,22 +317,19 @@ export const useDiscordRpc = () => {
await discordRpc?.initialize(discordSettings.clientId);
}
logFn.debug(logMsg[LogCategory.EXTERNAL].discordRpcSetActivity, {
category: LogCategory.EXTERNAL,
meta: {
albumName: song.album,
artistName: song.artists?.[0]?.name,
currentStatus: current[2],
currentTime: current[1],
displayType: discordSettings.displayType,
hasLargeImage: !!activity.largeImageKey,
hasTimestamps: !!(activity.startTimestamp && activity.endTimestamp),
reason,
showAsListening: discordSettings.showAsListening,
songName: song.name,
trackChanged,
trigger,
},
logger.debug('Activity was set for Discord RPC', {
albumName: song.album,
artistName: song.artists?.[0]?.name,
currentStatus: current[2],
currentTime: current[1],
displayType: discordSettings.displayType,
hasLargeImage: !!activity.largeImageKey,
hasTimestamps: !!(activity.startTimestamp && activity.endTimestamp),
reason,
showAsListening: discordSettings.showAsListening,
songName: song.name,
trackChanged,
trigger,
});
discordRpc?.setActivity(activity);
},
@@ -374,12 +357,9 @@ export const useDiscordRpc = () => {
// Quit Discord RPC if it was enabled and is now disabled
useEffect(() => {
if ((!discordSettings.enabled || privateMode) && Boolean(previousEnabledRef.current)) {
logFn.info(logMsg[LogCategory.EXTERNAL].discordRpcQuit, {
category: LogCategory.EXTERNAL,
meta: {
enabled: discordSettings.enabled,
privateMode,
},
logger.info('Discord RPC was quit', {
enabled: discordSettings.enabled,
privateMode,
});
previousEnabledRef.current = false;
@@ -5,8 +5,7 @@ import { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'r
import { AudioPlayer, PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
import { convertToLogVolume } from '/@/renderer/features/player/audio-player/utils/player-utils';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { PlayerStatus } from '/@/shared/types/types';
export interface WebPlayerEngineHandle extends AudioPlayer {
@@ -174,6 +173,21 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
player2Ref.current?.getInternalPlayer()?.pause();
}, []);
const mediaErrorLabel = (code: number | undefined) => {
switch (code) {
case MediaError.MEDIA_ERR_ABORTED:
return 'ABORTED';
case MediaError.MEDIA_ERR_DECODE:
return 'DECODE';
case MediaError.MEDIA_ERR_NETWORK:
return 'NETWORK';
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
return 'SRC_NOT_SUPPORTED';
default:
return 'unknown';
}
};
const handleOnError = (
playerRef: React.RefObject<null | ReactPlayer>,
onEnded: () => void,
@@ -188,27 +202,30 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
}
const { error } = target;
logFn.error(logMsg[LogCategory.PLAYER].playbackError, {
category: LogCategory.PLAYER,
meta: { error },
});
const code = error?.code;
const label = mediaErrorLabel(code);
const isNetworkError =
error?.code === MediaError.MEDIA_ERR_NETWORK ||
error?.code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED;
code === MediaError.MEDIA_ERR_NETWORK ||
code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED;
if (isNetworkError) {
if (networkRetryCountRef.current < MAX_NETWORK_RETRIES) {
networkRetryCountRef.current += 1;
logger.warn('Playback error, retrying', {
code,
label,
retryCount: networkRetryCountRef.current,
});
const audio = target;
setTimeout(() => {
pauseBothPlayers();
audio.load();
audio.play().catch(() => {
logFn.error(logMsg[LogCategory.PLAYER].playbackError, {
category: LogCategory.PLAYER,
meta: { error: 'Failed to play audio after network error' },
logger.error('Playback error, retries exhausted', {
code,
label,
retryCount: networkRetryCountRef.current,
});
});
}, NETWORK_RETRY_DELAY_MS);
@@ -216,14 +233,24 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
}
}
if (error?.code !== MediaError.MEDIA_ERR_DECODE && !isNetworkError) {
if (code !== MediaError.MEDIA_ERR_DECODE && !isNetworkError) {
return;
}
pauseBothPlayers();
if (error?.code === MediaError.MEDIA_ERR_DECODE) {
if (code === MediaError.MEDIA_ERR_DECODE) {
logger.error('Playback decode error, skipping track', {
code,
label,
retryCount: networkRetryCountRef.current,
});
onEnded();
} else {
logger.error('Playback error, pausing', {
code,
label,
retryCount: networkRetryCountRef.current,
});
if (onErrorPause) {
onErrorPause();
}
@@ -39,7 +39,7 @@ import {
usePlaybackType,
useSettingsStoreActions,
} from '/@/renderer/store';
import { logFn } from '/@/renderer/utils/logger';
import { logger } from '/@/renderer/utils/logger';
import { toast } from '/@/shared/components/toast/toast';
import { LibraryItem } from '/@/shared/types/domain-types';
import { PlayerType } from '/@/shared/types/types';
@@ -99,7 +99,7 @@ function detectBrowserProfile() {
}
}
logFn.info('DIRECT_PLAY_PROFILES', { meta: DIRECT_PLAY_PROFILES });
logger.debug('DIRECT_PLAY_PROFILES', DIRECT_PLAY_PROFILES);
return DIRECT_PLAY_PROFILES;
}
@@ -158,6 +158,8 @@ export const AudioPlayers = () => {
);
};
const mpvPlayerListener = isElectron() ? window.api.mpvPlayerListener : null;
const AudioPlayersContent = ({
audioContext,
audioDeviceId,
@@ -179,6 +181,24 @@ const AudioPlayersContent = ({
}) => {
const isRadioActive = useIsRadioActive();
useEffect(() => {
logger.info('Playback engine', { playbackType });
}, [playbackType]);
useEffect(() => {
if (!mpvPlayerListener) {
return;
}
mpvPlayerListener.rendererPlayerFallback((isFallback: boolean) => {
if (isFallback) {
logger.warn('Playback engine fell back to web');
} else {
logger.info('Playback engine using local (mpv)');
}
});
}, []);
useEffect(() => {
if (webAudio && 'AudioContext' in window) {
let context: AudioContext;
@@ -18,8 +18,7 @@ import {
import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api';
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
import { AddToQueueType, usePlayerActions, useSettingsStore } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { shuffle as shuffleArray } from '/@/renderer/utils/shuffle';
import { sortSongsByFetchedOrder } from '/@/shared/api/utils';
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
@@ -229,22 +228,20 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
if (typeof type === 'object' && 'edge' in type && type.edge !== null) {
const edge = type.edge === 'top' ? 'top' : 'bottom';
logFn.debug(logMsg[LogCategory.PLAYER].addToQueueByData, {
category: LogCategory.PLAYER,
meta: {
data: data.length,
edge,
filtered: filteredData.length,
type,
uniqueId: type.uniqueId,
},
logger.debug('Added to queue by data', {
data: data.length,
edge,
filtered: filteredData.length,
type,
uniqueId: type.uniqueId,
});
storeActions.addToQueueByUniqueId(filteredData, type.uniqueId, edge, playSongId);
} else {
logFn.debug(logMsg[LogCategory.PLAYER].addToQueueByType, {
category: LogCategory.PLAYER,
meta: { data: data.length, filtered: filteredData.length, type },
logger.debug('Added to queue by type', {
data: data.length,
filtered: filteredData.length,
type,
});
storeActions.addToQueueByType(filteredData, type as Play, playSongId);
@@ -281,10 +278,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
};
try {
logFn.debug(logMsg[LogCategory.PLAYER].addToQueueByFetch, {
category: LogCategory.PLAYER,
meta: { ids: id, itemType, serverId, type },
});
logger.debug('Added to queue by fetch', { ids: id, itemType, serverId, type });
const songs = await queryClient.fetchQuery({
gcTime: 0,
@@ -361,10 +355,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
let toastId: null | string = null;
let fetchId: null | string = null;
logFn.debug(logMsg[LogCategory.PLAYER].addToQueueByListQuery, {
category: LogCategory.PLAYER,
meta: { itemType, query, serverId, type },
});
logger.debug('Added to queue by list query', { itemType, query, serverId, type });
try {
let totalCount = 0;
@@ -440,10 +431,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
autoClose: false,
message: t('player.playbackFetchCancel'),
onClose: () => {
logFn.debug(logMsg[LogCategory.PLAYER].cancelledFetch, {
category: LogCategory.PLAYER,
meta: { itemType, serverId },
});
logger.debug('Cancelled fetch', { itemType, serverId });
queryClient.cancelQueries({
exact: false,
@@ -538,19 +526,14 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const clearQueue = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].clearQueue, {
category: LogCategory.PLAYER,
});
logger.debug('Cleared queue');
storeActions.clearQueue();
}, [storeActions]);
const clearSelected = useCallback(
(items: QueueSong[]) => {
logFn.debug(logMsg[LogCategory.PLAYER].clearSelected, {
category: LogCategory.PLAYER,
meta: { items: items.length },
});
logger.debug('Cleared selected', { items: items.length });
storeActions.clearSelected(items);
},
@@ -559,10 +542,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const decreaseVolume = useCallback(
(amount: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].decreaseVolume, {
category: LogCategory.PLAYER,
meta: { amount },
});
logger.debug('Decreased volume', { amount });
storeActions.decreaseVolume(amount);
},
@@ -570,9 +550,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const getQueue = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].clearQueue, {
category: LogCategory.PLAYER,
});
logger.debug('Cleared queue');
const queue = storeActions.getQueue();
return queue.items;
@@ -580,10 +558,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const increaseVolume = useCallback(
(amount: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].increaseVolume, {
category: LogCategory.PLAYER,
meta: { amount },
});
logger.debug('Increased volume', { amount });
storeActions.increaseVolume(amount);
},
@@ -592,9 +567,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const mediaNext = useCallback(
(toNextAlbum: boolean) => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaNext, {
category: LogCategory.PLAYER,
});
logger.debug('Media next');
storeActions.mediaNext(toNextAlbum);
},
@@ -602,19 +575,14 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const mediaPause = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaPause, {
category: LogCategory.PLAYER,
});
logger.debug('Media pause');
storeActions.mediaPause();
}, [storeActions]);
const mediaPlay = useCallback(
(id?: string) => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaPlay, {
category: LogCategory.PLAYER,
meta: { id },
});
logger.debug('Media play', { id });
storeActions.mediaPlay(id);
},
@@ -623,10 +591,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const mediaPlayByIndex = useCallback(
(index: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaPlayByIndex, {
category: LogCategory.PLAYER,
meta: { index },
});
logger.debug('Media play by index', { index });
storeActions.mediaPlayByIndex(index);
},
@@ -635,9 +600,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const mediaPrevious = useCallback(
(toPreviousAlbum: boolean) => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaPrevious, {
category: LogCategory.PLAYER,
});
logger.debug('Media previous');
storeActions.mediaPrevious(toPreviousAlbum);
},
@@ -646,10 +609,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const mediaStop = useCallback(
(options?: { reset?: boolean }) => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaStop, {
category: LogCategory.PLAYER,
meta: { reset: options?.reset },
});
logger.debug('Media stop', { reset: options?.reset });
storeActions.mediaStop(options);
},
@@ -658,10 +618,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const mediaSeekToTimestamp = useCallback(
(timestamp: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaSeekToTimestamp, {
category: LogCategory.PLAYER,
meta: { timestamp },
});
logger.debug('Media seek to timestamp', { timestamp });
storeActions.mediaSeekToTimestamp(timestamp);
},
@@ -669,30 +626,23 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const mediaSkipBackward = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaSkipBackward, {
category: LogCategory.PLAYER,
});
logger.debug('Media skip backward');
storeActions.mediaSkipBackward();
}, [storeActions]);
const mediaSkipForward = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaSkipForward, {
category: LogCategory.PLAYER,
});
logger.debug('Media skip forward');
storeActions.mediaSkipForward();
}, [storeActions]);
const setQueue = useCallback(
(data: Song[], index?: number, position?: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].setQueue, {
category: LogCategory.PLAYER,
meta: {
data: data.length,
index,
position,
},
logger.debug('Set queue', {
data: data.length,
index,
position,
});
storeActions.setQueue(data, index, position);
@@ -702,10 +652,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const setSpeed = useCallback(
(speed: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].setSpeed, {
category: LogCategory.PLAYER,
meta: { speed },
});
logger.debug('Set speed', { speed });
storeActions.setSpeed(speed);
},
@@ -713,27 +660,20 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const mediaToggleMute = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaToggleMute, {
category: LogCategory.PLAYER,
});
logger.debug('Media toggle mute');
storeActions.mediaToggleMute();
}, [storeActions]);
const mediaTogglePlayPause = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].mediaTogglePlayPause, {
category: LogCategory.PLAYER,
});
logger.debug('Media toggle play pause');
storeActions.mediaTogglePlayPause();
}, [storeActions]);
const moveSelectedTo = useCallback(
(items: QueueSong[], edge: 'bottom' | 'top', uniqueId: string) => {
logFn.debug(logMsg[LogCategory.PLAYER].moveSelectedTo, {
category: LogCategory.PLAYER,
meta: { edge, items, uniqueId },
});
logger.debug('Moved selected to', { edge, items, uniqueId });
storeActions.moveSelectedTo(items, uniqueId, edge);
},
@@ -742,10 +682,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const moveSelectedToBottom = useCallback(
(items: QueueSong[]) => {
logFn.debug(logMsg[LogCategory.PLAYER].moveSelectedToBottom, {
category: LogCategory.PLAYER,
meta: { items },
});
logger.debug('Moved selected to bottom', { items });
storeActions.moveSelectedToBottom(items);
},
@@ -754,10 +691,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const moveSelectedToNext = useCallback(
(items: QueueSong[]) => {
logFn.debug(logMsg[LogCategory.PLAYER].moveSelectedToNext, {
category: LogCategory.PLAYER,
meta: { items },
});
logger.debug('Moved selected to next', { items });
storeActions.moveSelectedToNext(items);
},
@@ -766,10 +700,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const moveSelectedToTop = useCallback(
(items: QueueSong[]) => {
logFn.debug(logMsg[LogCategory.PLAYER].moveSelectedToTop, {
category: LogCategory.PLAYER,
meta: { items },
});
logger.debug('Moved selected to top', { items });
storeActions.moveSelectedToTop(items);
},
@@ -778,10 +709,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const setVolume = useCallback(
(volume: number) => {
logFn.debug(logMsg[LogCategory.PLAYER].setVolume, {
category: LogCategory.PLAYER,
meta: { volume },
});
logger.debug('Set volume', { volume });
storeActions.setVolume(volume);
},
@@ -790,10 +718,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const setRepeat = useCallback(
(repeat: PlayerRepeat) => {
logFn.debug(logMsg[LogCategory.PLAYER].setRepeat, {
category: LogCategory.PLAYER,
meta: { repeat },
});
logger.debug('Set repeat', { repeat });
storeActions.setRepeat(repeat);
},
@@ -802,10 +727,7 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
const setShuffle = useCallback(
(shuffle: PlayerShuffle) => {
logFn.debug(logMsg[LogCategory.PLAYER].setShuffle, {
category: LogCategory.PLAYER,
meta: { shuffle },
});
logger.debug('Set shuffle', { shuffle });
storeActions.setShuffle(shuffle);
},
@@ -813,27 +735,20 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const shuffle = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].shuffle, {
category: LogCategory.PLAYER,
});
logger.debug('Shuffle');
storeActions.shuffle();
}, [storeActions]);
const shuffleAll = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].shuffleAll, {
category: LogCategory.PLAYER,
});
logger.debug('Shuffle all');
storeActions.shuffleAll();
}, [storeActions]);
const shuffleSelected = useCallback(
(items: QueueSong[]) => {
logFn.debug(logMsg[LogCategory.PLAYER].shuffleSelected, {
category: LogCategory.PLAYER,
meta: { items },
});
logger.debug('Shuffle selected', { items });
storeActions.shuffleSelected(items);
},
@@ -841,17 +756,13 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => {
);
const toggleRepeat = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].toggleRepeat, {
category: LogCategory.PLAYER,
});
logger.debug('Toggle repeat');
storeActions.toggleRepeat();
}, [storeActions]);
const toggleShuffle = useCallback(() => {
logFn.debug(logMsg[LogCategory.PLAYER].toggleShuffle, {
category: LogCategory.PLAYER,
});
logger.debug('Toggle shuffle');
storeActions.toggleShuffle();
}, [storeActions]);
@@ -16,8 +16,7 @@ import {
usePlayerStoreBase,
useSettingsStore,
} from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { hasFeature } from '/@/shared/api/utils';
import { LibraryItem } from '/@/shared/types/domain-types';
import { ServerFeature } from '/@/shared/types/features-types';
@@ -65,9 +64,9 @@ export const useAutoDJ = () => {
return;
}
logFn.debug(logMsg[LogCategory.PLAYER].autoPlayTriggered, {
category: LogCategory.PLAYER,
meta: { remaining: properties.remaining, songId: properties.song?.id },
logger.info('Auto play triggered', {
remaining: properties.remaining,
songId: properties.song?.id,
});
try {
@@ -143,9 +142,9 @@ export const useAutoDJ = () => {
});
}
} catch (error) {
logFn.error(logMsg[LogCategory.PLAYER].autoPlayFailed, {
category: LogCategory.PLAYER,
meta: { error: (error as Error).message, songId: properties.song?.id },
logger.error('Auto play failed', {
error: (error as Error).message,
songId: properties.song?.id,
});
}
},
@@ -14,8 +14,7 @@ import {
useSettingsStore,
useTimestampStoreBase,
} from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { hasFeature } from '/@/shared/api/utils';
import { LibraryItem, QueueSong, ServerType } from '/@/shared/types/domain-types';
import { ServerFeature } from '/@/shared/types/features-types';
@@ -211,12 +210,9 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledTimeupdate, {
category: LogCategory.SCROBBLE,
meta: {
id: song.id,
reason: 'after submission',
},
logger.debug('Scrobbled a timeupdate event', {
id: song.id,
reason: 'after submission',
});
},
},
@@ -305,8 +301,7 @@ export const useScrobble = () => {
// },
// {
// onSuccess: () => {
// logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledTimeupdate, {
// category: LogCategory.SCROBBLE,
// logFn.debug("Scrobbled a timeupdate event", {
// meta: {
// id: currentSong.id,
// },
@@ -342,12 +337,9 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledSubmission, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
reason: 'from listened time',
},
logger.info('Scrobbled a submission event', {
id: currentSong.id,
reason: 'from listened time',
});
sendProgressAfterSubmission(currentSong);
},
@@ -399,11 +391,8 @@ export const useScrobble = () => {
silent: true,
});
} catch (error) {
logFn.error('an error occurred while sending a desktop notification', {
category: LogCategory.SCROBBLE,
meta: {
error: error as Error,
},
logger.error('an error occurred while sending a desktop notification', {
error: error as Error,
});
}
}
@@ -447,11 +436,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledStart, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
},
logger.info('Scrobbled a start event', {
id: currentSong.id,
});
},
},
@@ -480,11 +466,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledStop, {
category: LogCategory.SCROBBLE,
meta: {
id: previousSong.id,
},
logger.info('Scrobbled a stop event', {
id: previousSong.id,
});
},
},
@@ -578,11 +561,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledTimeupdate, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
},
logger.debug('Scrobbled a timeupdate event', {
id: currentSong.id,
});
},
},
@@ -633,11 +613,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledPause, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
},
logger.debug('Scrobbled a pause event', {
id: currentSong.id,
});
},
},
@@ -661,11 +638,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledUnpause, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
},
logger.debug('Scrobbled an unpause event', {
id: currentSong.id,
});
},
},
@@ -694,11 +668,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledStart, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
},
logger.info('Scrobbled a start event', {
id: currentSong.id,
});
},
},
@@ -726,11 +697,8 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledStop, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
},
logger.info('Scrobbled a stop event', {
id: currentSong.id,
});
},
},
@@ -777,12 +745,9 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledStart, {
category: LogCategory.SCROBBLE,
meta: {
id: currentSong.id,
reason: 'from repeat',
},
logger.info('Scrobbled a start event', {
id: currentSong.id,
reason: 'from repeat',
});
},
},
@@ -840,12 +805,9 @@ export const useScrobble = () => {
},
{
onSuccess: () => {
logFn.debug(logMsg[LogCategory.SCROBBLE].scrobbledSubmission, {
category: LogCategory.SCROBBLE,
meta: {
id: song.id,
reason: 'forced from UI',
},
logger.info('Scrobbled a submission event', {
id: song.id,
reason: 'forced from UI',
});
sendProgressAfterSubmission(song);
},
@@ -6,7 +6,7 @@ import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { updateQueueSong } from '/@/renderer/store/player.store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logger } from '/@/renderer/utils/logger';
import { QueueSong, SongDetailQuery } from '/@/shared/types/domain-types';
export const useUpdateCurrentSong = () => {
@@ -43,22 +43,16 @@ export const useUpdateCurrentSong = () => {
if (!isEqual(currentSongData, updatedSong)) {
updateQueueSong(currentSong.id, updatedSong);
logFn.debug('Song updated in queue', {
category: LogCategory.PLAYER,
meta: {
id: currentSong.id,
name: updatedSong.name,
},
logger.debug('Song updated in queue', {
id: currentSong.id,
name: updatedSong.name,
});
}
}
} catch (error) {
logFn.error('Failed to update song in queue', {
category: LogCategory.PLAYER,
meta: {
error: error instanceof Error ? error.message : String(error),
id: currentSong.id,
},
logger.error('Failed to update song in queue', {
error: error instanceof Error ? error.message : String(error),
id: currentSong.id,
});
}
},
+15 -19
View File
@@ -4,8 +4,7 @@ import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { folderQueries } from '/@/renderer/features/folders/api/folder-api';
import { PlayerFilter, useSettingsStore } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { resolveSongPath } from '/@/renderer/utils/resolve-song-path';
import { sortSongList } from '/@/shared/api/utils';
import {
@@ -435,23 +434,20 @@ export const filterSongsByPlayerFilters = (songs: Song[], filters: PlayerFilter[
});
if (filteredSongs.length > 0) {
logFn.debug(logMsg[LogCategory.PLAYER].playerFiltersApplied, {
category: LogCategory.PLAYER,
meta: {
filteredCount: filteredSongs.length,
filteredSongs: filteredSongs.map(({ filter, song }) => ({
artist: song.artistName,
condition: {
field: filter.field,
operator: filter.operator,
value: filter.value,
},
songId: song.id,
songName: song.name,
})),
originalCount: songs.length,
remainingCount: filtered.length,
},
logger.debug('Player filters applied', {
filteredCount: filteredSongs.length,
filteredSongs: filteredSongs.map(({ filter, song }) => ({
artist: song.artistName,
condition: {
field: filter.field,
operator: filter.operator,
value: filter.value,
},
songId: song.id,
songName: song.name,
})),
originalCount: songs.length,
remainingCount: filtered.length,
});
}
@@ -7,8 +7,7 @@ import { useDeleteInternetRadioStationImage } from '/@/renderer/features/radio/m
import { useUpdateRadioStation } from '/@/renderer/features/radio/mutations/update-radio-station-mutation';
import { useUploadInternetRadioStationImage } from '/@/renderer/features/radio/mutations/upload-internet-radio-station-image-mutation';
import { useCurrentServer } from '/@/renderer/store';
import { logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { hasFeature } from '/@/shared/api/utils';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Box } from '/@/shared/components/box/box';
@@ -108,9 +107,7 @@ export const EditRadioStationForm = ({ onCancel, station }: EditRadioStationForm
});
closeAllModals();
} catch (err: unknown) {
logFn.error(logMsg.other.error, {
meta: { error: err as Error },
});
logger.error('An error occurred', { error: err as Error });
toast.error({
message: (err as Error)?.message,
@@ -7,8 +7,7 @@ import { useSetRating } from '/@/renderer/features/shared/hooks/use-set-rating';
import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
import { usePlayerActions, usePlayerStore, useRemoteSettings } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
import { logger } from '/@/renderer/utils/logger';
import { toast } from '/@/shared/components/toast/toast';
import { LibraryItem } from '/@/shared/types/domain-types';
import { PlayerShuffle } from '/@/shared/types/types';
@@ -32,13 +31,10 @@ export const useRemote = () => {
// we must send this EVEN IF the remote is disabled, as this is what
// makes sure that the main process gets the port/username/password on startup
logFn.debug(logMsg[LogCategory.REMOTE].initializingRemoteSettings, {
category: LogCategory.REMOTE,
meta: {
enabled: remoteSettings.enabled,
port: remoteSettings.port,
username: remoteSettings.username,
},
logger.info('Initializing remote settings', {
enabled: remoteSettings.enabled,
port: remoteSettings.port,
username: remoteSettings.username,
});
remote
@@ -49,10 +45,7 @@ export const useRemote = () => {
remoteSettings.password,
)
.catch((error) => {
logFn.error(logMsg[LogCategory.REMOTE].failedToEnableRemote, {
category: LogCategory.REMOTE,
meta: { error },
});
logger.error('Failed to enable remote', { error });
toast.warn({ message: error, title: 'Failed to enable remote' });
});
// We only want to fire this once
@@ -65,42 +58,35 @@ export const useRemote = () => {
}
remote.requestPosition((data: { position: number }) => {
logFn.debug(logMsg[LogCategory.REMOTE].requestPositionReceived, {
category: LogCategory.REMOTE,
meta: { position: data.position },
});
logger.debug('Request position received', { position: data.position });
const newTime = data.position;
player.mediaSeekToTimestamp(newTime);
});
remote.requestSeek((data: { offset: number }) => {
logFn.debug(logMsg[LogCategory.REMOTE].requestSeekReceived, {
category: LogCategory.REMOTE,
meta: { offset: data.offset },
});
logger.debug('Request seek received', { offset: data.offset });
mediaSkipForward(data.offset);
});
remote.requestRating((data: { id: string; rating: number; serverId: string }) => {
logFn.debug(logMsg[LogCategory.REMOTE].requestRatingReceived, {
category: LogCategory.REMOTE,
meta: { id: data.id, rating: data.rating, serverId: data.serverId },
logger.debug('Request rating received', {
id: data.id,
rating: data.rating,
serverId: data.serverId,
});
setRating(data.serverId, [data.id], LibraryItem.SONG, data.rating);
});
remote.requestVolume((data: { volume: number }) => {
logFn.debug(logMsg[LogCategory.REMOTE].requestVolumeReceived, {
category: LogCategory.REMOTE,
meta: { volume: data.volume },
});
logger.debug('Request volume received', { volume: data.volume });
setVolume(data.volume);
});
remote.requestFavorite((data: { favorite: boolean; id: string; serverId: string }) => {
logFn.debug(logMsg[LogCategory.REMOTE].requestFavoriteReceived, {
category: LogCategory.REMOTE,
meta: { favorite: data.favorite, id: data.id, serverId: data.serverId },
logger.debug('Request favorite received', {
favorite: data.favorite,
id: data.id,
serverId: data.serverId,
});
const mutator = data.favorite ? addToFavoritesMutation : removeFromFavoritesMutation;
mutator.mutate({
@@ -141,13 +127,10 @@ export const useRemote = () => {
const currentSong = player.getCurrentSong();
if (currentSong) {
logFn.debug(logMsg[LogCategory.REMOTE].sendingInitialSong, {
category: LogCategory.REMOTE,
meta: {
artistName: currentSong.artistName,
id: currentSong.id,
name: currentSong.name,
},
logger.debug('Sending initial song', {
artistName: currentSong.artistName,
id: currentSong.id,
name: currentSong.name,
});
const imageUrl =
@@ -171,14 +154,11 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updateSongSent, {
category: LogCategory.REMOTE,
meta: {
artistName: properties.song?.artistName,
id: properties.song?.id,
index: properties.index,
name: properties.song?.name,
},
logger.debug('Update song sent', {
artistName: properties.song?.artistName,
id: properties.song?.id,
index: properties.index,
name: properties.song?.name,
});
if (properties.song) {
const song = properties.song;
@@ -202,10 +182,7 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updatePositionSent, {
category: LogCategory.REMOTE,
meta: { timestamp: properties.timestamp },
});
logger.debug('Update position sent', { timestamp: properties.timestamp });
remote.updatePosition(properties.timestamp);
},
onPlayerRepeat: (properties) => {
@@ -213,10 +190,7 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updateRepeatSent, {
category: LogCategory.REMOTE,
meta: { repeat: properties.repeat },
});
logger.debug('Update repeat sent', { repeat: properties.repeat });
remote.updateRepeat(properties.repeat);
},
onPlayerShuffle: (properties) => {
@@ -225,9 +199,9 @@ export const useRemote = () => {
}
const isShuffleEnabled = properties.shuffle !== PlayerShuffle.NONE;
logFn.debug(logMsg[LogCategory.REMOTE].updateShuffleSent, {
category: LogCategory.REMOTE,
meta: { isShuffleEnabled, shuffle: properties.shuffle },
logger.debug('Update shuffle sent', {
isShuffleEnabled,
shuffle: properties.shuffle,
});
remote.updateShuffle(isShuffleEnabled);
},
@@ -236,10 +210,7 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updatePlaybackSent, {
category: LogCategory.REMOTE,
meta: { status: properties.status },
});
logger.debug('Update playback sent', { status: properties.status });
remote.updatePlayback(properties.status);
},
onPlayerVolume: (properties) => {
@@ -247,10 +218,7 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updateVolumeSent, {
category: LogCategory.REMOTE,
meta: { volume: properties.volume },
});
logger.debug('Update volume sent', { volume: properties.volume });
remote.updateVolume(properties.volume);
},
onUserFavorite: (properties) => {
@@ -258,13 +226,10 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updateFavoriteSent, {
category: LogCategory.REMOTE,
meta: {
favorite: properties.favorite,
id: properties.id,
serverId: properties.serverId,
},
logger.debug('Update favorite sent', {
favorite: properties.favorite,
id: properties.id,
serverId: properties.serverId,
});
remote.updateFavorite(properties.favorite, properties.serverId, properties.id);
},
@@ -273,13 +238,10 @@ export const useRemote = () => {
return;
}
logFn.debug(logMsg[LogCategory.REMOTE].updateRatingSent, {
category: LogCategory.REMOTE,
meta: {
id: properties.id,
rating: properties.rating || 0,
serverId: properties.serverId,
},
logger.debug('Update rating sent', {
id: properties.id,
rating: properties.rating || 0,
serverId: properties.serverId,
});
remote.updateRating(properties.rating || 0, properties.serverId, properties.id);
},
@@ -1,71 +1,160 @@
import { memo } from 'react';
import { ComboboxItem, ComboboxLikeRenderOptionInput } from '@mantine/core';
import isElectron from 'is-electron';
import { memo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
SettingOption,
SettingsSection,
} from '/@/renderer/features/settings/components/settings-section';
import { logFn, LogLevel } from '/@/renderer/utils/logger';
import { useCurrentServer, useSettingsStore } from '/@/renderer/store';
import { logger, LogLevel, normalizeLogLevel } from '/@/renderer/utils/logger';
import { Button } from '/@/shared/components/button/button';
import { Group } from '/@/shared/components/group/group';
import { Select } from '/@/shared/components/select/select';
import { Stack } from '/@/shared/components/stack/stack';
import { Text } from '/@/shared/components/text/text';
import { toast } from '/@/shared/components/toast/toast';
import { isLocalUrl } from '/@/shared/utils/is-local-url';
const DEFAULT_LOG_LEVEL: LogLevel = process.env.NODE_ENV === 'production' ? 'info' : 'debug';
const utils = isElectron() ? window.api.utils : null;
const LOG_LEVEL_DESCRIPTION_CONTEXT: Record<LogLevel, string> = {
debug: 'optionDebugDescription',
info: 'optionInfoDescription',
};
const LogLevelSelectOption = ({ option }: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
const { t } = useTranslation();
const level = normalizeLogLevel(option.value);
return (
<Stack gap={2} style={{ flex: 1, paddingBlock: 4 }}>
<Text fw={500}>{option.label}</Text>
<Text isMuted size="sm">
{t('setting.logLevel', {
context: LOG_LEVEL_DESCRIPTION_CONTEXT[level],
})}
</Text>
</Stack>
);
};
const getRendererSettingsForExport = (): Record<string, unknown> => {
const state = { ...useSettingsStore.getState() } as Record<string, unknown>;
delete state.actions;
return state;
};
export const LoggerSettings = memo(() => {
const { t } = useTranslation();
const currentServer = useCurrentServer();
const [isExporting, setIsExporting] = useState(false);
const getCurrentLogLevel = (): LogLevel => {
const stored = localStorage.getItem('log_level');
if (stored && ['debug', 'error', 'info', 'warn'].includes(stored)) {
return stored as LogLevel;
}
return DEFAULT_LOG_LEVEL;
return normalizeLogLevel(localStorage.getItem('log_level') ?? DEFAULT_LOG_LEVEL);
};
const handleLogLevelChange = (value: null | string) => {
if (!value) return;
const logLevel = value as LogLevel;
const logLevel = normalizeLogLevel(value);
localStorage.setItem('log_level', logLevel);
logger.updateLogLevel(logLevel);
};
// Update the logger dynamically
if (logFn.updateLogLevel) {
logFn.updateLogLevel(logLevel);
const handleOpenLogsFolder = async () => {
await utils?.openLogsFolder();
};
const handleExportDiagnostics = async () => {
if (!utils || isExporting) {
return;
}
setIsExporting(true);
try {
const result = await utils.exportDiagnostics({
logLevel: localStorage.getItem('log_level'),
rendererSettings: getRendererSettingsForExport(),
server: currentServer
? {
isAdmin: currentServer.isAdmin,
isLocalUrl: isLocalUrl(currentServer.url),
musicFolderId: currentServer.musicFolderId,
name: currentServer.name,
preferInstantMix: currentServer.preferInstantMix,
preferRemoteUrl: currentServer.preferRemoteUrl,
...(currentServer.remoteUrl
? {
isLocalRemoteUrl: isLocalUrl(currentServer.remoteUrl),
remoteUrl: '[Redacted]',
}
: {}),
type: currentServer.type,
url: '[Redacted]',
version: currentServer.version,
}
: null,
});
if (result.canceled) {
return;
}
} catch (error) {
toast.error({
message: (error as Error).message,
});
} finally {
setIsExporting(false);
}
};
const loggerOptions: SettingOption[] = [
{
control: (
<Select
data={[
{
label: t('setting.logLevel', {
context: 'optionDebug',
}),
value: 'debug',
},
{
label: t('setting.logLevel', {
context: 'optionInfo',
}),
value: 'info',
},
{
label: t('setting.logLevel', {
context: 'optionWarn',
}),
value: 'warn',
},
{
label: t('setting.logLevel', {
context: 'optionError',
}),
value: 'error',
},
]}
defaultValue={getCurrentLogLevel()}
onChange={handleLogLevelChange}
/>
<Stack>
<Select
data={[
{
label: t('setting.logLevel', {
context: 'optionInfo',
}),
value: 'info',
},
{
label: t('setting.logLevel', {
context: 'optionDebug',
}),
value: 'debug',
},
]}
defaultValue={getCurrentLogLevel()}
onChange={handleLogLevelChange}
renderOption={LogLevelSelectOption}
width={240}
/>
{utils && (
<Group gap="xs" justify="flex-end" wrap="nowrap">
<Button
loading={isExporting}
onClick={handleExportDiagnostics}
size="compact-sm"
variant="subtle"
>
{t('setting.exportDiagnostics')}
</Button>
<Button
onClick={handleOpenLogsFolder}
size="compact-sm"
variant="subtle"
>
{t('common.openFolder', { postProcess: 'titleCase' })}
</Button>
</Group>
)}
</Stack>
),
description: t('setting.logLevel', {
context: 'description',
@@ -9,12 +9,14 @@ import {
} from '/@/renderer/features/settings/components/settings-section';
import { useCurrentServer, usePlaybackType, usePlayerStatus } from '/@/renderer/store';
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
import { logger } from '/@/renderer/utils/logger';
import { hasFeature } from '/@/shared/api/utils';
import { Select } from '/@/shared/components/select/select';
import { Switch } from '/@/shared/components/switch/switch';
import { toast } from '/@/shared/components/toast/toast';
import { ServerFeature } from '/@/shared/types/features-types';
import { PlayerStatus, PlayerType } from '/@/shared/types/types';
const ipc = isElectron() ? window.api.ipc : null;
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
@@ -25,14 +27,13 @@ const getAudioDevices = async () => {
const getMpvAudioDevices = async () => {
if (!mpvPlayer) {
console.log('mpvPlayer not found');
return [];
}
try {
return await mpvPlayer.getAudioDevices();
} catch (error) {
console.error('Failed to get MPV audio devices:', error);
logger.error('Failed to get MPV audio devices:', error);
return [];
}
};
@@ -162,7 +162,6 @@ export const PlaylistRowButton = memo(
};
},
onDrag: () => {
console.log('started drag');
return;
},
onDragLeave: () => {