Skip to content

feature: multi-part m4b merging - #120

Open
benjitobz wants to merge 4 commits into
Chaptarr:developfrom
benjitobz:feature/m4b-merge-multi-part
Open

benjitobz wants to merge 4 commits into
Chaptarr:developfrom
benjitobz:feature/m4b-merge-multi-part

Conversation

@benjitobz

Copy link
Copy Markdown

Description

Chaptarr already merges multi-part audiobook downloads into a single M4B when conversion is planned, but releases that arrive as multiple M4B parts are skipped entirely — since no format conversion was needed. This adds an opt-in "Create Single File" setting on quality profiles: when enabled, multi-part downloads whose parts are already M4B are merged into one M4B file on import. Embedded chapters from each part are preserved and re-offset in the merged file, so chapter navigation survives the concatenation instead of being lost. With the setting off (the default), behavior is unchanged. Reason for adding this is it's nice to have the books in one file, especially while using ABS in a vehicle.

Fixes # — n/a (feature)

Database Migration

YES - Migration 103_add_quality_profile_merge_multi_part_files:

  • Adds a MergeMultiPartFiles boolean column (not-null, default false) to the QualityProfiles table, guarded by an existence check.
  • The fresh-install baseline schema (001_chaptarr_complete_schema) is updated to include the same column.

How was this tested?

Docker (linux/amd64) on an Ubuntu server host, image built with Dockerfile.build. Exercised with real multi-part audiobook releases:

  • With "Create Single File" enabled on the profile: multi-part M4B releases are merged into a single M4B on import, and the merged file's chapters were verified present and correctly offset across part boundaries.
  • With the setting disabled: multi-part M4B releases import unchanged (parts kept), confirming the gate defaults to existing behavior.
  • Existing multi-part MP3 → M4B conversion paths re-tested to confirm they're unaffected.
  • Migration verified on an existing database (column added, profiles default to off) and on a fresh install via the baseline schema.

Screenshots (UI changes only) - (red box is just show the change not actually present in the UI)

image

A note on AI: We know AI/agentic coding is everywhere and only getting
more popular. We won't insist that you disclose whether you used it or which
models you used, but in the same spirit, please don't take offense if your PR
is scrutinized and changes are requested.

Review time: The longer the PR and the more lines changed, the longer the
review will take. Small, focused PRs merge fastest. If yours is big, please be
patient.

@benjitobz benjitobz changed the title Multi-part M4B merging feature: Multi-part M4B merging Sep 3, 2026
@benjitobz benjitobz changed the title feature: Multi-part M4B merging feature: multi-part m4bmerging Sep 3, 2026
@benjitobz
benjitobz force-pushed the feature/m4b-merge-multi-part branch from 8979369 to ad97b78 Compare September 3, 2026 20:00
@benjitobz benjitobz changed the title feature: multi-part m4bmerging feature: multi-part m4b merging Sep 3, 2026

@bhoffman20 bhoffman20 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. A few issues with the merged output and with how a failed merge is handled; details inline. Test notes are in a separate comment.

Comment thread src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs Outdated
Comment thread src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs
Comment thread src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs
Comment thread src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs
Comment thread src/NzbDrone.Core/Localization/Core/en.json Outdated
Comment thread src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs Outdated
@bhoffman20

Copy link
Copy Markdown
Collaborator

Process: native Linux dev instance with "Create Single File" on and Convert to Quality = M4B. I moved a seeding 5-part M4B release (The Fifth Risk; 22.05 kHz, 63 kbps, 13 embedded chapters) into the Chaptarr category and let it import. I also ran m4b-tool directly on a 63-part release (Equal Rites; 44.1 kHz, 125 kbps) to compare re-encoding with --no-conversion.

Results:

  • Pass: the parts merged into a single M4B with the correct duration and the embedded cover.
  • Fail: chapters. Expected the 13 embedded chapters, re-offset. Got 5 chapters named after the files, at the part boundaries.
  • Fail: audio quality. Expected the source format. Got a re-encode at 16 kHz, down from 22.05 kHz (bitrate 63 → 61 kbps).
  • Fail: tags. Expected single-file tags. Got track=1/5 carried over, and the title replaced by the album value.
  • Pass: --no-conversion on both releases kept the source codec, sample rate, and bitrate, with an exact duration; Equal Rites merged in 29 s instead of 75 s.
  • Pass: no m4b-tool errors with silent parts, very short parts, or long trailing silence.
  • Pass: migration 103 applied on an existing DB already at 107.

- Renumber the migration to 108; 104-107 are already released.
- Reword the help text to say the setting only merges multi-part M4B downloads.
- Reuse mergeMultiPartM4b instead of re-reading the profile flag.
- Carry each part's embedded chapters into the merged file, offset by the
  preceding parts' durations, instead of one filename chapter per part.
- Merge with --no-conversion when every part shares codec, sample rate and
  channel count, so the source audio is kept as-is.
- Drop the parts' track/disc tags and keep the title the parts share instead
  of replacing it with the album value.
- Import the parts unmerged when the optional merge fails, instead of
  rejecting the whole book.

@bhoffman20 bhoffman20 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All earlier comments are fixed in de309dc. Thanks!

Test notes (native Linux dev instance, Convert to Quality = M4B):

  • Pass: a 5-part M4B release merged without re-encoding (AAC, 22.05 kHz, ~63 kbps kept), with an exact duration.
  • Pass: embedded chapters were carried over. A synthetic release with chapters inside each part merged with every chapter at the correct time; a part without chapters fell back to the file name.
  • Pass: track tags removed; title kept from the parts.
  • Pass: with m4b-tool forced to fail, the parts imported unmerged.
  • Pass: with the setting off, the parts imported unchanged.
  • Pass: migration 108 applied on an existing DB.

Found while testing, but not caused by this PR: #284. Re-importing a book that already has a merged file runs the merge, then fails the import.

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