527 lines
16 KiB
JavaScript
527 lines
16 KiB
JavaScript
//js/settings
|
|
import {
|
|
themeManager,
|
|
lastFMStorage,
|
|
nowPlayingSettings,
|
|
lyricsSettings,
|
|
backgroundSettings,
|
|
trackListSettings,
|
|
cardSettings,
|
|
waveformSettings,
|
|
} 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]) => `
|
|
<div class="theme-color-input">
|
|
<label>${key}</label>
|
|
<input type="color" data-color="${key}" value="${value}">
|
|
</div>
|
|
`,
|
|
)
|
|
.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();
|
|
});
|
|
|
|
// Quality setting
|
|
const qualitySetting = document.getElementById("quality-setting");
|
|
if (qualitySetting) {
|
|
const savedQuality = localStorage.getItem("playback-quality") || "LOSSLESS";
|
|
qualitySetting.value = savedQuality;
|
|
player.setQuality(savedQuality);
|
|
|
|
qualitySetting.addEventListener("change", (e) => {
|
|
const newQuality = e.target.value;
|
|
player.setQuality(newQuality);
|
|
localStorage.setItem("playback-quality", newQuality);
|
|
});
|
|
}
|
|
|
|
// 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 } }));
|
|
});
|
|
}
|
|
|
|
// 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);
|
|
});
|
|
}
|