From ad5485506d87bdd2c4a463159da1427e88f22bca Mon Sep 17 00:00:00 2001 From: jeffvli Date: Mon, 15 Dec 2025 01:44:31 -0800 Subject: [PATCH] include select settings values in analytics --- .../analytics/hooks/use-app-tracker.ts | 300 ++++++++++-------- src/renderer/utils/logger-message.ts | 2 +- 2 files changed, 169 insertions(+), 133 deletions(-) diff --git a/src/renderer/features/analytics/hooks/use-app-tracker.ts b/src/renderer/features/analytics/hooks/use-app-tracker.ts index a6daa8502..069bac199 100644 --- a/src/renderer/features/analytics/hooks/use-app-tracker.ts +++ b/src/renderer/features/analytics/hooks/use-app-tracker.ts @@ -9,13 +9,27 @@ dayjs.extend(utc); import packageJson from '../../../../../package.json'; import { isAnalyticsDisabled } from '/@/renderer/features/analytics/hooks/use-analytics-disabled'; -import { useAuthStore } from '/@/renderer/store'; +import { + PlayerbarSliderType, + SideQueueType, + useAuthStore, + usePlayerStore, + useSettingsStore, +} from '/@/renderer/store'; import { LogCategory, logFn } from '/@/renderer/utils/logger'; import { logMsg } from '/@/renderer/utils/logger-message'; -import { ServerType } from '/@/shared/types/domain-types'; -import { Platform } from '/@/shared/types/types'; +import { LyricSource, ServerType } from '/@/shared/types/domain-types'; +import { + FontType, + Platform, + PlayerQueueType, + PlayerStyle, + PlayerType, +} from '/@/shared/types/types'; const utils = isElectron() ? window.api.utils : null; +let appTrackerInFlight = false; +let appTrackerLastSentDate: null | string = null; const getVersion = (): AppTrackerProperties['_version'] => { return packageJson.version; @@ -41,137 +55,153 @@ const getPlatform = (): AppTrackerProperties['_platform'] => { return 'unknown'; }; -type AppTrackerProperties = { - _platform: 'unknown' | Platform; - _version: string; - // player: { - // mediaSession: boolean; - // playerQueueType: PlayerQueueType; - // playerStyle: PlayerStyle; - // playerType: PlayerType; - // transcoding: boolean; - // webAudio: boolean; - // }; - server: { - [ServerType.JELLYFIN]?: boolean; - [ServerType.NAVIDROME]?: boolean; - [ServerType.SUBSONIC]?: boolean; +type AppTrackerProperties = PlayerProperties & + SettingsProperties & { + _platform: 'unknown' | Platform; + _server: 'unknown' | ServerType; + _version: string; }; - // settings: { - // albumBackground: boolean; - // albumBackgroundBlur: number; - // artistBackground: boolean; - // artistBackgroundBlur: number; - // customCss: boolean; - // disableAutoUpdate: boolean; - // discord: boolean; - // exitToTray: boolean; - // fontType: FontType; - // globalHotkeys: boolean; - // homeFeature: boolean; - // language: string; - // lastFM: boolean; - // lyricsEnableAutoTranslation: boolean; - // lyricsEnableNeteaseTranslation: boolean; - // lyricsFetch: boolean; - // minimizeToTray: boolean; - // musicBrainz: boolean; - // nativeAspectRatio: boolean; - // playerbarSliderType: PlayerbarSliderType; - // playerbarWaveformAlign: BarAlign; - // playerbarWaveformBarWidth: number; - // playerbarWaveformGap: number; - // playerbarWaveformRadius: number; - // preventSleepOnPlayback: boolean; - // releaseChannel: string; - // resume: boolean; - // scrobbleEnabled: boolean; - // sideQueueType: SideQueueType; - // skipBackwardSeconds: number; - // skipButtons: boolean; - // skipForwardSeconds: number; - // startMinimized: boolean; - // theme: string; - // tray: boolean; - // windowBarStyle: Platform; - // zoomFactor: number; - // }; + +type PlayerProperties = { + 'player.mediaSession': boolean; + 'player.queueType': PlayerQueueType; + 'player.style': PlayerStyle; + 'player.transcoding': boolean; + 'player.type': PlayerType; + 'player.webAudio': boolean; }; -// const getPlayerProperties = (): AppTrackerProperties['player'] => { -// const player = usePlayerStore.getState(); -// const playbackSettings = useSettingsStore.getState().playback; +type SettingsProperties = { + 'settings.albumBackground': boolean; + 'settings.artistBackground': boolean; + 'settings.autoDJ': boolean; + 'settings.autoDJItemCount': number; + 'settings.autoDJTiming': number; + 'settings.customCss': boolean; + 'settings.disableAutoUpdate': boolean; + 'settings.discord': boolean; + 'settings.exitToTray': boolean; + 'settings.followSystemTheme': boolean; + 'settings.fontType': FontType; + 'settings.globalHotkeys': boolean; + 'settings.homeFeature': boolean; + 'settings.language': string; + 'settings.lyrics.enableAutoTranslation': boolean; + 'settings.lyrics.enableNeteaseTranslation': boolean; + 'settings.lyrics.fetch': boolean; + 'settings.lyrics.sources.genius': boolean; + 'settings.lyrics.sources.lrclib': boolean; + 'settings.lyrics.sources.netease': boolean; + 'settings.minimizeToTray': boolean; + 'settings.nativeAspectRatio': boolean; + 'settings.playerbarSliderType': PlayerbarSliderType; + 'settings.preventSleepOnPlayback': boolean; + 'settings.releaseChannel': string; + 'settings.resume': boolean; + 'settings.scrobble.enabled': boolean; + 'settings.scrobble.notify': boolean; + 'settings.showLyricsInSidebar': boolean; + 'settings.showVisualizerInSidebar': boolean; + 'settings.sideQueueType': SideQueueType; + 'settings.skipButtons': boolean; + 'settings.startMinimized': boolean; + 'settings.theme': string; + 'settings.themeDark': string; + 'settings.themeLight': string; + 'settings.tray': boolean; + 'settings.useThemeAccentColor': boolean; + 'settings.windowBarStyle': Platform; + 'settings.zoomFactor': number; +}; -// return { -// mediaSession: playbackSettings.mediaSession, -// playerQueueType: player.player.queueType, -// playerStyle: player.player.transitionType, -// playerType: playbackSettings.type, -// transcoding: playbackSettings.transcode.enabled, -// webAudio: playbackSettings.webAudio, -// }; -// }; +const getPlayerProperties = (): Pick< + AppTrackerProperties, + | 'player.mediaSession' + | 'player.queueType' + | 'player.style' + | 'player.transcoding' + | 'player.type' + | 'player.webAudio' +> => { + const player = usePlayerStore.getState(); + const playbackSettings = useSettingsStore.getState().playback; -// const getSettingsProperties = (): AppTrackerProperties['settings'] => { -// const settings = useSettingsStore.getState(); + return { + 'player.mediaSession': playbackSettings.mediaSession, + 'player.queueType': player.player.queueType, + 'player.style': player.player.transitionType, + 'player.transcoding': playbackSettings.transcode.enabled, + 'player.type': playbackSettings.type, + 'player.webAudio': playbackSettings.webAudio, + }; +}; -// return { -// albumBackground: settings.general.albumBackground, -// albumBackgroundBlur: settings.general.albumBackgroundBlur, -// artistBackground: settings.general.artistBackground, -// artistBackgroundBlur: settings.general.artistBackgroundBlur, -// customCss: settings.css.enabled, -// disableAutoUpdate: settings.window.disableAutoUpdate, -// discord: settings.discord.enabled, -// exitToTray: settings.window.exitToTray, -// fontType: settings.font.type, -// globalHotkeys: settings.hotkeys.globalMediaHotkeys, -// homeFeature: settings.general.homeFeature, -// language: settings.general.language, -// lastFM: settings.general.lastFM, -// lyricsEnableAutoTranslation: settings.lyrics.enableAutoTranslation, -// lyricsEnableNeteaseTranslation: settings.lyrics.enableNeteaseTranslation, -// lyricsFetch: settings.lyrics.fetch, -// minimizeToTray: settings.window.minimizeToTray, -// musicBrainz: settings.general.musicBrainz, -// nativeAspectRatio: settings.general.nativeAspectRatio, -// playerbarSliderType: settings.general.playerbarSlider.type as PlayerbarSliderType, -// playerbarWaveformAlign: settings.general.playerbarSlider.barAlign as BarAlign, -// playerbarWaveformBarWidth: settings.general.playerbarSlider.barWidth, -// playerbarWaveformGap: settings.general.playerbarSlider.barGap, -// playerbarWaveformRadius: settings.general.playerbarSlider.barRadius, -// preventSleepOnPlayback: settings.window.preventSleepOnPlayback, -// releaseChannel: settings.window.releaseChannel, -// resume: settings.general.resume, -// scrobbleEnabled: settings.playback.scrobble.enabled, -// sideQueueType: settings.general.sideQueueType, -// skipBackwardSeconds: settings.general.skipButtons.skipBackwardSeconds, -// skipButtons: settings.general.skipButtons.enabled, -// skipForwardSeconds: settings.general.skipButtons.skipForwardSeconds, -// startMinimized: settings.window.startMinimized, -// theme: settings.general.theme, -// tray: settings.window.tray, -// windowBarStyle: settings.window.windowBarStyle, -// zoomFactor: settings.general.zoomFactor, -// }; -// }; +const getSettingsProperties = (): SettingsProperties => { + const settings = useSettingsStore.getState(); -const getServerProperties = (): AppTrackerProperties['server'] => { + return { + 'settings.albumBackground': settings.general.albumBackground, + // 'settings.albumBackgroundBlur': settings.general.albumBackgroundBlur, + 'settings.artistBackground': settings.general.artistBackground, + // 'settings.artistBackgroundBlur': settings.general.artistBackgroundBlur, + 'settings.autoDJ': settings.autoDJ.enabled, + 'settings.autoDJItemCount': settings.autoDJ.itemCount, + 'settings.autoDJTiming': settings.autoDJ.timing, + 'settings.customCss': settings.css.enabled, + 'settings.disableAutoUpdate': settings.window.disableAutoUpdate, + 'settings.discord': settings.discord.enabled, + 'settings.exitToTray': settings.window.exitToTray, + 'settings.followSystemTheme': settings.general.followSystemTheme, + 'settings.fontType': settings.font.type, + 'settings.globalHotkeys': settings.hotkeys.globalMediaHotkeys, + 'settings.homeFeature': settings.general.homeFeature, + 'settings.language': settings.general.language, + // 'settings.lastFM': settings.general.lastFM, + 'settings.lyrics.enableAutoTranslation': settings.lyrics.enableAutoTranslation, + 'settings.lyrics.enableNeteaseTranslation': settings.lyrics.enableNeteaseTranslation, + 'settings.lyrics.fetch': settings.lyrics.fetch, + 'settings.lyrics.sources.genius': settings.lyrics.sources.includes(LyricSource.GENIUS), + 'settings.lyrics.sources.lrclib': settings.lyrics.sources.includes(LyricSource.LRCLIB), + 'settings.lyrics.sources.netease': settings.lyrics.sources.includes(LyricSource.NETEASE), + 'settings.minimizeToTray': settings.window.minimizeToTray, + // 'settings.musicBrainz': settings.general.musicBrainz, + 'settings.nativeAspectRatio': settings.general.nativeAspectRatio, + 'settings.playerbarSliderType': settings.general.playerbarSlider + .type as PlayerbarSliderType, + // 'settings.playerbarWaveformAlign': settings.general.playerbarSlider.barAlign as BarAlign, + // 'settings.playerbarWaveformBarWidth': settings.general.playerbarSlider.barWidth, + // 'settings.playerbarWaveformGap': settings.general.playerbarSlider.barGap, + // 'settings.playerbarWaveformRadius': settings.general.playerbarSlider.barRadius, + 'settings.preventSleepOnPlayback': settings.window.preventSleepOnPlayback, + 'settings.releaseChannel': settings.window.releaseChannel, + 'settings.resume': settings.general.resume, + 'settings.scrobble.enabled': settings.playback.scrobble.enabled, + 'settings.scrobble.notify': settings.playback.scrobble.notify, + 'settings.showLyricsInSidebar': settings.general.showLyricsInSidebar, + 'settings.showVisualizerInSidebar': settings.general.showVisualizerInSidebar, + 'settings.sideQueueType': settings.general.sideQueueType, + // 'settings.skipBackwardSeconds': settings.general.skipButtons.skipBackwardSeconds, + 'settings.skipButtons': settings.general.skipButtons.enabled, + // 'settings.skipForwardSeconds': settings.general.skipButtons.skipForwardSeconds, + 'settings.startMinimized': settings.window.startMinimized, + 'settings.theme': settings.general.theme, + 'settings.themeDark': settings.general.themeDark, + 'settings.themeLight': settings.general.themeLight, + 'settings.tray': settings.window.tray, + 'settings.useThemeAccentColor': settings.general.useThemeAccentColor, + 'settings.windowBarStyle': settings.window.windowBarStyle, + 'settings.zoomFactor': settings.general.zoomFactor, + }; +}; + +const getServer = (): 'unknown' | ServerType => { const auth = useAuthStore.getState(); - const serverList = auth.serverList; - - const properties: AppTrackerProperties['server'] = {}; - - Object.values(serverList).forEach((server) => { - properties[server.type] = true; - }); - - return properties; + const currentServer = auth.currentServer; + return currentServer?.type || 'unknown'; }; export const useAppTracker = () => { const { mutate: trackAppMutation } = useMutation(appTrackerMutation); - const isTrackingInProgressRef = useRef(false); const hasRunOnMountRef = useRef(false); useEffect(() => { @@ -182,16 +212,16 @@ export const useAppTracker = () => { const getProperties = () => { const platform = getPlatform(); const version = getVersion(); - const serverProperties = getServerProperties(); - // const playerProperties = getPlayerProperties(); - // const settingsProperties = getSettingsProperties(); + const server = getServer(); + const playerProperties = getPlayerProperties(); + const settingsProperties = getSettingsProperties(); const properties: AppTrackerProperties = { _platform: platform, + _server: server, _version: version, - server: serverProperties, - // player: playerProperties, - // settings: settingsProperties, + ...playerProperties, + ...settingsProperties, }; return properties; @@ -199,26 +229,32 @@ export const useAppTracker = () => { const checkAndTrack = () => { // Prevent multiple simultaneous requests - if (isTrackingInProgressRef.current) { + if (appTrackerInFlight) { return; } const lastSentDate = localStorage.getItem('analytics_app_tracker_timestamp'); + const lastTrackedDate = appTrackerLastSentDate ?? lastSentDate; const todayUTC = dayjs.utc().format('YYYY-MM-DD'); // Only send if it's a new day in UTC (ensures once per 24 hours) - if (lastSentDate !== todayUTC) { - isTrackingInProgressRef.current = true; + if (lastTrackedDate !== todayUTC) { + appTrackerInFlight = true; const properties = getProperties(); + logFn.info(logMsg[LogCategory.ANALYTICS].appTracked, { + category: LogCategory.ANALYTICS, + meta: { properties, todayUTC }, + }); trackAppMutation(properties, { onError: () => {}, onSettled: () => { - isTrackingInProgressRef.current = false; + appTrackerInFlight = false; }, onSuccess: () => { // Only update timestamp on success to ensure we only send once per 24 hours const utcDate = dayjs.utc().format('YYYY-MM-DD'); + appTrackerLastSentDate = utcDate; localStorage.setItem('analytics_app_tracker_timestamp', utcDate); logFn.debug(logMsg[LogCategory.ANALYTICS].appTracked, { diff --git a/src/renderer/utils/logger-message.ts b/src/renderer/utils/logger-message.ts index 2b5e82197..b3373b84a 100644 --- a/src/renderer/utils/logger-message.ts +++ b/src/renderer/utils/logger-message.ts @@ -2,7 +2,7 @@ import { LogCategory } from '/@/renderer/utils/logger'; export const logMsg = { [LogCategory.ANALYTICS]: { - appTracked: 'App tracked', + appTracked: 'Analytics sent', pageViewTracked: 'Page view tracked', }, [LogCategory.API]: {},