fix(import): actually embed the ASIN after an import - #843
Open
m4bard wants to merge 1 commit into
Open
Conversation
Two independent faults stop the post-import ASIN write from reaching the file. The import reports success either way, because the enrichment step is deliberately non-fatal, so neither is visible without reading the destination file's tags. The stream is write-only. TagLibAudioTagWriter's file abstraction hands TagLib the lease's metadata write stream, which reaches OpenIndependentWriteStream and opens O_WRONLY on Unix, or NtCreateFile without GenericRead on Windows. Mpeg4.File.Save() parses the existing box headers through that same stream before it writes, so it throws NotSupportedException mid-parse. Open read+write instead, via a new UnixOpenFlags.OpenReadWriteNoFollow() alongside the existing OpenWriteNoFollow(). The tag lookup never matches on MPEG-4. ApplyAsinTag tests `file.Tag is AppleTag`, but an MPEG-4 file's Tag is a CombinedTag wrapping the Apple tag, so the branch is never taken. The Id3v2 and Xiph branches do not match an m4b either, so Save() rewrites an unchanged file and the writer logs success. Ask for the tag by type instead. Only MPEG-4 answers to Apple, so mp3 and flac fall through as before. The second fault matters for how the first is judged: fixing only the stream turns a logged failure into a silent one. That was observed on a build carrying just the stream change, not predicted. Pinning is unaffected. The handle is still opened relative to the pinned parent, still refuses to follow a link, and is still checked against the validated file object. Widening the access mode does not widen what the lease will open. Rebuilt on top of Listenarrs#828, which replaced the hardcoded open-flag constants with UnixOpenFlags. The new method inherits that commit's per-architecture noFollow detection rather than reintroducing a literal.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
After a successful manual import, the step that writes the book's ASIN into the imported file's own tags never gets there. Two independent faults, and the import reports success through both of them, because the enrichment step is deliberately non-fatal.
Full write-up, measurements and the one decision I did not want to make myself are in #842.
Changes
Fixed
UnixOpenFlagsgainsOpenReadWriteNoFollow()beside the existingOpenWriteNoFollow().PinnedFileEntry.OpenIndependentWriteStreambecomesOpenIndependentReadWriteStreamand uses it, so the stream handed to TagLib can be read as well as written.Mpeg4.File.Save()parses the existing box structure through that same stream before writing, so a write-only handle throwsNotSupportedExceptionmid-parse.ApplyAsinTagasks for the tag by type,file.GetTag(TagTypes.Apple, create: true), rather than testingfile.Tag is AppleTag. An MPEG-4 file'sTagis aCombinedTagwrapping the Apple tag, so the type test never matched andSave()rewrote an unchanged file. Only MPEG-4 answers to Apple, so mp3 and flac fall through as before.The second fault is why the first one alone is not enough. On a build carrying only the stream change, the writer stops throwing and logs
Wrote ASIN tagat Debug for a file whose bytes did not change. That was observed on the way through rather than predicted.Pinning is unchanged. The handle is still opened relative to the pinned parent, still refuses to follow a link, and is still checked against the validated file object. Widening the access mode does not widen what the lease will open.
Testing
PinnedAudiobookFileRegistrationLeaseTestsgains a case asserting the metadata write stream is readable, seekable and returns the file's existing bytes. Verified as a real guard in both directions: withFileAccess.Writerestored it fails onCanRead, and with the change it passes.UnixOpenFlagsTestsgains a case for the new method, asserting that only the access-mode bits differ fromOpenWriteNoFollowand that everything else is identical. It is written as a difference rather than as a literal on purpose, since #828 established thatnoFollowis not the same value on arm64 and x64.Full suite on this branch: 3,031 passed, 0 failed, 125 skipped, against a 3,029 baseline on
03958c15.Reproduced end to end before and after against
ghcr.io/listenarrs/listenarr:canary. On canary the imported file reads untagged with oneFailed to write ASIN tagin the log; on a build of this branch it reads tagged and ffprobe reports the ASIN on the destination. The check is public, in the test-data repo linked from the issue, and it refuses a verdict unless a hand-stamped control reads tagged and the input file reads untagged in the same run.Notes
This is rebuilt on top of #828. The earlier version of the change added a
bool readableparameter toGetUnixWriteExistingFlags, which that commit deleted. Adding a sibling method to the new helper is both smaller and better, since it picks up the per-architecturenoFollowdetection rather than carrying a literal of its own.One thing I would rather you decided than me, and it is the reason this is worth a look beyond the diff. The lease exists to fence a specific generation of a specific file, and I do not know whether write-only was a deliberate part of that. Nothing reads back through the handle today and the pinning is enforced separately, which is why I think widening it is safe. If it was deliberate, the fix belongs elsewhere: open a separate read+write handle for tagging and verify identity against the lease, rather than widening the lease's own. Say so and I will redo it that way.