Skip to content

Avoid MPD manifest parsing to fix regression with new TIDAL group="main" manifests#216

Merged
blacklight merged 1 commit intoEbbLabs:mainfrom
blacklight:fix/updated-handling-of-media-manifest
Jan 15, 2026
Merged

Avoid MPD manifest parsing to fix regression with new TIDAL group="main" manifests#216
blacklight merged 1 commit intoEbbLabs:mainfrom
blacklight:fix/updated-handling-of-media-manifest

Conversation

@blacklight
Copy link
Copy Markdown
Collaborator

@blacklight blacklight commented Jan 15, 2026

TIDAL appears to have changed the MPEG-DASH MPD manifests returned for some streams to include non-numeric values in <AdaptationSet group="..."> (e.g. group="main").

The current mpegdash parser expects group to be an integer and raises a ValueError, which tidalapi wraps as ManifestDecodeError. This caused mopidy-tidal playback to fail and tracks to be marked “not playable”.

This PR updates mopidy-tidal’s playback provider to avoid parsing MPD manifests via tidalapi/mpegdash.

For MPD manifests we only need to persist the MPD XML and return a file:// URI, so parsing is unnecessary.

Root cause

Changes

  • MPD path (ManifestMimeType.MPD)
    • Stop calling stream.get_stream_manifest() (this triggers MPD parsing and the crash)
    • Use stream.get_manifest_data() to fetch raw MPD XML
    • Write the MPD to manifest.mpd in the extension cache directory
    • Return file://…/manifest.mpd for playback (same end result as before, but without parsing)
  • BTS path (ManifestMimeType.BTS)
    • Keep existing behavior using stream.get_stream_manifest()

Why this is safe

mopidy-tidal already ultimately plays MPD by writing it to disk and handing Mopidy a file:// URI.

The parsed MPD data from tidalapi wasn’t required for playback logic here; it was effectively only used for logging (codecs).

Closes: EbbLabs/python-tidal#396

…TIDAL group="main" manifests

TIDAL appears to have changed the MPEG-DASH MPD manifests returned for
some streams to include non-numeric values in
`<AdaptationSet group="...">` (e.g. group="main").

The current `mpegdash` parser expects group to be an integer and raises
a `ValueError`, which `tidalapi` wraps as `ManifestDecodeError`. This
caused `mopidy-tidal` playback to fail and tracks to be marked “not
playable”.

This PR updates mopidy-tidal’s playback provider to avoid parsing MPD
manifests via tidalapi/mpegdash.

For MPD manifests we only need to persist the MPD XML and return a
`file://` URI, so parsing is unnecessary.

**Root cause**

- [`tidalapi.StreamManifest`](https://github.com/EbbLabs/python-tidal/blob/08742362ee8cef7df1362387cef60c2846aa84ee/tidalapi/media.py#L644) → [`DashInfo.from_mpd()`](https://github.com/EbbLabs/python-tidal/blob/08742362ee8cef7df1362387cef60c2846aa84ee/tidalapi/media.py#L770) → `mpegdash` parser

- New MPD contains: `<AdaptationSet ... group="main" ...>`

- [`mpegdash` tries to parse group as int](https://github.com/sangwonl/python-mpegdash/blob/48b52122cdbcaebe1804b79f77d05dfc1ce32900/mpegdash/nodes.py#L782) → `ValueError` → `tidalapi.exceptions.ManifestDecodeError`

- Mopidy logs: backend exception + _Track is not playable_

**Changes**

- **MPD path** (`ManifestMimeType.MPD`)
    - Stop calling `stream.get_stream_manifest()` (this triggers MPD
      parsing and the crash)
    - Use `stream.get_manifest_data()` to fetch raw MPD XML
    - Write the MPD to `manifest.mpd` in the extension cache directory
    - Return `file://…/manifest.mpd` for playback (same end result as
      before, but without parsing)
- **BTS path** (ManifestMimeType.BTS)
    - Keep existing behavior using stream.get_stream_manifest()

**Why this is safe**

mopidy-tidal already ultimately plays MPD by writing it to disk and
handing Mopidy a `file://` URI.

The parsed MPD data from tidalapi wasn’t required for playback logic
here; it was effectively only used for logging (codecs).

Closes: EbbLabs/python-tidal#397
@blacklight blacklight changed the title fix(playback): Avoid MPD manifest parsing to fix regression with new … Avoid MPD manifest parsing to fix regression with new TIDAL group="main" manifests Jan 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request fixes a regression in TIDAL playback caused by recent changes to TIDAL's MPEG-DASH MPD manifests that include non-numeric group attributes. The fix avoids unnecessary MPD manifest parsing that was causing ValueError exceptions.

Changes:

  • Removed top-level call to stream.get_stream_manifest() that was triggering MPD parsing errors
  • Moved manifest parsing to only occur for BTS manifest types where it's actually needed
  • Split playback logging into separate MPD and BTS code paths, with codec information only logged for BTS

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mopidy_tidal/playback.py
Comment thread mopidy_tidal/playback.py
Comment on lines +44 to +51
logger.info(
"Starting playback of track:{}, (quality:{}, {}bit/{}Hz)".format(
track_id,
stream.audio_quality,
stream.bit_depth,
stream.sample_rate,
)
)
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

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

The logging statement for MPD playback occurs before verifying that manifest data is available. If get_manifest_data returns None or empty data, the log will indicate playback is starting even though it will fail. Consider moving the logging to after the successful data check or adjusting the message to indicate an attempt rather than definite playback start.

Copilot uses AI. Check for mistakes.
Comment thread mopidy_tidal/playback.py
)
)

data = stream.get_manifest_data()
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

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

The new MPD manifest handling logic lacks test coverage. The existing test in test_playback.py is marked as xfail. Consider adding tests to verify that get_manifest_data is called correctly for MPD manifests and that the file is written and returned properly.

Copilot uses AI. Check for mistakes.
@tehkillerbee
Copy link
Copy Markdown
Collaborator

The parsed MPD data from tidalapi wasn’t required for playback logic here; it was effectively only used for logging (codecs).

Yes, I see no problem that we remove it here to avoid the error caused by python-tidal

Copy link
Copy Markdown
Collaborator

@tehkillerbee tehkillerbee left a comment

Choose a reason for hiding this comment

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

LGTM!

@blacklight blacklight merged commit fa1ab08 into EbbLabs:main Jan 15, 2026
8 of 9 checks passed
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.

Manifest decoding has suddenly broken

3 participants