feat(metadata): per-field user overrides that survive library rescans
Previously both the metadata editor (PUT /api/media-items/:id) and the
scanner (library scans, force rescans, per-book rescans) wrote through
the same unconditional UPDATE media_items query, so any rescan wiped
user-written descriptions, tags, and uploaded covers. Custom and scanned
values were indistinguishable, and custom cover uploads even wrote to
the same {file}.cover.jpg sidecar path the scanner generates, so each
side silently clobbered the other.
Introduce metadata_overrides, a TEXT[] column on media_items listing the
column names the user has customized:
- Saving metadata records overrides per field by diffing the submitted
values against the stored row (an untouched save records nothing);
overrides accumulate until an explicit reset. Cover upload/removal
always marks cover_image_path. Bulk updates mark each applied field.
- The scanner merges: updateMediaItem() now takes the existing row and
restores every overridden column (including derived *_search arrays)
before writing, and preserves the override set itself.
- Uploaded covers move to a dedicated {file}.custom_cover.{jpg|png|webp}
sidecar so the scanner can never overwrite a user cover on disk.
- RescanMediaItem gains resetOverrides: POST /api/media-items/:id/rescan?
reset_overrides=true clears the set first, returning the item to pure
scanned defaults.
Shared detection/restore helpers live in internal/utils
(metadata_overrides.go) with unit tests covering detection, accumulation,
unset-form equality, and restore-with-derived-fields. Schema change is
an idempotent ADD COLUMN IF NOT EXISTS applied on startup. Also includes
incidental gofmt of NewMediaScanner literals in media_scanner.go.
This commit is contained in:
@@ -282,10 +282,17 @@ UPDATE media_items SET
|
||||
alternate_info = $35,
|
||||
scan_information = $36,
|
||||
summary = $37,
|
||||
metadata_overrides = $38,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: ClearMediaItemMetadataOverrides :exec
|
||||
-- Reset an item to scanned defaults: clears per-field user overrides so the
|
||||
-- next rescan can freely overwrite user-customized metadata.
|
||||
UPDATE media_items SET metadata_overrides = '{}', updated_at = NOW()
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: DeleteMediaItem :exec
|
||||
DELETE FROM media_items WHERE id = $1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user