diff --git a/src/utils/SettingsExportImport.ts b/src/utils/SettingsExportImport.ts new file mode 100644 index 00000000..9cc67038 --- /dev/null +++ b/src/utils/SettingsExportImport.ts @@ -0,0 +1,50 @@ +const STORAGE_PREFIXES = ["SpicyLyrics-", "spicy-lyrics-settings.", "spicy-lyrics-dev-settings.", "spicy-lyrics-health."]; + +export function exportSettings(): void { + const data: Record = {}; + + for (let i = 0; i < window.localStorage.length; i++) { + const key = window.localStorage.key(i); + if (!key) continue; + if (STORAGE_PREFIXES.some((p) => key.startsWith(p))) { + data[key] = window.localStorage.getItem(key) ?? ""; + } + } + + 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 = `spicy-lyrics-settings-${new Date().toISOString().slice(0, 10)}.json`; + a.click(); + URL.revokeObjectURL(url); +} + +export function importSettings(): void { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".json"; + input.onchange = (e: Event) => { + const file = (e.target as HTMLInputElement).files?.[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = (ev) => { + try { + const raw = ev.target?.result; + if (typeof raw !== "string") throw new Error("empty"); + const data = JSON.parse(raw) as Record; + for (const [key, value] of Object.entries(data)) { + if (typeof value === "string") { + window.localStorage.setItem(key, value); + } + } + (Spicetify as any).showNotification?.("Settings imported! Reloading in 2s…", false, 2000); + setTimeout(() => window.location.reload(), 2200); + } catch { + (Spicetify as any).showNotification?.("Failed to import: invalid settings file.", true); + } + }; + reader.readAsText(file); + }; + input.click(); +} diff --git a/src/utils/settings.ts b/src/utils/settings.ts index c2132241..a667bcba 100644 --- a/src/utils/settings.ts +++ b/src/utils/settings.ts @@ -1,6 +1,8 @@ import Defaults from "../components/Global/Defaults.ts"; import storage from "./storage.ts"; import { RemoveCurrentLyrics_AllCaches, RemoveCurrentLyrics_StateCache, RemoveLyricsCache } from "./LyricsCacheTools.ts"; +import { exportSettings, importSettings } from "./SettingsExportImport.ts"; +import { ProjectVersion } from "../../project/config.ts"; export async function setSettingsMenu() { while (!Spicetify.React || !Spicetify.ReactDOM) { @@ -11,6 +13,7 @@ export async function setSettingsMenu() { generalSettings(SettingsSection); devSettings(SettingsSection); + healthSettings(SettingsSection); //infos(SettingsSection); } @@ -207,6 +210,40 @@ function generalSettings(SettingsSection: any) { settings.pushSettings(); } +function healthSettings(SettingsSection: any) { + const settings = new SettingsSection( + "Spicy Lyrics - Info & Health", + "spicy-lyrics-health" + ); + + settings.addButton( + "version-info", + `Extension version: ${ProjectVersion} | API: ${Defaults.lyrics.api.url}`, + "Copy Debug Info", + () => { + const info = `Spicy Lyrics v${ProjectVersion} | API: ${Defaults.lyrics.api.url}`; + navigator.clipboard?.writeText(info).catch(() => {}); + (Spicetify as any).showNotification?.("Debug info copied to clipboard", false, 2000); + } + ); + + settings.addButton( + "export-settings", + "Download all Spicy Lyrics settings as a JSON file for backup or sharing", + "Export Settings", + () => exportSettings() + ); + + settings.addButton( + "import-settings", + "Restore settings from a previously exported JSON file (reloads Spotify)", + "Import Settings", + () => importSettings() + ); + + settings.pushSettings(); +} + /* function infos(SettingsSection: any) { const settings = new SettingsSection("Spicy Lyrics - Info", "spicy-lyrics-settings-info");