[PR #4957] feat: Add sampleRate and profile extraction for audio files #4381

Open
opened 2026-04-25 00:19:32 +02:00 by adam · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/advplyr/audiobookshelf/pull/4957
Author: @H2OKing89
Created: 1/3/2026
Status: 🔄 Open

Base: masterHead: add-audio-samplerate-profile


📝 Commits (3)

  • fadd144 Add sampleRate and profile extraction for audio files
  • 194f018 feat: Embed AUDIBLE_ASIN metadata in m4b files
  • 47f6f4e Revert ASIN changes - moved to separate PR #4959

📊 Changes

4 files changed (+18 additions, -5 deletions)

View changed files

📝 server/models/Book.js (+2 -0)
📝 server/objects/files/AudioFile.js (+13 -5)
📝 server/scanner/MediaProbeData.js (+2 -0)
📝 server/utils/prober.js (+1 -0)

📄 Description

Brief summary

Adds extraction and persistence of sampleRate and profile for audio files during library scanning. Both values are present in ffprobe output but were not fully captured or propagated into the AudioFile API payload.

Which issue is fixed?

Enhancement - no specific issue linked

In-depth Description

How it works

Audio metadata flows through the scanner pipeline and now captures two additional fields:

┌──────────────────────────────────────────────────────────────────┐
│  Audio Metadata Extraction Pipeline                              │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ffprobe                                                         │
│     │                                                            │
│     ├─► audio_stream.sample_rate ────────┐                       │
│     └─► audio_stream.profile ─────────┐  │                       │
│                                       │  │                       │
│                                       ▼  ▼                       │
│                             server/utils/prober.js               │
│                                        │                         │
│                                        ▼                         │
│                       server/scanner/MediaProbeData.js           │
│                        • sampleRate + profile captured           │
│                                        │                         │
│                                        ▼                         │
│                    server/objects/files/AudioFile.js             │
│                     • setDataFromProbe() persists both           │
│                     • toJSON() exposes via API                   │
│                                        │                         │
│                                        ▼                         │
│                         API Response                             │
│                   {                                              │
│                     "sampleRate": 44100,                         │
│                     "profile": "xHE-AAC"                         │
│                   }                                              │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

What changed

Files modified in pipeline order:

  • server/utils/prober.js: Extract profile from audio stream ffprobe output
  • server/scanner/MediaProbeData.js: Populate profile property; ensure sampleRate is included (previously available in probe data but not fully propagated to AudioFile)
  • server/objects/files/AudioFile.js: Add sampleRate and profile to constructor, toJSON(), construct(), and setDataFromProbe() to persist and expose both fields via API
  • server/models/Book.js: Add JSDoc @property documentation for API typing/docs

Why this solution?

These fields provide useful technical information for library management and playback troubleshooting:

  • Sample Rate: Indicates audio quality (44.1kHz, 48kHz, etc.) - helps validate source quality and consistency
  • Profile: Distinguishes AAC variants (LC vs HE-AAC vs xHE-AAC), which have different performance characteristics across devices/players

The values already exist in ffprobe output — this PR completes the pipeline so they become available to:

  • API consumers who need detailed audio metadata
  • Frontend UI displays (see #4958 for the UI implementation)
  • Troubleshooting workflows (codec/profile mismatches)

Does it solve a problem that affects multiple users?
Yes - users managing high-quality audiobook libraries benefit from visibility into technical audio specifications, especially when comparing encodings or troubleshooting playback issues across different devices.

API Response Example (After Rescan)

{
  "index": 1,
  "duration": 104183.760862,
  "format": "QuickTime / MOV",
  "bitRate": 118653,
  "codec": "aac",
  "channels": 2,
  "channelLayout": "stereo",
  "sampleRate": 44100,
  "profile": "xHE-AAC"
}

How have you tested this?

Manual Verification:

Tested with two audiobooks:

Title Codec Profile Sample Rate
He Who Fights with Monsters Vol 1 AAC xHE-AAC 44100
He Who Fights with Monsters Vol 3 AAC LC 44100

Reproducible test steps:

  1. Started dev server
  2. Created test library pointing to audiobook folder
  3. Scanned library
  4. Called GET /api/items/{id}?expanded=1
  5. Confirmed sampleRate and profile fields populated in media.audioFiles[]

Edge case verified:
Files without profile data return null/omit the field as expected.

Screenshots

N/A - Backend/API change only (no UI modifications).

Notes:

  • Existing library items require rescan to populate these fields
  • Frontend display added in #4958

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/advplyr/audiobookshelf/pull/4957 **Author:** [@H2OKing89](https://github.com/H2OKing89) **Created:** 1/3/2026 **Status:** 🔄 Open **Base:** `master` ← **Head:** `add-audio-samplerate-profile` --- ### 📝 Commits (3) - [`fadd144`](https://github.com/advplyr/audiobookshelf/commit/fadd14484e53aa14a840a38e2511026522005d04) Add sampleRate and profile extraction for audio files - [`194f018`](https://github.com/advplyr/audiobookshelf/commit/194f0189fc89b28e9ab01b7342359abc5f8e3dfd) feat: Embed AUDIBLE_ASIN metadata in m4b files - [`47f6f4e`](https://github.com/advplyr/audiobookshelf/commit/47f6f4e18a063a488612d3a793f5ffb552477f33) Revert ASIN changes - moved to separate PR #4959 ### 📊 Changes **4 files changed** (+18 additions, -5 deletions) <details> <summary>View changed files</summary> 📝 `server/models/Book.js` (+2 -0) 📝 `server/objects/files/AudioFile.js` (+13 -5) 📝 `server/scanner/MediaProbeData.js` (+2 -0) 📝 `server/utils/prober.js` (+1 -0) </details> ### 📄 Description ## Brief summary Adds extraction and persistence of `sampleRate` and `profile` for audio files during library scanning. Both values are present in ffprobe output but were not fully captured or propagated into the AudioFile API payload. ## Which issue is fixed? Enhancement - no specific issue linked ## In-depth Description ### How it works Audio metadata flows through the scanner pipeline and now captures two additional fields: ``` ┌──────────────────────────────────────────────────────────────────┐ │ Audio Metadata Extraction Pipeline │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ ffprobe │ │ │ │ │ ├─► audio_stream.sample_rate ────────┐ │ │ └─► audio_stream.profile ─────────┐ │ │ │ │ │ │ │ ▼ ▼ │ │ server/utils/prober.js │ │ │ │ │ ▼ │ │ server/scanner/MediaProbeData.js │ │ • sampleRate + profile captured │ │ │ │ │ ▼ │ │ server/objects/files/AudioFile.js │ │ • setDataFromProbe() persists both │ │ • toJSON() exposes via API │ │ │ │ │ ▼ │ │ API Response │ │ { │ │ "sampleRate": 44100, │ │ "profile": "xHE-AAC" │ │ } │ │ │ └──────────────────────────────────────────────────────────────────┘ ``` ### What changed Files modified in pipeline order: - **server/utils/prober.js**: Extract `profile` from audio stream ffprobe output - **server/scanner/MediaProbeData.js**: Populate `profile` property; ensure `sampleRate` is included (previously available in probe data but not fully propagated to AudioFile) - **server/objects/files/AudioFile.js**: Add `sampleRate` and `profile` to constructor, `toJSON()`, `construct()`, and `setDataFromProbe()` to persist and expose both fields via API - **server/models/Book.js**: Add JSDoc `@property` documentation for API typing/docs ### Why this solution? These fields provide useful technical information for library management and playback troubleshooting: - **Sample Rate**: Indicates audio quality (44.1kHz, 48kHz, etc.) - helps validate source quality and consistency - **Profile**: Distinguishes AAC variants (LC vs HE-AAC vs xHE-AAC), which have different performance characteristics across devices/players The values already exist in ffprobe output — this PR completes the pipeline so they become available to: - API consumers who need detailed audio metadata - Frontend UI displays (see #4958 for the UI implementation) - Troubleshooting workflows (codec/profile mismatches) **Does it solve a problem that affects multiple users?** Yes - users managing high-quality audiobook libraries benefit from visibility into technical audio specifications, especially when comparing encodings or troubleshooting playback issues across different devices. ### API Response Example (After Rescan) ```json { "index": 1, "duration": 104183.760862, "format": "QuickTime / MOV", "bitRate": 118653, "codec": "aac", "channels": 2, "channelLayout": "stereo", "sampleRate": 44100, "profile": "xHE-AAC" } ``` ## How have you tested this? **Manual Verification:** Tested with two audiobooks: | Title | Codec | Profile | Sample Rate | | ------- | ------- | --------- | ------------- | | He Who Fights with Monsters Vol 1 | AAC | xHE-AAC | 44100 | | He Who Fights with Monsters Vol 3 | AAC | LC | 44100 | **Reproducible test steps:** 1. Started dev server 2. Created test library pointing to audiobook folder 3. Scanned library 4. Called `GET /api/items/{id}?expanded=1` 5. Confirmed `sampleRate` and `profile` fields populated in `media.audioFiles[]` **Edge case verified:** Files without profile data return null/omit the field as expected. ## Screenshots N/A - Backend/API change only (no UI modifications). **Notes:** - Existing library items require rescan to populate these fields - Frontend display added in #4958 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
adam added the pull-request label 2026-04-25 00:19:32 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf#4381