diff --git a/js/analytics.js b/js/analytics.js index 43a5ace..d262fe3 100644 --- a/js/analytics.js +++ b/js/analytics.js @@ -34,722 +34,10 @@ export function trackPageView(path) { trackEvent('pageview', { path }); } -// Playback Events -export function trackPlayTrack(track) { - trackEvent('Play Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - album: track?.album?.title || 'Unknown', - duration: track?.duration || 0, - quality: track?.audioQuality || track?.quality || 'Unknown', - is_local: track?.isLocal || false, - is_explicit: track?.explicit || false, - track_number: track?.trackNumber || 0, - year: track?.album?.releaseYear || track?.album?.releaseDate || 'unknown', - }); -} - -export function trackPauseTrack(track) { - trackEvent('Pause Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - album: track?.album?.title || 'Unknown', - }); -} - -export function trackSkipTrack(track, direction) { - trackEvent('Skip Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - album: track?.album?.title || 'Unknown', - direction: direction, - }); -} - -export function trackToggleShuffle(enabled) { - trackEvent('Toggle Shuffle', { enabled }); -} - -export function trackToggleRepeat(mode) { - trackEvent('Toggle Repeat', { mode }); -} - -export function trackTrackComplete(track, completionPercent) { - trackEvent('Track Complete', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - album: track?.album?.title || 'Unknown', - duration: track?.duration || 0, - completion_percent: completionPercent || 100, - }); -} - -export function trackSetVolume(level) { - // Only track volume changes at coarse intervals to avoid spam - const roundedLevel = Math.round(level * 10) / 10; - trackEvent('Set Volume', { level: roundedLevel }); -} - -export function trackToggleMute(muted) { - trackEvent('Toggle Mute', { muted }); -} - -// Track listening progress milestones (10%, 50%, 90%, 100%) -export function trackListeningProgress(track, percent) { - trackEvent('Listening Progress', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - percent: percent, - }); -} - -// Search Events -export function trackSearch(query, resultsCount) { - trackEvent('Search', { - query_length: query?.length || 0, - has_results: resultsCount > 0, - results_count: resultsCount, - }); -} - -export function trackSearchTabChange(tab) { - trackEvent('Search Tab Change', { tab }); -} - -// Navigation Events -export function trackNavigate(path, pageType) { - trackEvent('Navigate', { - path, - page_type: pageType, - }); -} - -export function trackSidebarNavigation(item) { - trackEvent('Sidebar Navigation', { item }); -} - -// Library Events -export function trackLikeTrack(track) { - trackEvent('Like Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - album: track?.album?.title || 'Unknown', - }); -} - -export function trackUnlikeTrack(track) { - trackEvent('Unlike Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - }); -} - -export function trackLikeAlbum(album) { - trackEvent('Like Album', { - album_title: album?.title || 'Unknown', - artist: album?.artist?.name || 'Unknown', - }); -} - -export function trackUnlikeAlbum(album) { - trackEvent('Unlike Album', { - album_title: album?.title || 'Unknown', - }); -} - -export function trackLikeArtist(artist) { - trackEvent('Like Artist', { - artist_name: artist?.name || 'Unknown', - }); -} - -export function trackUnlikeArtist(artist) { - trackEvent('Unlike Artist', { - artist_name: artist?.name || 'Unknown', - }); -} - -export function trackLikePlaylist(playlist) { - trackEvent('Like Playlist', { - playlist_name: playlist?.title || playlist?.name || 'Unknown', - }); -} - -export function trackUnlikePlaylist(playlist) { - trackEvent('Unlike Playlist', { - playlist_name: playlist?.title || playlist?.name || 'Unknown', - }); -} - -// Playlist Management Events -export function trackCreatePlaylist(playlist, source) { - trackEvent('Create Playlist', { - playlist_name: playlist?.name || 'Unknown', - track_count: playlist?.tracks?.length || 0, - is_public: playlist?.isPublic || false, - source: source || 'manual', - }); -} - -export function trackEditPlaylist(playlist) { - trackEvent('Edit Playlist', { - playlist_name: playlist?.name || 'Unknown', - }); -} - -export function trackDeletePlaylist(playlistName) { - trackEvent('Delete Playlist', { playlist_name: playlistName }); -} - -export function trackAddToPlaylist(track, playlist) { - trackEvent('Add to Playlist', { - track_title: track?.title || 'Unknown', - playlist_name: playlist?.name || 'Unknown', - }); -} - -export function trackRemoveFromPlaylist(track, playlist) { - trackEvent('Remove from Playlist', { - track_title: track?.title || 'Unknown', - playlist_name: playlist?.name || 'Unknown', - }); -} - -export function trackCreateFolder(folder) { - trackEvent('Create Folder', { - folder_name: folder?.name || 'Unknown', - }); -} - -export function trackDeleteFolder(folderName) { - trackEvent('Delete Folder', { folder_name: folderName }); -} - -// Playback Actions -export function trackPlayAlbum(album, shuffle) { - trackEvent('Play Album', { - album_id: album?.id || 'unknown', - album_title: album?.title || 'Unknown', - artist_id: album?.artist?.id || 'unknown', - artist: album?.artist?.name || 'Unknown', - shuffle: shuffle || false, - track_count: album?.numberOfTracks || album?.tracks?.length || 0, - year: album?.releaseYear || album?.releaseDate || 'unknown', - }); -} - -export function trackPlayPlaylist(playlist, shuffle) { - trackEvent('Play Playlist', { - playlist_id: playlist?.id || 'unknown', - playlist_name: playlist?.title || playlist?.name || 'Unknown', - shuffle: shuffle || false, - track_count: playlist?.tracks?.length || 0, - is_public: playlist?.isPublic || false, - }); -} - -export function trackPlayArtistRadio(artist) { - trackEvent('Play Artist Radio', { - artist_id: artist?.id || 'unknown', - artist_name: artist?.name || 'Unknown', - }); -} - -export function trackShuffleLikedTracks(count) { - trackEvent('Shuffle Liked Tracks', { track_count: count }); -} - -// Download Events -export function trackDownloadTrack(track, quality) { - trackEvent('Download Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - quality: quality || 'Unknown', - }); -} - -export function trackDownloadAlbum(album, quality) { - trackEvent('Download Album', { - album_id: album?.id || 'unknown', - album_title: album?.title || 'Unknown', - artist_id: album?.artist?.id || 'unknown', - artist: album?.artist?.name || 'Unknown', - track_count: album?.numberOfTracks || album?.tracks?.length || 0, - quality: quality || 'Unknown', - }); -} - -export function trackDownloadPlaylist(playlist, quality) { - trackEvent('Download Playlist', { - playlist_id: playlist?.id || 'unknown', - playlist_name: playlist?.title || playlist?.name || 'Unknown', - track_count: playlist?.tracks?.length || 0, - quality: quality || 'Unknown', - }); -} - -export function trackDownloadLikedTracks(count, quality) { - trackEvent('Download Liked Tracks', { - track_count: count, - quality: quality || 'Unknown', - }); -} - -export function trackDownloadDiscography(artist, selection) { - trackEvent('Download Discography', { - artist_id: artist?.id || 'unknown', - artist_name: artist?.name || 'Unknown', - include_albums: selection?.includeAlbums || false, - include_eps: selection?.includeEPs || false, - include_singles: selection?.includeSingles || false, - }); -} - -// Queue Management -export function trackAddToQueue(track, position) { - trackEvent('Add to Queue', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - position: position || 'end', - }); -} - -export function trackPlayNext(track) { - trackEvent('Play Next', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - }); -} - -export function trackClearQueue() { - trackEvent('Clear Queue'); -} - -export function trackShuffleQueue() { - trackEvent('Shuffle Queue'); -} - -// Context Menu Actions -export function trackContextMenuAction(action, itemType, item) { - trackEvent('Context Menu Action', { - action, - item_type: itemType, - item_name: item?.title || item?.name || 'Unknown', - }); -} - -export function trackBlockTrack(track) { - trackEvent('Block Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - artist_id: track?.artist?.id || track?.artists?.[0]?.id || 'unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - album_id: track?.album?.id || 'unknown', - }); -} - -export function trackUnblockTrack(track) { - trackEvent('Unblock Track', { - track_id: track?.id || 'unknown', - track_title: track?.title || 'Unknown', - }); -} - -export function trackBlockAlbum(album) { - trackEvent('Block Album', { - album_id: album?.id || 'unknown', - album_title: album?.title || 'Unknown', - artist_id: album?.artist?.id || 'unknown', - }); -} - -export function trackUnblockAlbum(album) { - trackEvent('Unblock Album', { - album_id: album?.id || 'unknown', - album_title: album?.title || 'Unknown', - }); -} - -export function trackBlockArtist(artist) { - trackEvent('Block Artist', { - artist_id: artist?.id || 'unknown', - artist_name: artist?.name || 'Unknown', - }); -} - -export function trackUnblockArtist(artist) { - trackEvent('Unblock Artist', { - artist_id: artist?.id || 'unknown', - artist_name: artist?.name || 'Unknown', - }); -} - -export function trackCopyLink(type, id) { - trackEvent('Copy Link', { type, id }); -} - -export function trackOpenInNewTab(type, id) { - trackEvent('Open in New Tab', { type, id }); -} - -// Lyrics Events -export function trackOpenLyrics(track) { - trackEvent('Open Lyrics', { - track_title: track?.title || 'Unknown', - artist: track?.artist?.name || track?.artists?.[0]?.name || 'Unknown', - }); -} - -export function trackCloseLyrics(track) { - trackEvent('Close Lyrics', { - track_title: track?.title || 'Unknown', - }); -} - -// Fullscreen/Cover View Events -export function trackOpenFullscreenCover(track) { - trackEvent('Open Fullscreen Cover', { - track_title: track?.title || 'Unknown', - }); -} - -export function trackCloseFullscreenCover() { - trackEvent('Close Fullscreen Cover'); -} - -export function trackToggleVisualizer(enabled) { - trackEvent('Toggle Visualizer', { enabled }); -} - -export function trackToggleLyricsFullscreen(enabled) { - trackEvent('Toggle Lyrics Fullscreen', { enabled }); -} - -// Settings Events -export function trackChangeSetting(setting, value) { - trackEvent('Change Setting', { - setting, - value: typeof value === 'object' ? JSON.stringify(value) : String(value), - }); -} - -export function trackChangeTheme(theme) { - trackEvent('Change Theme', { theme }); -} - -export function trackChangeQuality(type, quality) { - trackEvent('Change Quality', { type, quality }); -} - -export function trackChangeVolume(volume) { - trackEvent('Change Volume', { volume: Math.round(volume * 100) }); -} - -export function trackToggleScrobbler(service, enabled) { - trackEvent('Toggle Scrobbler', { service, enabled }); -} - -export function trackConnectScrobbler(service) { - trackEvent('Connect Scrobbler', { service }); -} - -export function trackDisconnectScrobbler(service) { - trackEvent('Disconnect Scrobbler', { service }); -} - -// Local Files Events -export function trackSelectLocalFolder(fileCount) { - trackEvent('Select Local Folder', { file_count: fileCount }); -} - -export function trackPlayLocalFile(track) { - trackEvent('Play Local File', { - track_title: track?.title || 'Unknown', - }); -} - -export function trackChangeLocalFolder() { - trackEvent('Change Local Folder'); -} - -// Import/Export Events -export function trackImportCSV(playlistName, trackCount, missingCount) { - trackEvent('Import CSV', { - playlist_name: playlistName, - track_count: trackCount, - missing_count: missingCount, - }); -} - -export function trackImportJSPF(playlistName, trackCount, missingCount, source) { - trackEvent('Import JSPF', { - playlist_name: playlistName, - track_count: trackCount, - missing_count: missingCount, - source: source || 'unknown', - }); -} - -export function trackImportXSPF(playlistName, trackCount, missingCount) { - trackEvent('Import XSPF', { - playlist_name: playlistName, - track_count: trackCount, - missing_count: missingCount, - }); -} - -export function trackImportXML(playlistName, trackCount, missingCount) { - trackEvent('Import XML', { - playlist_name: playlistName, - track_count: trackCount, - missing_count: missingCount, - }); -} - -export function trackImportM3U(playlistName, trackCount, missingCount) { - trackEvent('Import M3U', { - playlist_name: playlistName, - track_count: trackCount, - missing_count: missingCount, - }); -} - -// Sleep Timer Events -export function trackSetSleepTimer(minutes) { - trackEvent('Set Sleep Timer', { minutes }); -} - -export function trackCancelSleepTimer() { - trackEvent('Cancel Sleep Timer'); -} - -// History Events -export function trackClearHistory() { - trackEvent('Clear History'); -} - -export function trackClearRecent() { - trackEvent('Clear Recent'); -} - -// Casting Events -export function trackStartCasting(deviceType) { - trackEvent('Start Casting', { device_type: deviceType }); -} - -export function trackStopCasting() { - trackEvent('Stop Casting'); -} - -// Keyboard Shortcuts -export function trackKeyboardShortcut(key) { - trackEvent('Keyboard Shortcut', { key }); -} - -// Pinning Events -export function trackPinItem(type, item) { - trackEvent('Pin Item', { - type, - item_name: item?.title || item?.name || 'Unknown', - }); -} - -export function trackUnpinItem(type, item) { - trackEvent('Unpin Item', { - type, - item_name: item?.title || item?.name || 'Unknown', - }); -} - -// Side Panel Events -export function trackOpenSidePanel(panelType) { - trackEvent('Open Side Panel', { panel_type: panelType }); -} - -export function trackCloseSidePanel() { - trackEvent('Close Side Panel'); -} - -// Queue Panel Events -export function trackOpenQueue() { - trackEvent('Open Queue'); -} - -export function trackCloseQueue() { - trackEvent('Close Queue'); -} - -// Mix Events -export function trackStartMix(sourceType, source) { - trackEvent('Start Mix', { - source_type: sourceType, - source_name: source?.title || source?.name || 'Unknown', - }); -} - -export function trackPlayMix(mixId) { - trackEvent('Play Mix', { mix_id: mixId }); -} - -// Search History Events -export function trackClearSearchHistory() { - trackEvent('Clear Search History'); -} - -export function trackClickSearchHistory(query) { - trackEvent('Click Search History', { query_length: query?.length || 0 }); -} - -// PWA/Update Events -export function trackPwaInstall() { - trackEvent('PWA Install'); -} - -export function trackPwaUpdate() { - trackEvent('PWA Update'); -} - -export function trackDismissUpdate() { - trackEvent('Dismiss Update'); -} - -// Sort Events -export function trackChangeSort(sortType) { - trackEvent('Change Sort', { sort_type: sortType }); -} - -// Modal Events -export function trackOpenModal(modalName) { - trackEvent('Open Modal', { modal_name: modalName }); -} - -export function trackCloseModal(modalName) { - trackEvent('Close Modal', { modal_name: modalName }); -} - -// Sharing Events -export function trackSharePlaylist(playlist, isPublic) { - trackEvent('Share Playlist', { - playlist_name: playlist?.name || 'Unknown', - is_public: isPublic, - }); -} - -// Audio Effects Events -export function trackChangePlaybackSpeed(speed) { - trackEvent('Change Playback Speed', { speed }); -} - -export function trackToggleReplayGain(mode) { - trackEvent('Toggle ReplayGain', { mode }); -} - -export function trackChangeEqualizer(preset) { - trackEvent('Change Equalizer', { preset }); -} - -// Waveform Events -export function trackToggleWaveform(enabled) { - trackEvent('Toggle Waveform', { enabled }); -} - -// Error Events -export function trackPlaybackError(errorType, track) { - trackEvent('Playback Error', { - error_type: errorType, - track_title: track?.title || 'Unknown', - }); -} - -export function trackSearchError(query) { - trackEvent('Search Error', { query_length: query?.length || 0 }); -} - -export function trackApiError(endpoint) { - trackEvent('API Error', { endpoint }); -} - -// Feature Discovery Events -export function trackViewFeature(feature) { - trackEvent('View Feature', { feature }); -} - -export function trackUseFeature(feature) { - trackEvent('Use Feature', { feature }); -} - -// Session Events -export function trackSessionStart() { - trackEvent('Session Start', { - user_agent: navigator.userAgent, - screen_width: window.screen.width, - screen_height: window.screen.height, - language: navigator.language, - }); -} - -export function trackSessionEnd(duration) { - trackEvent('Session End', { duration }); -} - // Initialize analytics on page load export function initAnalytics() { if (!isAnalyticsEnabled()) return; // Track initial page view trackPageView(window.location.pathname); - - // Track session start - trackSessionStart(); - - // Track navigation changes - let lastPath = window.location.pathname; - setInterval(() => { - const currentPath = window.location.pathname; - if (currentPath !== lastPath) { - trackPageView(currentPath); - lastPath = currentPath; - } - }, 500); - - // Track online/offline status - window.addEventListener('online', () => trackEvent('Go Online')); - window.addEventListener('offline', () => trackEvent('Go Offline')); - - // Track visibility changes (app focus/blur) - document.addEventListener('visibilitychange', () => { - if (document.visibilityState === 'hidden') { - trackEvent('App Background'); - } else { - trackEvent('App Foreground'); - } - }); } diff --git a/js/app.js b/js/app.js index 311d15c..8293949 100644 --- a/js/app.js +++ b/js/app.js @@ -35,28 +35,7 @@ import { openEditProfile } from './profile.js'; import { ThemeStore } from './themeStore.js'; import './commandPalette.js'; import { initTracker } from './tracker.js'; -import { - initAnalytics, - trackSidebarNavigation, - trackCreatePlaylist, - trackCreateFolder, - trackImportJSPF, - trackImportCSV, - trackImportXSPF, - trackImportXML, - trackImportM3U, - trackSelectLocalFolder, - trackChangeLocalFolder, - trackOpenModal, - trackCloseModal, - trackKeyboardShortcut, - trackPwaUpdate, - trackDismissUpdate, - trackOpenFullscreenCover, - trackCloseFullscreenCover, - trackOpenLyrics, - trackCloseLyrics, -} from './analytics.js'; +import { initAnalytics } from './analytics.js'; import { parseCSV, parseJSPF, @@ -253,52 +232,40 @@ function initializeCasting(audioPlayer, castBtn) { function initializeKeyboardShortcuts(player, _audioPlayer) { const keyActionMap = { playPause: () => { - trackKeyboardShortcut('Space'); player.handlePlayPause(); }, seekForward: () => { - trackKeyboardShortcut('Right'); player.seekForward(10); }, seekBackward: () => { - trackKeyboardShortcut('Left'); player.seekBackward(10); }, nextTrack: () => { - trackKeyboardShortcut('Shift+Right'); player.playNext(); }, previousTrack: () => { - trackKeyboardShortcut('Shift+Left'); player.playPrev(); }, volumeUp: () => { - trackKeyboardShortcut('Up'); player.setVolume(player.userVolume + 0.1); }, volumeDown: () => { - trackKeyboardShortcut('Down'); player.setVolume(player.userVolume - 0.1); }, mute: () => { - trackKeyboardShortcut('M'); const el = player.activeElement; el.muted = !el.muted; }, shuffle: () => { - trackKeyboardShortcut('S'); document.getElementById('shuffle-btn')?.click(); }, repeat: () => { - trackKeyboardShortcut('R'); document.getElementById('repeat-btn')?.click(); }, queue: () => { - trackKeyboardShortcut('Q'); document.getElementById('queue-btn')?.click(); }, lyrics: () => { - trackKeyboardShortcut('L'); const overlay = document.getElementById('fullscreen-cover-overlay'); const isFullscreenOpen = overlay && getComputedStyle(overlay).display !== 'none'; @@ -309,29 +276,24 @@ function initializeKeyboardShortcuts(player, _audioPlayer) { document.getElementById('toggle-lyrics-btn')?.click(); }, search: () => { - trackKeyboardShortcut('/'); document.getElementById('search-input')?.focus(); }, escape: () => { - trackKeyboardShortcut('Escape'); document.getElementById('search-input')?.blur(); sidePanelManager.close(); clearLyricsPanelSync(player.activeElement, sidePanelManager.panel); }, visualizerNext: () => { - trackKeyboardShortcut('VisualizerNext'); if (UIRenderer.instance.visualizer?.presets?.['butterchurn']) { UIRenderer.instance.visualizer.presets['butterchurn'].nextPreset(); } }, visualizerPrev: () => { - trackKeyboardShortcut('VisualizerPrev'); if (UIRenderer.instance.visualizer?.presets?.['butterchurn']) { UIRenderer.instance.visualizer.presets['butterchurn'].prevPreset(); } }, visualizerCycle: () => { - trackKeyboardShortcut('VisualizerCycle'); if (UIRenderer.instance.visualizer?.presets?.['butterchurn']) { UIRenderer.instance.visualizer.presets['butterchurn'].toggleCycle(); } @@ -694,7 +656,6 @@ document.addEventListener('DOMContentLoaded', async () => { const href = link.getAttribute('href'); if (href && !href.startsWith('http')) { const item = link.querySelector('span')?.textContent || href; - trackSidebarNavigation(item); } }); }); @@ -729,18 +690,10 @@ document.addEventListener('DOMContentLoaded', async () => { if (mode === 'lyrics') { const isActive = sidePanelManager.isActive('lyrics'); - - if (isActive) { - trackCloseLyrics(Player.instance.currentTrack); - } else { - trackOpenLyrics(Player.instance.currentTrack); - } } else if (mode === 'cover') { const overlay = document.getElementById('fullscreen-cover-overlay'); if (overlay && overlay.style.display === 'flex') { - trackCloseFullscreenCover(); } else { - trackOpenFullscreenCover(Player.instance.currentTrack); } } @@ -781,7 +734,6 @@ document.addEventListener('DOMContentLoaded', async () => { }); document.getElementById('close-fullscreen-cover-btn')?.addEventListener('click', async () => { - trackCloseFullscreenCover(); await closeFullscreenOverlay(); }); @@ -1332,7 +1284,6 @@ document.addEventListener('DOMContentLoaded', async () => { } if (e.target.closest('#create-playlist-btn') || e.target.closest('#library-create-playlist-card')) { - trackOpenModal('Create Playlist'); const modal = document.getElementById('playlist-modal'); document.getElementById('playlist-modal-title').textContent = 'Create Playlist'; document.getElementById('playlist-name-input').value = ''; @@ -1386,7 +1337,6 @@ document.addEventListener('DOMContentLoaded', async () => { } if (e.target.closest('#create-folder-btn') || e.target.closest('#library-create-folder-card')) { - trackOpenModal('Create Folder'); const modal = document.getElementById('folder-modal'); document.getElementById('folder-name-input').value = ''; document.getElementById('folder-cover-input').value = ''; @@ -1400,11 +1350,9 @@ document.addEventListener('DOMContentLoaded', async () => { if (name) { const folder = await db.createFolder(name, cover); - trackCreateFolder(folder); await syncManager.syncUserFolder(folder, 'create'); UIRenderer.instance.renderLibraryPage(); document.getElementById('folder-modal').classList.remove('active'); - trackCloseModal('Create Folder'); } else { showNotification('Please enter a folder name.'); } @@ -1593,7 +1541,6 @@ document.addEventListener('DOMContentLoaded', async () => { } console.log(`Imported ${tracks.length} tracks from YouTube`); - trackImportCSV(name || 'Untitled', tracks.length, missingTracks.length); if (missingTracks.length > 0) { setTimeout(() => { @@ -1673,12 +1620,6 @@ document.addEventListener('DOMContentLoaded', async () => { jspfPlaylist?.creator || jspfPlaylist?.extension?.['https://musicbrainz.org/doc/jspf#playlist']?.creator || 'unknown'; - trackImportJSPF( - name || jspfPlaylist?.title || 'Untitled', - tracks.length, - missingTracks.length, - jspfCreator - ); if (missingTracks.length > 0) { setTimeout(() => { @@ -1792,8 +1733,6 @@ document.addEventListener('DOMContentLoaded', async () => { } console.log(`Imported ${tracks.length} tracks from CSV`); - trackImportCSV(name || 'Untitled', tracks.length, missingTracks.length); - if (missingTracks.length > 0) { setTimeout(() => { showMissingTracksNotification(missingTracks, name || 'Untitled'); @@ -1851,8 +1790,6 @@ document.addEventListener('DOMContentLoaded', async () => { } console.log(`Imported ${tracks.length} tracks from XSPF`); - trackImportXSPF(name || 'Untitled', tracks.length, missingTracks.length); - if (missingTracks.length > 0) { setTimeout(() => { showMissingTracksNotification(missingTracks, name || 'Untitled'); @@ -1910,8 +1847,6 @@ document.addEventListener('DOMContentLoaded', async () => { } console.log(`Imported ${tracks.length} tracks from XML`); - trackImportXML(name || 'Untitled', tracks.length, missingTracks.length); - if (missingTracks.length > 0) { setTimeout(() => { showMissingTracksNotification(missingTracks, name || 'Untitled'); @@ -1969,8 +1904,6 @@ document.addEventListener('DOMContentLoaded', async () => { } console.log(`Imported ${tracks.length} tracks from M3U`); - trackImportM3U(name || 'Untitled', tracks.length, missingTracks.length); - if (missingTracks.length > 0) { setTimeout(() => { showMissingTracksNotification(missingTracks, name || 'Untitled'); @@ -2002,10 +1935,8 @@ document.addEventListener('DOMContentLoaded', async () => { // Update DB again with isPublic flag await db.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist)); await syncManager.syncUserPlaylist(playlist, 'create'); - trackCreatePlaylist(playlist, importSource); UIRenderer.instance.renderLibraryPage(); modal.classList.remove('active'); - trackCloseModal('Create Playlist'); }); } } else { @@ -2507,9 +2438,6 @@ document.addEventListener('DOMContentLoaded', async () => { }); await db.saveSetting('local_folder_handle', handle); - if (isChange) { - trackChangeLocalFolder(); - } const btn = document.getElementById('select-local-folder-btn'); const btnText = document.getElementById('select-local-folder-text'); @@ -2520,7 +2448,6 @@ document.addEventListener('DOMContentLoaded', async () => { } const tracks = scanLocalMediaFolder(true); - trackSelectLocalFolder(tracks?.length ?? 0); UIRenderer.instance.renderLibraryPage(); } catch (err) { if (err.name !== 'AbortError') { @@ -2707,12 +2634,10 @@ document.addEventListener('DOMContentLoaded', async () => { onNeedRefresh() { if (pwaUpdateSettings.isAutoUpdateEnabled()) { // Auto-update: immediately activate the new service worker - trackPwaUpdate(); updateSW(true); } else { // Show notification with Update button and dismiss option showUpdateNotification(() => { - trackPwaUpdate(); updateSW(true); }); } @@ -2955,7 +2880,6 @@ function showUpdateNotification(updateCallback) { }); document.getElementById('dismiss-update-btn').addEventListener('click', () => { - trackDismissUpdate(); notification.remove(); }); } diff --git a/js/events.js b/js/events.js index cb9e5b7..d173fa3 100644 --- a/js/events.js +++ b/js/events.js @@ -23,37 +23,6 @@ import { syncManager } from './accounts/pocketbase.js'; import { waveformGenerator } from './waveform.js'; import { audioContextManager } from './audio-context.js'; import { hapticLongPress, hapticMedium, hapticLight } from './haptics.js'; -import { - trackPlayTrack, - trackPauseTrack, - trackSkipTrack, - trackToggleShuffle, - trackToggleRepeat, - trackAddToQueue, - trackPlayNext, - trackLikeTrack, - trackUnlikeTrack, - trackLikeAlbum, - trackUnlikeAlbum, - trackLikeArtist, - trackUnlikeArtist, - trackLikePlaylist, - trackUnlikePlaylist, - trackDownloadTrack, - trackContextMenuAction, - trackBlockTrack, - trackUnblockTrack, - trackBlockAlbum, - trackUnblockAlbum, - trackBlockArtist, - trackUnblockArtist, - trackCopyLink, - trackOpenInNewTab, - trackSetSleepTimer, - trackCancelSleepTimer, - trackStartMix, - trackEvent, -} from './analytics.js'; import { SVG_BIN, SVG_MUTE, SVG_PAUSE, SVG_PLAY, SVG_VOLUME, SVG_CHECKBOX, SVG_CHECKBOX_CHECKED } from './icons.js'; import { partyManager } from './listening-party.js'; import { MusicAPI } from './music-api.js'; @@ -435,9 +404,6 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { await audioContextManager.resume(); if (player.currentTrack) { - // Track play event - trackPlayTrack(player.currentTrack); - // Scrobble if (scrobbler.isAuthenticated()) { scrobbler.updateNowPlaying(player.currentTrack); @@ -460,9 +426,6 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { element.addEventListener('pause', () => { if (player.activeElement !== element) return; - if (player.currentTrack) { - trackPauseTrack(player.currentTrack); - } playPauseBtn.innerHTML = SVG_PLAY(20); player.updateMediaSessionPlaybackState(); player.updateMediaSessionPositionState(); @@ -566,19 +529,16 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { }); nextBtn.addEventListener('click', async () => { await hapticMedium(); - trackSkipTrack(player.currentTrack, 'next'); player.playNext(); }); prevBtn.addEventListener('click', async () => { await hapticMedium(); - trackSkipTrack(player.currentTrack, 'previous'); player.playPrev(); }); shuffleBtn.addEventListener('click', async () => { await hapticLight(); player.toggleShuffle(); - trackToggleShuffle(player.shuffleActive); shuffleBtn.classList.toggle('active', player.shuffleActive); if (window.renderQueueFunction) await window.renderQueueFunction(); }); @@ -586,7 +546,6 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { repeatBtn.addEventListener('click', async () => { await hapticLight(); const mode = await player.toggleRepeat(); - trackToggleRepeat(mode === REPEAT_MODE.OFF ? 'off' : mode === REPEAT_MODE.ALL ? 'all' : 'one'); repeatBtn.classList.toggle('active', mode !== REPEAT_MODE.OFF); repeatBtn.classList.toggle('repeat-one', mode === REPEAT_MODE.ONE); repeatBtn.title = @@ -604,7 +563,6 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { sleepTimerBtnDesktop.addEventListener('click', () => { if (player.isSleepTimerActive()) { player.clearSleepTimer(); - trackCancelSleepTimer(); showNotification('Sleep timer cancelled'); } else { showSleepTimerModal(player); @@ -617,7 +575,6 @@ export function initializePlayerEvents(player, audioPlayer, scrobbler, ui) { sleepTimerBtnMobile.addEventListener('click', () => { if (player.isSleepTimerActive()) { player.clearSleepTimer(); - trackCancelSleepTimer(); showNotification('Sleep timer cancelled'); } else { showSleepTimerModal(player); @@ -1349,12 +1306,10 @@ export async function handleTrackAction( } if (action === 'add-to-queue') { - trackAddToQueue(item, 'end'); player.addToQueue(item); if (window.renderQueueFunction) await window.renderQueueFunction(); showNotification(`Added to queue: ${item.title}`); } else if (action === 'play-next') { - trackPlayNext(item); player.addNextToQueue(item); if (window.renderQueueFunction) await window.renderQueueFunction(); showNotification(`Playing next: ${item.title}`); @@ -1363,34 +1318,17 @@ export async function handleTrackAction( player.playAtIndex(0); showNotification(`Playing track: ${item.title}`); } else if (action === 'start-mix') { - trackStartMix(type, item); if (item.mixes?.TRACK_MIX) { navigate(`/mix/${item.mixes.TRACK_MIX}`); } else { showNotification('No mix available for this track'); } } else if (action === 'download') { - trackDownloadTrack(item, downloadQualitySettings.getQuality()); await downloadTrackWithMetadata(item, downloadQualitySettings.getQuality(), api, lyricsManager); } else if (action === 'toggle-like') { const added = await db.toggleFavorite(type, item); await syncManager.syncLibraryItem(type, item, added); - // Track like/unlike - if (added) { - if (type === 'track') trackLikeTrack(item); - else if (type === 'video') trackEvent('Like Video', { title: item.title }); - else if (type === 'album') trackLikeAlbum(item); - else if (type === 'artist') trackLikeArtist(item); - else if (type === 'playlist' || type === 'user-playlist') trackLikePlaylist(item); - } else { - if (type === 'track') trackUnlikeTrack(item); - else if (type === 'video') trackEvent('Unlike Video', { title: item.title }); - else if (type === 'album') trackUnlikeAlbum(item); - else if (type === 'artist') trackUnlikeArtist(item); - else if (type === 'playlist' || type === 'user-playlist') trackUnlikePlaylist(item); - } - if (added && type === 'track' && scrobbler) { if (lastFMStorage.isEnabled() && lastFMStorage.shouldLoveOnLike()) { scrobbler.loveTrack(item); @@ -1675,7 +1613,6 @@ export async function handleTrackAction( const typeForUrl = type === 'user-playlist' ? 'userplaylist' : type; const url = getShareUrl(storedHref ? storedHref : `/${typeForUrl}/${item.id || item.uuid}`); - trackCopyLink(type, item.id || item.uuid); await navigator.clipboard .writeText(url) .then(() => { @@ -1690,7 +1627,6 @@ export async function handleTrackAction( ? `${window.location.origin}${storedHref}` : `${window.location.origin}/${type}/${item.id || item.uuid}`; - trackOpenInNewTab(type, item.id || item.uuid); window.open(url, '_blank'); } else if (action === 'open-in-harmony') { const albumId = item.id; @@ -1868,11 +1804,9 @@ export async function handleTrackAction( const { contentBlockingSettings } = await import('./storage.js'); if (contentBlockingSettings.isTrackBlocked(item.id)) { contentBlockingSettings.unblockTrack(item.id); - trackUnblockTrack(item); showNotification(`Unblocked track: ${item.title}`); } else { contentBlockingSettings.blockTrack(item); - trackBlockTrack(item); showNotification(`Blocked track: ${item.title}`); } } else if (action === 'block-album') { @@ -1891,11 +1825,9 @@ export async function handleTrackAction( if (contentBlockingSettings.isAlbumBlocked(albumId)) { contentBlockingSettings.unblockAlbum(albumId); - trackUnblockAlbum(albumObj); showNotification(`Unblocked album: ${albumTitle || 'Unknown Album'}`); } else { contentBlockingSettings.blockAlbum(albumObj); - trackBlockAlbum(albumObj); showNotification(`Blocked album: ${albumTitle || 'Unknown Album'}`); } } else if (action === 'block-artist') { @@ -1912,11 +1844,9 @@ export async function handleTrackAction( if (contentBlockingSettings.isArtistBlocked(artistId)) { contentBlockingSettings.unblockArtist(artistId); - trackUnblockArtist(artistObj); showNotification(`Unblocked artist: ${artistName || 'Unknown Artist'}`); } else { contentBlockingSettings.blockArtist(artistObj); - trackBlockArtist(artistObj); showNotification(`Blocked artist: ${artistName || 'Unknown Artist'}`); } } @@ -2494,7 +2424,6 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen switch (action) { case 'play-next': selectedTracks.forEach((t) => { - trackPlayNext(t); player.addNextToQueue(t); }); if (window.renderQueueFunction) await window.renderQueueFunction(); @@ -2536,8 +2465,6 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen break; } } else { - // Track context menu action - trackContextMenuAction(action, type, track); await handleTrackAction(action, track, player, api, lyricsManager, type, ui, scrobbler, target.dataset); } } @@ -2700,7 +2627,6 @@ function showSleepTimerModal(player) { if (minutes) { player.setSleepTimer(minutes); - trackSetSleepTimer(minutes); showNotification(`Sleep timer set for ${minutes} minute${minutes === 1 ? '' : 's'}`); closeModal(); } diff --git a/js/side-panel.js b/js/side-panel.js index 5da3b4a..23499e2 100644 --- a/js/side-panel.js +++ b/js/side-panel.js @@ -1,5 +1,3 @@ -import { trackCloseSidePanel, trackCloseQueue, trackCloseLyrics } from './analytics.js'; - export class SidePanelManager { constructor() { this.panel = document.getElementById('side-panel'); @@ -103,15 +101,9 @@ export class SidePanelManager { close() { // Track side panel close if (this.currentView) { - trackCloseSidePanel(); - if (this.currentView === 'queue') { - trackCloseQueue(); - } else if (this.currentView === 'lyrics') { + if (this.currentView === 'lyrics') { // Get current track from audio player context const audioPlayer = document.getElementById('audio-player'); - if (audioPlayer && audioPlayer._currentTrack) { - trackCloseLyrics(audioPlayer._currentTrack); - } } } diff --git a/js/ui-interactions.js b/js/ui-interactions.js index 0a66529..5c93f6d 100644 --- a/js/ui-interactions.js +++ b/js/ui-interactions.js @@ -12,7 +12,6 @@ import { downloadQualitySettings, contentBlockingSettings } from './storage.js'; import { db } from './db.js'; import { syncManager } from './accounts/pocketbase.js'; import { showNotification, downloadTracks } from './downloads.js'; -import { trackSearchTabChange, trackOpenQueue } from './analytics.js'; import { SVG_CLOSE, SVG_BIN, @@ -474,7 +473,6 @@ export function initializeUIInteractions(player, api, ui) { }; const openQueuePanel = () => { - trackOpenQueue(); sidePanelManager.open('queue', 'Queue', renderQueueControls, renderQueueContent); setTimeout(() => { @@ -536,9 +534,6 @@ export function initializeUIInteractions(player, api, ui) { const page = tab.closest('.page'); if (!page) return; - // Track tab change - trackSearchTabChange(tab.dataset.tab); - page.querySelectorAll('.search-tab').forEach((t) => t.classList.remove('active')); page.querySelectorAll('.search-tab-content').forEach((c) => c.classList.remove('active')); diff --git a/js/ui.js b/js/ui.js index 8f42aa1..f29712a 100644 --- a/js/ui.js +++ b/js/ui.js @@ -49,7 +49,6 @@ import { createProjectCardHTML, createTrackFromSong, } from './tracker.js'; -import { trackSearch, trackChangeSort } from './analytics.js'; fontSettings.applyFont().catch(console.error); fontSettings.applyFontSize(); @@ -3608,7 +3607,6 @@ export class UIRenderer { // Track search with results const totalResults = finalTracks.length + finalArtists.length + finalAlbums.length + finalPlaylists.length; - trackSearch(query, totalResults); if (finalTracks.length) { await this.renderListWithTracks(tracksContainer, finalTracks, true, false, false, true); @@ -5674,7 +5672,6 @@ export class UIRenderer { const handleSort = async (ev) => { const li = ev.target.closest('li'); if (li && li.dataset.sort) { - trackChangeSort(li.dataset.sort); await onSort(li.dataset.sort); closeMenu(); }