Skip to content

Backport MPD manifest parsing fixes from main repo#4

Merged
enigmae merged 1 commit intomasterfrom
backport/avoid-mpd-manifest-parsing
Jan 22, 2026
Merged

Backport MPD manifest parsing fixes from main repo#4
enigmae merged 1 commit intomasterfrom
backport/avoid-mpd-manifest-parsing

Conversation

@YutongGu
Copy link
Collaborator

@YutongGu YutongGu commented Jan 22, 2026

fix(playback): Avoid MPD manifest parsing to fix regression with new 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

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).

…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
@YutongGu YutongGu requested a review from enigmae January 22, 2026 22:32
@enigmae enigmae merged commit 809ae75 into master Jan 22, 2026
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.

3 participants