From 2bec8d9d6027b2aa84368589c8592cb31c0c5e91 Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Thu, 30 Jul 2026 18:27:52 +0200 Subject: [PATCH] chore: store file manager files as CID + extension --- src/components/upload/dropbox/common.js | 8 +- src/facets/data/file-manager/index.inline.js | 182 ++++++++++++++++--- src/facets/data/file-manager/styles.css | 8 + 3 files changed, 168 insertions(+), 30 deletions(-) diff --git a/src/components/upload/dropbox/common.js b/src/components/upload/dropbox/common.js index 8cfd0f57..c4e9ff50 100644 --- a/src/components/upload/dropbox/common.js +++ b/src/components/upload/dropbox/common.js @@ -30,10 +30,14 @@ export async function uploadFile(refreshToken, destinationPath, file) { headers: { "Authorization": `Bearer ${accessToken}`, "Content-Type": "application/octet-stream", + // `overwrite` is safe because uploads are content-addressed: the + // filename is `.`, so the same bytes always map to the same + // path (overwrite is a no-op) and different bytes get a different path + // (no conflict). This makes re-uploads idempotent instead of spawning + // autorenamed duplicates. "Dropbox-API-Arg": JSON.stringify({ path: destinationPath, - mode: "add", - autorename: true, + mode: "overwrite", mute: true, }).replace(/[^\x00-\x7F]/g, (ch) => "\\u" + ("0000" + ch.charCodeAt(0).toString(16)).slice(-4) diff --git a/src/facets/data/file-manager/index.inline.js b/src/facets/data/file-manager/index.inline.js index 7475d54e..5a68d004 100644 --- a/src/facets/data/file-manager/index.inline.js +++ b/src/facets/data/file-manager/index.inline.js @@ -33,6 +33,10 @@ const SYNC_SCHEME_KEY = "file-manager:sync-scheme"; /** IDB key for storing a pending delete path (retried after reconnection). */ const PENDING_DELETE_KEY = "file-manager:pending-delete"; +/** IDB key for a persisted map of CID → original filename, so the + * "Artist - Title" label survives upload (remote tracks) and reloads. */ +const CID_NAMES_KEY = "file-manager:cid-names"; + foundation.setup({ title: "File Manager | Diffuse" }); //////////////////////////////////////////// @@ -64,7 +68,12 @@ await Promise.all([ /** Maps ephemeral cache URIs to their original filename. */ const ephemeralNames = new Map(); -/** Bumped whenever `ephemeralNames` is updated so the reactive effect re-fires. */ +/** Maps a content CID to its original filename. Persisted to IDB so the label + * is available for remote tracks (after upload) and across reloads. */ +const cidNames = new Map(); + +/** Bumped whenever `ephemeralNames` or `cidNames` is updated so the reactive + * effect re-fires (they're plain Maps, not signals). */ const namesVersion = signal(0); /** Tracks the upload button state: "idle", "caching", or "uploading". */ @@ -78,7 +87,7 @@ const syncScheme = signal(/** @type {string | null} */ (null)); //////////////////////////////////////////// /** - * @typedef {{ name: string; onRemove: () => void }} FileItem + * @typedef {{ name: string; subtitle?: string; onRemove: () => void }} FileItem */ /** @@ -174,11 +183,14 @@ function renderFileList(listEl, items, prefix) { litRender( html` ${items.map( - ({ name, onRemove }, index) => + ({ name, subtitle, onRemove }, index) => html`
  • ${name} + ${subtitle + ? html`${subtitle}` + : null}