Add support for transcoding plex streams before playback#4615
Add support for transcoding plex streams before playback#4615chicco-carone wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an optional Plex-side transcoding mode so Plex streams can be delivered to Music Assistant as bandwidth-capped Opus/HLS instead of always direct-streaming the original file, plus a small HLS sub-playlist URL resolution fix.
Changes:
- Add a Plex provider config entry (
stream_quality) to choose original vs. fixed Opus bitrates (96/128/192/320 kbps). - Implement Plex HLS transcode URL generation and use it for music tracks, podcast episodes, and single-part audiobooks when configured.
- Improve HLS child-playlist URL resolution (root-relative paths) and add unit tests covering the new behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/providers/plex/test_provider_methods.py | Adds coverage for original vs transcoded stream details across track/podcast/audiobook cases. |
| tests/providers/plex/test_config_entries.py | Verifies the new stream quality config entry appears (and options/defaults) across library types. |
| tests/controllers/streams/test_hls_substream.py | Adds tests for resolving root-relative and directory-relative HLS child playlists. |
| music_assistant/translations/en.json | Adds English translations for the new Plex stream quality config entry (generated output). |
| music_assistant/providers/plex/strings.json | Adds localized strings/options for the new stream_quality config entry. |
| music_assistant/providers/plex/constants.py | Introduces constants for stream quality config key and option values. |
| music_assistant/providers/plex/init.py | Implements stream quality handling and Plex HLS transcode URL generation in stream detail methods. |
| music_assistant/controllers/streams/audio.py | Switches HLS substream URL stitching to urljoin for correct root-relative handling. |
| stream_type=StreamType.HTTP, | ||
| audio_format=audio_format, | ||
| stream_type=stream_type, | ||
| duration=plex_track.duration, |
|
Are you aware of this thread? |
|
I updated the pr so that if plex has the metadata to support transcoding the file it will transcode it else it will fallback the the previous behaviour for files that are not yet fully processed |
| }, | ||
| "stream_quality": { | ||
| "label": "Stream quality", | ||
| "description": "Audio quality to request from Plex for music tracks. Original streams the source file directly. Lower bitrates ask Plex Media Server to transcode before sending audio to Music Assistant.", |
|
Good, have you tested the behavior on a newly added track that was not analyzed? |
|
I haven't been able since if I add new tracks plex process them instantly and I don't even have the time to go I mass to test it. I'll see if I can slow it down somehow on my server to test |
|
I'm completely out of ideas on how I could test it, I gave my plex container half cpu and imported a whole series with some music to hopefully slow it down but it doesn't even appear in mass in time. If you have any ideas on how I could test this I would be happy to try it to then close this but currently i'm not sure |
|
This task also populates the size of the track, which the streaming process requires. Without it, you'll see that it raises an error and this is where it should fallback on downloading the track. |
|
This track i played it after disabling the analysis and adding it and it played back fine |
|
... and it works because you have |
|
In the provided example mass is playing back the track in opus which is correct per the settings that I set in the provider settings to transcode and its not falling back to
And its separate from the sonic analysis that you can disable in the settings For what this pr covers the transcode works fine and if there is no metadata it fallbacks to the original file works fine |
|
My server does not behave this way. The size of the file is populated only after the scheduled analysis. But you seem to say that the fallback to the original could be tested? |
|
I'm not sure how to test this in my current environment since I can't reproduce the edge case that would cause this problem. That said here in the code where it decides to transcode or not if any of the checks in the if fail for any possible reason (like plex not having the metadata) it will fallback to using download=1 which is already proven by #3561 to work in those specific cases. if (quality_bitrate := self._get_stream_quality_bitrate()) and audio_stream:
stream_details.path = self._get_transcode_url(plex_track, quality_bitrate)
stream_details.stream_type = StreamType.HLS
stream_details.audio_format.content_type = ContentType.OPUS
stream_details.audio_format.bit_rate = quality_bitrate
return stream_details
download_url = self._plex_server.url(f"{media_part.key}?download=1", True) |


What does this implement/fix?
Add support into the plex provider to let the server transcode audio before sending it to MA to reduce streaming bandwidth limits. Plex supports calling its api from a different endpoint and specifying the bitrate and codec to stream from the server to avoid always streaming the original file, this pr adds into the provider settings an option to choose either the original quality or opus at a specific bitrate. To avoid issues when updating it defaults to original which was the previous behavior and then the user if needed can change it.
Related issue (if applicable):
This issue was discussed in the MA discord server in the following thread Thread Link
Types of changes
bugfixnew-featureenhancementnew-providerbreaking-changerefactordocumentationmaintenancecidependenciesChecklist
pre-commit run --all-filespasses.pytestpasses, and tests have been added/updated undertests/where applicable.music-assistant/modelsis linked.music-assistant/frontendis linked.