blastoise/public/init.js

140 lines
3.9 KiB
JavaScript

// MusicRoom - Init module
// Application initialization sequence
(function() {
const M = window.MusicRoom;
// Check for /listen/<trackId> 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();
});
// 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();
}
// Handle direct track link after everything is loaded
if (directTrackId) {
// Small delay to ensure UI is ready
setTimeout(() => M.playDirectTrack(directTrackId), 500);
}
});
})();