// MusicRoom - Init module // Application initialization sequence (function() { const M = window.MusicRoom; // Check for /listen/ URL function checkDirectTrackLink() { const match = location.pathname.match(/^\/listen\/(.+)$/); if (match) { const trackId = decodeURIComponent(match[1]); console.log("[Init] Direct track link detected:", trackId); return trackId; } return null; } // Play a specific track in local/desync mode M.playDirectTrack = async function(trackId) { // Find track in library const track = M.library?.find(t => t.id === trackId); if (!track) { M.showToast("Track not found", "error"); // Clear the URL history.replaceState(null, "", "/"); return; } // Desync from server M.wantSync = false; M.synced = false; if (M.ws) { M.ws.close(); M.ws = null; } // Set up and play track M.currentTrackId = trackId; M.serverTrackDuration = track.duration; M.setTrackTitle(track.title || track.filename); M.loadingSegments.clear(); const cachedUrl = await M.loadTrackBlob(trackId); M.audio.src = cachedUrl || M.getTrackUrl(trackId); M.audio.currentTime = 0; M.localTimestamp = 0; M.audio.play().catch(() => { M.showToast("Click to start playback"); }); M.updateUI(); M.showToast(`Playing: ${track.title || track.filename}`); // Clear the URL to normal history.replaceState(null, "", "/"); }; // Fetch server status/config async function loadServerStatus() { try { const res = await fetch("/api/status"); M.serverStatus = await res.json(); console.log("Server status:", M.serverStatus); } catch (e) { console.warn("Failed to load server status"); M.serverStatus = null; } } // Initialize track storage async function initStorage() { await TrackStorage.init(); await M.updateCacheStatus(); console.log(`TrackStorage: ${M.cachedTracks.size} tracks cached`); } // Setup panel tab switching function initPanelTabs() { const tabs = document.querySelectorAll(".panel-tab"); tabs.forEach(tab => { tab.onclick = () => { const tabId = tab.dataset.tab; const panel = tab.closest("#library-panel, #queue-panel"); if (!panel) return; // Update active tab panel.querySelectorAll(".panel-tab").forEach(t => t.classList.remove("active")); tab.classList.add("active"); // Update active view panel.querySelectorAll(".panel-view").forEach(v => v.classList.remove("active")); const view = panel.querySelector(`#${tabId}-view`); if (view) view.classList.add("active"); }; }); } // Setup history panel handlers document.addEventListener("DOMContentLoaded", () => { const btnHistory = M.$("#btn-history"); const btnClose = M.$("#btn-close-history"); if (btnHistory) { btnHistory.onclick = () => M.toggleToastHistory(); } if (btnClose) { btnClose.onclick = () => M.toggleToastHistory(); } initPanelTabs(); // Initialize playlists if (M.playlists?.init) { M.playlists.init(); } }); // Update UI based on server status function updateFeatureVisibility() { const fetchBtn = M.$("#btn-fetch-url"); if (fetchBtn) { const ytdlpEnabled = M.serverStatus?.ytdlp?.enabled && M.serverStatus?.ytdlp?.available; fetchBtn.style.display = ytdlpEnabled ? "" : "none"; } } // Initialize the application const directTrackId = checkDirectTrackLink(); Promise.all([initStorage(), loadServerStatus()]).then(async () => { updateFeatureVisibility(); await M.loadLibrary(); await M.loadCurrentUser(); if (M.currentUser) { M.loadChannels(); // Load playlists after auth if (M.playlists?.load) { M.playlists.load(); } } // Handle direct track link after everything is loaded if (directTrackId) { // Small delay to ensure UI is ready setTimeout(() => M.playDirectTrack(directTrackId), 500); } }); })();