mirror of
https://github.com/jeffvli/feishin.git
synced 2026-08-09 13:53:10 +02:00
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:
@@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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: () => {
|
||||
|
||||
Reference in New Issue
Block a user