/
/
/
# What does this implement/fix? Adds a **Mamma Mi Radio** music provider: a single Radio entry for the self-hosted radio station that runs as a Home Assistant addon (same author). The Italian hosts notice the home and work it into the show; live typed now-playing metadata (track/segment, hosts, artwork, up-next) is read from the addon's versioned consumer contract `GET /api/integrations/v1/now-playing`. The provider is v1-only and requires **addon 2.13+**. It exposes browse and search, adds its single station to the library on load, and polls the now-playing contract conditionally (`If-None-Match`, 304 reuses the cached payload) while a stream is active. **Related issue (if applicable):** - n/a — no tracking issue; discussed inline on this PR ## Types of changes - [ ] Bugfix (non-breaking change which fixes an issue) — `bugfix` - [ ] New feature (non-breaking change which adds functionality) — `new-feature` - [ ] Enhancement to an existing feature — `enhancement` - [x] New music/player/metadata/plugin provider — `new-provider` - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) — `breaking-change` - [ ] Refactor (no behaviour change) — `refactor` - [ ] Documentation only — `documentation` - [ ] Maintenance / chore — `maintenance` - [ ] CI / workflow change — `ci` - [ ] Dependencies bump — `dependencies` ## Checklist - [x] The code change is tested and works locally. - [x] `pre-commit run --all-files` passes. - [x] `pytest` passes, and tests have been added/updated under `tests/` where applicable. - [ ] For changes to shared models, the companion PR in `music-assistant/models` is linked. - [ ] For changes affecting the UI, the companion PR in `music-assistant/frontend` is linked. - [x] I have read and complied with the project's [AI Policy](https://github.com/music-assistant/.github/blob/main/AI_POLICY.md) for any AI-assisted contributions. - [x] I have [raised a PR against the documentation repository](https://github.com/music-assistant/music-assistant.io/blob/main/CONTRIBUTING.md) targeting the main or beta branch as appropriate. The two unticked boxes do not apply: this PR touches no shared models and no UI. The diff is confined to `music_assistant/providers/mammamiradio/**`, `tests/providers/mammamiradio/**` and the generated `translations/en.json` entries. ## Review rounds Per review, the legacy `/public-status` fallback was dropped entirely: the provider is v1-only and requires **addon 2.13+**. - `34eef4471`: drop legacy fallback; v1-only init; all style items (docstrings, plain-English comments, log prefixes, TypeError removal, class defaults, URL-at-init); v1 hardening (album only from payload, http(s)-only artwork, poisoned-ETag recovery); test suite rewritten for v1-only behavior - `0243c7c0e`: manifest documentation URL; add `icon_monochrome.svg` (single-tone currentColor, 522 bytes) - `67483efa2`: shared cross-repo contract fixture (see governance below) - `12a8e7143`: junk `schema_version` values get the 2.13 hint (never echoed), tests to 100% provider line coverage - `5a749269c`: malformed `relative_url` can no longer leak ValueError past init, unhashable `segment_class` renders the station frame, invalid host characters fail setup with the localized error - `8310f8382`: sharpened description copy (manifest, strings, radio metadata) - `c90d178d5`: `setup_flow.py` per @MarvinSchenkel (the provider cannot be configured on current `dev` without it, and the URL is now read via `get_setup_value`); the single station is added to the library on load per @OzGav; and the `schema_version` probe is reduced to the two checks @OzGav described, with the bool/int coercion removed from `_supports_v1_schema` Docs PR against `beta`: music-assistant/music-assistant.io#799. ## Behavior - Init validates the configured base URL first (localized setup error, no HTTP), then probes the v1 endpoint once. A missing endpoint, non-JSON body, or missing `schema_version` fails with "requires addon 2.13 or newer"; an unsupported version is named in the error; a 5xx reports the HTTP status; a connection failure reports unreachable. The probe doubles as format discovery (the contract publishes the stream's audio format) and as the liveness check, since the addon is a single process serving both the stream and the metadata endpoint. - Failed loads self-heal: these errors are `MusicAssistantError` subclasses, which MA auto-retries every 120s. - Metadata polling is one conditional request per active stream every 12s. Mid-stream failures keep the prior frame and never raise into MA. ## Contract stability The v1 contract is governed on the addon side, merged and running: florianhorner/mammamiradio#889. `CONTRACT.md` freezes the wire surface as additive-only, and a drift CI check byte-compares the addon serializer's output against a golden fixture on every addon PR. The release-ordering rule (the provider side lands here before the addon ships any contract change) is enforced by the same CI: it checksum-compares the addon's fixture against the copy on this repo's `dev`. That fixture lives in this PR at `tests/providers/mammamiradio/fixtures/v1_now_playing.json` (byte-identical) and is exercised by `test_golden_fixture_maps_cleanly`. [proof: fixture] ## Proof - [x] build: https://github.com/music-assistant/server/actions/runs/31439247832 [proof: build] - [x] tests: https://github.com/music-assistant/server/actions/runs/31439247832/job/93620279722 (green on `b0463093c`; 142 provider tests passed, 1 opt-in live smoke skipped, 100% provider line coverage) [proof: tests] - [x] lint: https://github.com/music-assistant/server/actions/runs/31439247832/job/93620234104 (pre-commit run --all-files clean: ruff, mypy, manifests, icons, method order, translations, config entries) [proof: lint] - [x] runtime: https://gist.github.com/florianhorner/92276d370f8610484e025f191af1dbfd (provider run against the production addon: v1 payload capture with headers, live ETag/304 conditional check, and the provider's opt-in live smoke test passing) [proof: runtime] - [x] schema: no MA core/model changes; the diff touches only `music_assistant/providers/mammamiradio/**`, `tests/providers/mammamiradio/**` and generated `translations/en.json` entries — the `provider-scope` check confirms this independently: https://github.com/music-assistant/server/actions/runs/31439247832/job/93620234157 [proof: schema] - [x] fixture: sha256 `5ff694ae8bb32ad00c2924b1c7a1f3f272f98f7cdce5b93fce17963bc5400067` identical in this PR and the addon repo's `tests/integrations/golden/` [proof: fixture] --------- Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]> Co-authored-by: OzGav <[email protected]>