A music player that connects to your cloud/distributed storage. diffuse.sh
Something went wrong. Try again.
7.5 kB · 242 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243import * as Output from "~/common/output.js";import foundation from "~/common/foundation.js";import { effect } from "~/common/signal.js";
// Set doc titlefoundation.setup({ title: "Export & Import | Diffuse" });
// Setupconst main = /** @type {HTMLElement} */ (document.querySelector("main"));const output = await foundation.orchestrator.output();
// Elementsconst exportBtn = /** @type {HTMLButtonElement} */ (document.querySelector("#export"));const fileInput = /** @type {HTMLInputElement} */ (document.querySelector("#file"));const importTracksBtn = /** @type {HTMLButtonElement} */ (document.querySelector("#import-tracks"));const importPlaylistItemsBtn = /** @type {HTMLButtonElement} */ (document.querySelector( "#import-playlist-items", ));const importFacetsBtn = /** @type {HTMLButtonElement} */ (document.querySelector("#import-facets"));const importSettingsBtn = /** @type {HTMLButtonElement} */ (document.querySelector("#import-settings"));const statusEl = /** @type {HTMLElement} */ (document.querySelector("#status"));const replaceCheckbox = /** @type {HTMLInputElement} */ (document.querySelector("#replace"));
/** @type {Record<string, any> | null} */let json = null;
/** * Show a status message. * @param {string} message * @param {"success" | "error"} type */function showStatus(message, type) { statusEl.textContent = message; statusEl.className = `status status--${type}`; statusEl.hidden = false;}
// Enable export button once output is readyeffect(() => { exportBtn.disabled = !output.ready();});
// Export all data as a JSON snapshotexportBtn.onclick = async () => { const facets = await Output.data(output.facets); const playlistItems = await Output.data(output.playlistItems); const settings = await Output.data(output.settings); const tracks = await Output.data(output.tracks);
const data = { exportedAt: new Date().toISOString(), facets, playlistItems, settings, tracks, };
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 = `diffuse-${new Date().toISOString().slice(0, 10)}.json`; document.body.append(a); a.click(); a.remove();
URL.revokeObjectURL(url);};
// Parse file on selectionfileInput.onchange = async () => { const file = fileInput.files?.[0];
json = null; statusEl.hidden = true; importTracksBtn.disabled = true; importPlaylistItemsBtn.disabled = true; importFacetsBtn.disabled = true; importSettingsBtn.disabled = true;
if (!file) return;
try { json = JSON.parse(await file.text()); } catch (err) { console.error("Failed to parse JSON:", err); showStatus( `Failed to parse JSON: ${/** @type {Error} */ (err).message}`, "error", ); return; }
if (Array.isArray(json?.tracks) && json.tracks.length > 0) { importTracksBtn.disabled = false; }
if (Array.isArray(json?.playlistItems) && json.playlistItems.length > 0) { importPlaylistItemsBtn.disabled = false; }
if (Array.isArray(json?.facets) && json.facets.length > 0) { importFacetsBtn.disabled = false; }
if (Array.isArray(json?.settings) && json.settings.length > 0) { importSettingsBtn.disabled = false; }};
/** * @param {HTMLButtonElement} btn * @param {string} label */function setButtonLabel(btn, label) { const span = /** @type {HTMLElement} */ (btn.querySelector("span")); span.textContent = label;}
// Import tracksimportTracksBtn.onclick = async () => { /** @type {any[]} */ const tracks = json?.tracks; if (!Array.isArray(tracks) || tracks.length === 0) return;
importTracksBtn.disabled = true; setButtonLabel(importTracksBtn, " Importing ..."); try { if (replaceCheckbox.checked) { await output.tracks.save(tracks); showStatus(`Imported ${tracks.length} track(s).`, "success"); } else { const existing = await Output.data(output.tracks); const merged = Output.mergeById(existing, tracks); await output.tracks.save(merged); showStatus(`Merged ${tracks.length} track(s).`, "success"); } } catch (err) { console.error("Import failed:", err); showStatus(`Import failed: ${/** @type {Error} */ (err).message}`, "error"); } finally { setButtonLabel(importTracksBtn, " Import tracks"); importTracksBtn.disabled = false; }};
// Import playlist itemsimportPlaylistItemsBtn.onclick = async () => { /** @type {any[]} */ const playlistItems = json?.playlistItems; if (!Array.isArray(playlistItems) || playlistItems.length === 0) return;
importPlaylistItemsBtn.disabled = true; setButtonLabel(importPlaylistItemsBtn, " Importing ..."); try { if (replaceCheckbox.checked) { await output.playlistItems.save(playlistItems); } else { const existing = await Output.data(output.playlistItems); const merged = Output.mergeById(existing, playlistItems); await output.playlistItems.save(merged); } const playlistCount = new Set(playlistItems.map((p) => p.playlist)).size; showStatus(`Imported ${playlistCount} playlist(s).`, "success"); } catch (err) { console.error("Import failed:", err); showStatus(`Import failed: ${/** @type {Error} */ (err).message}`, "error"); } finally { setButtonLabel(importPlaylistItemsBtn, " Import playlist items"); importPlaylistItemsBtn.disabled = false; }};
// Import facetsimportFacetsBtn.onclick = async () => { /** @type {any[]} */ const facets = json?.facets; if (!Array.isArray(facets) || facets.length === 0) return;
importFacetsBtn.disabled = true; setButtonLabel(importFacetsBtn, " Importing ..."); try { if (replaceCheckbox.checked) { await output.facets.save(facets); showStatus(`Imported ${facets.length} facet(s).`, "success"); } else { const existing = await Output.data(output.facets); const merged = Output.mergeById(existing, facets); await output.facets.save(merged); showStatus(`Merged ${facets.length} facet(s).`, "success"); } } catch (err) { console.error("Import failed:", err); showStatus(`Import failed: ${/** @type {Error} */ (err).message}`, "error"); } finally { setButtonLabel(importFacetsBtn, " Import facets"); importFacetsBtn.disabled = false; }};
// Import settingsimportSettingsBtn.onclick = async () => { /** @type {any[]} */ const settings = json?.settings; if (!Array.isArray(settings) || settings.length === 0) return;
importSettingsBtn.disabled = true; setButtonLabel(importSettingsBtn, " Importing ..."); try { if (replaceCheckbox.checked) { await output.settings.save(settings); showStatus(`Imported ${settings.length} setting(s).`, "success"); } else { const existing = await Output.data(output.settings); const merged = Output.mergeById(existing, settings); await output.settings.save(merged); showStatus(`Merged ${settings.length} setting(s).`, "success"); } } catch (err) { console.error("Import failed:", err); showStatus(`Import failed: ${/** @type {Error} */ (err).message}`, "error"); } finally { setButtonLabel(importSettingsBtn, " Import settings"); importSettingsBtn.disabled = false; }};
////////////////////////////////////////////// 🚀////////////////////////////////////////////
foundation.ready();