//js/settings
import {
themeManager,
lastFMStorage,
nowPlayingSettings,
lyricsSettings,
backgroundSettings,
trackListSettings,
cardSettings,
waveformSettings,
replayGainSettings,
smoothScrollingSettings,
downloadQualitySettings
} from "./storage.js";
import { db } from "./db.js";
import { authManager } from "./firebase/auth.js";
import { syncManager } from "./firebase/sync.js";
import { initializeFirebaseSettingsUI } from "./firebase/config.js";
export function initializeSettings(scrobbler, player, api, ui) {
// Initialize Firebase UI & Settings
authManager.updateUI(authManager.user);
initializeFirebaseSettingsUI();
// Email Auth UI Logic
const toggleEmailBtn = document.getElementById("toggle-email-auth-btn");
const cancelEmailBtn = document.getElementById("cancel-email-auth-btn");
const authContainer = document.getElementById("email-auth-container");
const authButtonsContainer = document.getElementById(
"auth-buttons-container",
);
const emailInput = document.getElementById("auth-email");
const passwordInput = document.getElementById("auth-password");
const signInBtn = document.getElementById("email-signin-btn");
const signUpBtn = document.getElementById("email-signup-btn");
if (toggleEmailBtn && authContainer && authButtonsContainer) {
toggleEmailBtn.addEventListener("click", () => {
authContainer.style.display = "flex";
authButtonsContainer.style.display = "none";
});
}
if (cancelEmailBtn && authContainer && authButtonsContainer) {
cancelEmailBtn.addEventListener("click", () => {
authContainer.style.display = "none";
authButtonsContainer.style.display = "flex";
});
}
if (signInBtn) {
signInBtn.addEventListener("click", async () => {
const email = emailInput.value;
const password = passwordInput.value;
if (!email || !password) {
alert("Please enter both email and password.");
return;
}
try {
await authManager.signInWithEmail(email, password);
authContainer.style.display = "none";
authButtonsContainer.style.display = "flex";
emailInput.value = "";
passwordInput.value = "";
} catch (e) {
// Error handled in authManager
}
});
}
if (signUpBtn) {
signUpBtn.addEventListener("click", async () => {
const email = emailInput.value;
const password = passwordInput.value;
if (!email || !password) {
alert("Please enter both email and password.");
return;
}
try {
await authManager.signUpWithEmail(email, password);
authContainer.style.display = "none";
authButtonsContainer.style.display = "flex";
emailInput.value = "";
passwordInput.value = "";
} catch (e) {
// Error handled in authManager
}
});
}
const lastfmConnectBtn = document.getElementById("lastfm-connect-btn");
const lastfmStatus = document.getElementById("lastfm-status");
const lastfmToggle = document.getElementById("lastfm-toggle");
const lastfmToggleSetting = document.getElementById("lastfm-toggle-setting");
const lastfmLoveToggle = document.getElementById("lastfm-love-toggle");
const lastfmLoveSetting = document.getElementById("lastfm-love-setting");
function updateLastFMUI() {
if (scrobbler.isAuthenticated()) {
lastfmStatus.textContent = `Connected as ${scrobbler.username}`;
lastfmConnectBtn.textContent = "Disconnect";
lastfmConnectBtn.classList.add("danger");
lastfmToggleSetting.style.display = "flex";
lastfmLoveSetting.style.display = "flex";
lastfmToggle.checked = lastFMStorage.isEnabled();
lastfmLoveToggle.checked = lastFMStorage.shouldLoveOnLike();
} else {
lastfmStatus.textContent =
"Connect your Last.fm account to scrobble tracks";
lastfmConnectBtn.textContent = "Connect Last.fm";
lastfmConnectBtn.classList.remove("danger");
lastfmToggleSetting.style.display = "none";
lastfmLoveSetting.style.display = "none";
}
}
updateLastFMUI();
lastfmConnectBtn?.addEventListener("click", async () => {
if (scrobbler.isAuthenticated()) {
if (confirm("Disconnect from Last.fm?")) {
scrobbler.disconnect();
updateLastFMUI();
}
return;
}
const authWindow = window.open("", "_blank");
lastfmConnectBtn.disabled = true;
lastfmConnectBtn.textContent = "Opening Last.fm...";
try {
const { token, url } = await scrobbler.getAuthUrl();
if (authWindow) {
authWindow.location.href = url;
} else {
alert("Popup blocked! Please allow popups.");
lastfmConnectBtn.textContent = "Connect Last.fm";
lastfmConnectBtn.disabled = false;
return;
}
lastfmConnectBtn.textContent = "Waiting for authorization...";
let attempts = 0;
const maxAttempts = 30;
const checkAuth = setInterval(async () => {
attempts++;
if (attempts > maxAttempts) {
clearInterval(checkAuth);
lastfmConnectBtn.textContent = "Connect Last.fm";
lastfmConnectBtn.disabled = false;
if (authWindow && !authWindow.closed) authWindow.close();
alert("Authorization timed out. Please try again.");
return;
}
try {
const result = await scrobbler.completeAuthentication(token);
if (result.success) {
clearInterval(checkAuth);
if (authWindow && !authWindow.closed) authWindow.close();
updateLastFMUI();
lastfmConnectBtn.disabled = false;
lastFMStorage.setEnabled(true);
lastfmToggle.checked = true;
alert(`Successfully connected to Last.fm as ${result.username}!`);
}
} catch (e) {
// Still waiting
}
}, 2000);
} catch (error) {
console.error("Last.fm connection failed:", error);
alert("Failed to connect to Last.fm: " + error.message);
lastfmConnectBtn.textContent = "Connect Last.fm";
lastfmConnectBtn.disabled = false;
if (authWindow && !authWindow.closed) authWindow.close();
}
});
lastfmToggle?.addEventListener("change", (e) => {
lastFMStorage.setEnabled(e.target.checked);
});
lastfmLoveToggle?.addEventListener("change", (e) => {
lastFMStorage.setLoveOnLike(e.target.checked);
});
// Theme picker
const themePicker = document.getElementById("theme-picker");
const currentTheme = themeManager.getTheme();
themePicker.querySelectorAll(".theme-option").forEach((option) => {
if (option.dataset.theme === currentTheme) {
option.classList.add("active");
}
option.addEventListener("click", () => {
const theme = option.dataset.theme;
themePicker
.querySelectorAll(".theme-option")
.forEach((opt) => opt.classList.remove("active"));
option.classList.add("active");
if (theme === "custom") {
document.getElementById("custom-theme-editor").classList.add("show");
renderCustomThemeEditor();
themeManager.setTheme('custom');
} else {
document.getElementById("custom-theme-editor").classList.remove("show");
themeManager.setTheme(theme);
}
});
});
function renderCustomThemeEditor() {
const grid = document.getElementById("theme-color-grid");
const customTheme = themeManager.getCustomTheme() || {
background: "#000000",
foreground: "#fafafa",
primary: "#ffffff",
secondary: "#27272a",
muted: "#27272a",
border: "#27272a",
highlight: "#ffffff",
};
grid.innerHTML = Object.entries(customTheme)
.map(
([key, value]) => `
`,
)
.join("");
}
document
.getElementById("apply-custom-theme")
?.addEventListener("click", () => {
const colors = {};
document
.querySelectorAll('#theme-color-grid input[type="color"]')
.forEach((input) => {
colors[input.dataset.color] = input.value;
});
themeManager.setCustomTheme(colors);
});
document
.getElementById("reset-custom-theme")
?.addEventListener("click", () => {
renderCustomThemeEditor();
});
// Streaming Quality setting
const streamingQualitySetting = document.getElementById("streaming-quality-setting");
if (streamingQualitySetting) {
const savedQuality = localStorage.getItem("playback-quality") || "LOSSLESS";
streamingQualitySetting.value = savedQuality;
player.setQuality(savedQuality);
streamingQualitySetting.addEventListener("change", (e) => {
const newQuality = e.target.value;
player.setQuality(newQuality);
localStorage.setItem("playback-quality", newQuality);
});
}
// Download Quality setting
const downloadQualitySetting = document.getElementById("download-quality-setting");
if (downloadQualitySetting) {
downloadQualitySetting.value = downloadQualitySettings.getQuality();
downloadQualitySetting.addEventListener("change", (e) => {
downloadQualitySettings.setQuality(e.target.value);
});
}
// ReplayGain Settings
const replayGainMode = document.getElementById("replay-gain-mode");
if (replayGainMode) {
replayGainMode.value = replayGainSettings.getMode();
replayGainMode.addEventListener("change", (e) => {
replayGainSettings.setMode(e.target.value);
player.applyReplayGain();
});
}
const replayGainPreamp = document.getElementById("replay-gain-preamp");
if (replayGainPreamp) {
replayGainPreamp.value = replayGainSettings.getPreamp();
replayGainPreamp.addEventListener("change", (e) => {
replayGainSettings.setPreamp(parseFloat(e.target.value) || 3);
player.applyReplayGain();
});
}
// Now Playing Mode
const nowPlayingMode = document.getElementById("now-playing-mode");
if (nowPlayingMode) {
nowPlayingMode.value = nowPlayingSettings.getMode();
nowPlayingMode.addEventListener("change", (e) => {
nowPlayingSettings.setMode(e.target.value);
});
}
// Track List Actions Mode
const trackListActionsMode = document.getElementById(
"track-list-actions-mode",
);
if (trackListActionsMode) {
trackListActionsMode.value = trackListSettings.getMode();
trackListActionsMode.addEventListener("change", (e) => {
trackListSettings.setMode(e.target.value);
});
}
// Compact Artist Toggle
const compactArtistToggle = document.getElementById("compact-artist-toggle");
if (compactArtistToggle) {
compactArtistToggle.checked = cardSettings.isCompactArtist();
compactArtistToggle.addEventListener("change", (e) => {
cardSettings.setCompactArtist(e.target.checked);
});
}
// Compact Album Toggle
const compactAlbumToggle = document.getElementById("compact-album-toggle");
if (compactAlbumToggle) {
compactAlbumToggle.checked = cardSettings.isCompactAlbum();
compactAlbumToggle.addEventListener("change", (e) => {
cardSettings.setCompactAlbum(e.target.checked);
});
}
// Download Lyrics Toggle
const downloadLyricsToggle = document.getElementById(
"download-lyrics-toggle",
);
if (downloadLyricsToggle) {
downloadLyricsToggle.checked = lyricsSettings.shouldDownloadLyrics();
downloadLyricsToggle.addEventListener("change", (e) => {
lyricsSettings.setDownloadLyrics(e.target.checked);
});
}
// Romaji Lyrics Toggle
const romajiLyricsToggle = document.getElementById("romaji-lyrics-toggle");
if (romajiLyricsToggle) {
romajiLyricsToggle.checked =
localStorage.getItem("lyricsRomajiMode") === "true";
romajiLyricsToggle.addEventListener("change", (e) => {
localStorage.setItem(
"lyricsRomajiMode",
e.target.checked ? "true" : "false",
);
});
}
// Album Background Toggle
const albumBackgroundToggle = document.getElementById(
"album-background-toggle",
);
if (albumBackgroundToggle) {
albumBackgroundToggle.checked = backgroundSettings.isEnabled();
albumBackgroundToggle.addEventListener("change", (e) => {
backgroundSettings.setEnabled(e.target.checked);
});
}
// Waveform Toggle
const waveformToggle = document.getElementById("waveform-toggle");
if (waveformToggle) {
waveformToggle.checked = waveformSettings.isEnabled();
waveformToggle.addEventListener("change", (e) => {
waveformSettings.setEnabled(e.target.checked);
window.dispatchEvent(new CustomEvent("waveform-toggle", { detail: { enabled: e.target.checked } }));
});
}
// Smooth Scrolling Toggle
const smoothScrollingToggle = document.getElementById("smooth-scrolling-toggle");
if (smoothScrollingToggle) {
smoothScrollingToggle.checked = smoothScrollingSettings.isEnabled();
smoothScrollingToggle.addEventListener("change", (e) => {
smoothScrollingSettings.setEnabled(e.target.checked);
window.dispatchEvent(new CustomEvent("smooth-scrolling-toggle", { detail: { enabled: e.target.checked } }));
});
}
// Filename template setting
const filenameTemplate = document.getElementById("filename-template");
if (filenameTemplate) {
filenameTemplate.value =
localStorage.getItem("filename-template") ||
"{trackNumber} - {artist} - {title}";
filenameTemplate.addEventListener("change", (e) => {
localStorage.setItem("filename-template", e.target.value);
});
}
// ZIP folder template
const zipFolderTemplate = document.getElementById("zip-folder-template");
if (zipFolderTemplate) {
zipFolderTemplate.value =
localStorage.getItem("zip-folder-template") ||
"{albumTitle} - {albumArtist}";
zipFolderTemplate.addEventListener("change", (e) => {
localStorage.setItem("zip-folder-template", e.target.value);
});
}
// API settings
document
.getElementById("refresh-speed-test-btn")
?.addEventListener("click", async () => {
const btn = document.getElementById("refresh-speed-test-btn");
const originalText = btn.textContent;
btn.textContent = "Testing...";
btn.disabled = true;
try {
await api.settings.refreshSpeedTests();
ui.renderApiSettings();
btn.textContent = "Done!";
setTimeout(() => {
btn.textContent = originalText;
btn.disabled = false;
}, 1500);
} catch (error) {
console.error("Failed to refresh speed tests:", error);
btn.textContent = "Error";
setTimeout(() => {
btn.textContent = originalText;
btn.disabled = false;
}, 1500);
}
});
document
.getElementById("api-instance-list")
?.addEventListener("click", async (e) => {
const button = e.target.closest("button");
if (!button) return;
const li = button.closest("li");
const index = parseInt(li.dataset.index, 10);
const type = li.dataset.type || "api"; // Default to api if not present
const instances = await api.settings.getInstances(type);
if (button.classList.contains("move-up") && index > 0) {
[instances[index], instances[index - 1]] = [
instances[index - 1],
instances[index],
];
} else if (
button.classList.contains("move-down") &&
index < instances.length - 1
) {
[instances[index], instances[index + 1]] = [
instances[index + 1],
instances[index],
];
}
api.settings.saveInstances(instances, type);
ui.renderApiSettings();
});
document
.getElementById("clear-cache-btn")
?.addEventListener("click", async () => {
const btn = document.getElementById("clear-cache-btn");
const originalText = btn.textContent;
btn.textContent = "Clearing...";
btn.disabled = true;
try {
await api.clearCache();
btn.textContent = "Cleared!";
setTimeout(() => {
btn.textContent = originalText;
btn.disabled = false;
if (window.location.hash.includes("settings")) {
ui.renderApiSettings();
}
}, 1500);
} catch (error) {
console.error("Failed to clear cache:", error);
btn.textContent = "Error";
setTimeout(() => {
btn.textContent = originalText;
btn.disabled = false;
}, 1500);
}
});
document
.getElementById("firebase-clear-cloud-btn")
?.addEventListener("click", async () => {
if (
confirm(
"Are you sure you want to delete ALL your data from the cloud? This cannot be undone.",
)
) {
try {
await syncManager.clearCloudData();
alert("Cloud data cleared successfully.");
authManager.signOut();
} catch (error) {
console.error("Failed to clear cloud data:", error);
alert("Failed to clear cloud data: " + error.message);
}
}
});
// Backup & Restore
document
.getElementById("export-library-btn")
?.addEventListener("click", async () => {
const data = await db.exportData();
const blob = new Blob([JSON.stringify(data, null, 2)], {
type: "application/json",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `monochrome-library-${new Date().toISOString().split("T")[0]}.json`;
a.click();
URL.revokeObjectURL(url);
});
const importInput = document.getElementById("import-library-input");
document
.getElementById("import-library-btn")
?.addEventListener("click", () => {
importInput.click();
});
importInput?.addEventListener("change", async (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = async (event) => {
try {
const data = JSON.parse(event.target.result);
await db.importData(data);
alert("Library imported successfully!");
window.location.reload(); // Simple way to refresh all state
} catch (err) {
console.error("Import failed:", err);
alert("Failed to import library. Please check the file format.");
}
};
reader.readAsText(file);
});
}