Skip to content

feat: audio transcoding endpoint for offline downloads (MP3/AAC)#97

Merged
mateof merged 1 commit into
developfrom
feat/audio-transcode-downloads
Jul 19, 2026
Merged

feat: audio transcoding endpoint for offline downloads (MP3/AAC)#97
mateof merged 1 commit into
developfrom
feat/audio-transcode-downloads

Conversation

@mateof

@mateof mateof commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

The TFM Audio PWA can now offer offline playlist downloads in MP3/AAC so lossless files (FLAC) take 5-8x less space on the phone. This PR adds the server side: an FFmpeg-based transcoding endpoint with disk caching, plus a capabilities endpoint so clients can detect whether FFmpeg is installed and warn the user.

Endpoints

  • GET /api/mobile/stream/transcode/info — reports { ffmpegAvailable, formats }. Clients must check this (or handle the 501 below) and fall back to original-format downloads when FFmpeg is missing.
  • GET /api/mobile/stream/tfm/{channelId}/{tfmId}/transcoded?format=mp3|aac&bitrate=64..320&fileName=...
    1. Ensures the original is fully cached in _temp (sequential 512KB Telegram download, same cache file the streaming endpoints use).
    2. Transcodes with FFmpeg (libmp3lame / native aac), writing to a .part file and moving into place so partial results are never served.
    3. Serves the cached result via PhysicalFile with full Range support. Repeat requests hit the disk cache under _temp/transcoded.

Safeguards

  • 501 Not Implemented when FFmpeg is not installed (checked once and cached; transcode/info reports it too).
  • Per-target locks prevent duplicate transcodes of the same file/format/bitrate; a global semaphore caps concurrent FFmpeg processes at 2.
  • FFmpeg process is killed (entire tree) and the partial output deleted if the client aborts; non-zero exit codes surface the stderr tail in the server log.
  • MP3 output keeps tags and embedded cover art (-map 0:v? -c:v copy -disposition:v:0 attached_pic); AAC/m4a keeps tags (-map_metadata 0).

Notes

  • First request for a track can take a while (Telegram download + transcode happen synchronously before the response); subsequent requests are instant.
  • No new configuration: FFmpeg is resolved from PATH, matching the existing video transcoding feature.

Test plan

  • GET /api/mobile/stream/transcode/info returns ffmpegAvailable: true on a host with FFmpeg, false without it.
  • Request a FLAC track with ?format=mp3&bitrate=192: response is a valid MP3 (~5-8x smaller), with tags/cover; file appears under local/temp/_temp/transcoded/.
  • Second request for the same track returns instantly (cache hit).
  • ?format=aac produces a playable .m4a.
  • Without FFmpeg installed, the endpoint returns 501 with a JSON error.

🤖 Generated with Claude Code

- GET api/mobile/stream/tfm/{channelId}/{tfmId}/transcoded?format=mp3|aac&bitrate=N
  downloads the original into the streaming cache if needed, transcodes it
  with FFmpeg and serves the result with Range support; transcodes are
  cached on disk under _temp/transcoded so repeat requests are instant
- GET api/mobile/stream/transcode/info reports FFmpeg availability so
  clients can warn the user and fall back to original downloads
- Returns 501 when FFmpeg is missing; per-target locks avoid duplicate
  transcodes and a semaphore caps concurrent FFmpeg processes at 2
- MP3 keeps embedded cover art and tags; AAC (m4a) keeps tags
@mateof
mateof merged commit 543e66f into develop Jul 19, 2026
@mateof
mateof deleted the feat/audio-transcode-downloads branch July 19, 2026 17:32
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.

1 participant