Skip to content

feat(v3 library): "Write to file" in the Fix-metadata popup#778

Merged
byrongamatos merged 2 commits into
mainfrom
feat/v3-write-to-file
Jul 5, 2026
Merged

feat(v3 library): "Write to file" in the Fix-metadata popup#778
byrongamatos merged 2 commits into
mainfrom
feat/v3-write-to-file

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Completes the confirmed edit model for the Fix-metadata popup (stacked on #777).

Today the popup's Save keeps edits as a reversible display overlay — the pack/.sloppak files are never touched. This adds the deliberate opt-in counterpart: Write to file bakes the shown title / artist / album / year into the pack itself, so other tools/apps see the corrected tags and the fix survives a full rescan.

How

  • Reuses the existing POST /api/song/{fn}/meta (already on main: writes the manifest via songmeta.write_song_metadata, re-stats, coalesces a rescan). No new backend — and no dependency on the heavier v3 library: per-field pack overwrite (R4b) — fix wrong author values, with receipts [DRAFT: gated on spec §7] #733 overwrite-with-backups feature, which is a separate thing.
  • On a real file write (persisted: true): the now-redundant override values are cleared (any locks are kept), and the Details tab re-renders — so the fields read from the file as Pack, honestly reflecting that the fix now lives in the pack, not just the overlay.
  • Loose-folder / unwritable packs fall back to the endpoint's DB-only update; the UI says so plainly ("may revert on a full rescan") and keeps the overlay.

UX

  • A secondary Write to file button beside the primary Save (Save stays the default, non-destructive path — matches the "files untouched unless you ask" ethos). Tooltip spells out that it's permanent and touches only the four fields, leaving the rest of the pack verbatim.

Testing

  • node --check clean. Verified on the testbed against the real library: the write path returns persisted: true (repacks the .feedpak); Save vs Write-to-file are distinct, and a persisted write flips the field provenance from Yours to Pack.

Stacked on #777 — merge that first (or land them together).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a “Write to file” option in the Details tab for metadata edits.
    • Users can now permanently apply shown title, artist, album, and year values to the stored song file, in addition to the existing reversible save behavior.
  • Bug Fixes

    • Improved status messaging to clearly distinguish between temporary overlay changes and changes written to the file.
    • After a successful write, the display now refreshes to reflect the updated stored metadata while preserving field locks.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bed24f31-69bd-4ea3-b46d-f65f2308830b

📥 Commits

Reviewing files that changed from the base of the PR and between af1170c and 0735d44.

📒 Files selected for processing (1)
  • static/v3/match-review.js

📝 Walkthrough

Walkthrough

Added a "Write to file" workflow to the Details tab metadata editor in match-review.js, alongside the existing reversible "Save" overlay behavior. Introduced a new footer button wired to an async writeToFile handler that posts edited fields to the metadata API, updates in-memory state, and conditionally clears overrides on persistence.

Changes

Write to File Feature

Layer / File(s) Summary
Details tab UI and button wiring
static/v3/match-review.js
Updated explanatory text and status placeholder, replaced the footer action row with a new "Write to file" button, and wired its click handler to invoke writeToFile(body, song).
writeToFile implementation
static/v3/match-review.js
Implemented async writeToFile that disables controls, POSTs edited title/artist/album/year to /api/song/{fn}/meta, mirrors server-coerced values, emits library:changed, clears overrides and re-renders on persistence, or falls back to keeping the overlay, with error handling to restore controls.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DetailsTab
  participant writeToFile
  participant API as /api/song/{fn}/meta
  participant Library

  User->>DetailsTab: click Write to file
  DetailsTab->>writeToFile: writeToFile(body, song)
  writeToFile->>API: POST edited title/artist/album/year
  API-->>writeToFile: response (persisted, coerced values)
  writeToFile->>Library: emit library:changed (reason write)
  alt persisted
    writeToFile->>DetailsTab: clear overrides, keep locks, re-render tab
    writeToFile->>DetailsTab: set status "Written to the song file."
  else not persisted
    writeToFile->>DetailsTab: keep overlay, set fallback status
  end
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v3-write-to-file
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/v3-write-to-file

Comment @coderabbitai help to get the list of available commands.

@ChrisBeWithYou

Copy link
Copy Markdown
Contributor Author

📋 Merge order — metadata-curation epic (7 PRs)

  1. feat(v3 library): "Fix metadata" popup — per-song override + lock, cover picker, MusicBrainz + AcoustID #777 — Fix-metadata popup
  2. feat(v3 library): "Write to file" in the Fix-metadata popup #778 — Write to file
  3. feat(v3 library): Match→Details "use these values" bridge #779 — Match→Details bridge
  4. feat(v3 library): genre field in the Fix-metadata popup #780 — Genre in Details
  5. feat(v3 library): persistent "no match" badge + Unmatched quick filter #781 — No-match badge + Unmatched filter (independent of 1–4 — fine to merge any time)
  6. feat(v3 library): batch→popup handoff + English-base romaji (metadata-curation capstone) #782 — Batch→popup handoff + romaji (capstone)
  7. feat(v3 library): searchable Cover Art Archive picker in Change-cover #783 — Searchable cover picker

#778#780 are stacked (each based on the branch above), so GitHub re-points each to main automatically as the previous one merges — just merge #777#778#779#780 top-down. #781 is independent (base: main).

⚠️ Hold #782 and #783 until #777#781 are all in main. #782's branch is a combined branch that already contains #777#781, so merging it early would double-merge the stack. Once #777#781 land, the author will rebase #782 (then #783) onto main — they shrink to just their own commits — and they're then ready to merge.

ChrisBeWithYou and others added 2 commits July 5, 2026 21:09
Completes the confirmed edit model: Save keeps edits as a reversible display
overlay (files untouched); "Write to file" bakes the shown title/artist/album/
year into the pack itself via the existing POST /api/song/{fn}/meta (writes the
manifest, re-stats, coalesces a rescan). On a real file write the now-redundant
override values are cleared (locks kept) and the tab re-renders, so the fields
read from the file as "Pack". Loose-folder / unwritable packs fall back to a
DB-only update and say so (may revert on a full rescan). Secondary button next
to Save; touches only the four file-safe fields, the rest of the pack verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
update_song_meta coerces a non-numeric/empty year to "" before persisting,
but writeToFile optimistically set song.year to the raw typed text — so the
library card flashed e.g. "abcd" until the next natural refresh. Apply the
same integer coercion client-side so the in-memory song matches what was
written.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@byrongamatos
byrongamatos force-pushed the feat/v3-write-to-file branch from 5f10762 to 0735d44 Compare July 5, 2026 19:10
@byrongamatos
byrongamatos changed the base branch from feat/v3-fix-metadata-popup to main July 5, 2026 19:10
@byrongamatos
byrongamatos merged commit 5f499a8 into main Jul 5, 2026
1 check was pending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants