Skip to content

docs(plugins): add Yandex Music Connect (Ynison) plugin page#624

Open
trudenboy wants to merge 1 commit intomusic-assistant:betafrom
trudenboy:docs/yandex-ynison
Open

docs(plugins): add Yandex Music Connect (Ynison) plugin page#624
trudenboy wants to merge 1 commit intomusic-assistant:betafrom
trudenboy:docs/yandex-ynison

Conversation

@trudenboy
Copy link
Copy Markdown
Contributor

@trudenboy trudenboy commented Apr 22, 2026

Summary

Adds a new documentation page for the Yandex Music Connect (Ynison) plugin, which exposes Music Assistant players as devices in the official Yandex Music app via the Ynison protocol (Yandex's equivalent of Spotify Connect).

Changes

  • New page: src/content/docs/plugins/yandex-ynison.md
  • Sidebar entry added to astro.config.mjs under Plugins

The page follows the style of the Yandex Music provider and Yandex Smart Home plugin pages (CAUTION / WARNING / NOTE callouts, features table, explicit settings list, known issues / notes) and documents:

  • What the plugin does: exposes MA players as Ynison playback targets in the Yandex Music app (play/pause/seek/next/prev from the app)
  • Dependency on the Yandex Music source (the plugin borrows its OAuth token for automatic refresh, or accepts a manually entered token)
  • Supported actions from the Yandex Music app and the passive-player model (Yandex controls the queue, MA signals completion)
  • Radio / My Wave queue replenishment
  • All plugin settings (basic and advanced), including sample-rate / bit-depth normalization
  • Known limitations (manual tokens do not auto-refresh, announcements interrupt the stream, one Yandex account per instance)

Related PRs

Related links

Test plan

  • Docs site builds with the new page and sidebar entry
  • Page renders at /plugins/yandex-ynison/
  • Callouts and tables display correctly

Adds a documentation page for the Yandex Music Connect (Ynison) plugin, which
exposes Music Assistant players as devices in the official Yandex Music app
via the Ynison protocol (Yandex's equivalent of Spotify Connect). Page follows
the style of the Yandex Music provider and Yandex Smart Home plugin pages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 22, 2026

Deploy Preview for ohf-music-assistant ready!

Name Link
🔨 Latest commit 6e17908
🔍 Latest deploy log https://app.netlify.com/projects/ohf-music-assistant/deploys/69e90fc67e8764000898c690
😎 Deploy Preview https://deploy-preview-624--ohf-music-assistant.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

MarvinSchenkel added a commit to music-assistant/server that referenced this pull request Apr 28, 2026
## Summary

Add new **Yandex Music Connect (Ynison)** plugin provider that makes
Music Assistant players appear as playback devices in the Yandex Music
app — similar to how Spotify Connect works.

When a user selects the MA device in the Yandex Music app, the plugin
receives track IDs via the Ynison WebSocket protocol, fetches audio from
Yandex Music CDN (via the linked `yandex_music` MusicProvider), and
streams PCM to the selected MA player.

## Architecture

```
Yandex Music app (phone/web/desktop)
  -> Ynison WebSocket <-> YandexYnisonProvider
    -> receives track_id from PlayerState
    -> fetches audio via linked yandex_music MusicProvider
    -> PCM audio -> PluginSource -> MA Player (Chromecast/DLNA/AirPlay/etc.)
    <- play/pause/seek/next/prev -> update_playing_status back to Ynison
```

## Authentication model

The plugin supports two top-level auth modes, picked via the **Yandex
Music source** dropdown. Together they give three reachable populated
states:

- **Borrow mode** (default when a `yandex_music` MusicProvider is
configured) — read OAuth credentials live from a linked `yandex_music`
instance via `ProviderConfig.get_value()`. No secrets stored in the
Ynison config; reactive refresh from `x_token` on 401 is in-memory only
(scheduled refresh stays with `yandex_music`).
- **Own mode — QR login** — a per-instance `Login with QR code` action
opens a Passport QR popup (via `AuthenticationHelper`); on scan-confirm
both the music token and the long-lived `x_token` are stored in this
plugin's config. Each instance can be bound to its own Yandex account
without sharing tokens with a `yandex_music` provider — useful with
`multi_instance: true` for one-account-per-player setups. A `Remember
session` toggle controls `x_token` persistence; with it enabled the
plugin reactively refreshes on 401 in own mode, mirroring borrow
behaviour.
- **Own mode — manual paste** — escape hatch for headless setups: paste
a music token by hand into `CONF_TOKEN`. With no stored `x_token`,
expiry surfaces a clear `LoginFailed` so the user knows to paste a new
token.

Upgrades from earlier standalone versions preserve own-mode if
`CONF_TOKEN` was set, so no silent switch of auth source.

## Key features

- **Ynison WebSocket protocol**: two-step connection (redirector → state
service), device registration, bidirectional state sync
- **Reconnect resilience**: unbounded exponential backoff with ±20%
jitter (5s → 10s → 30s → 60s, saturating), session ownership tracking,
graceful disconnect handling
- **Audio streaming** via linked `yandex_music` MusicProvider with
FFmpeg PCM conversion (`-re` realtime pacing) and byte-accurate progress
sync
- **Playback control**: play / pause / next / prev / seek, synced
bidirectionally to Ynison state
- **Echo detection**: `version.device_id`-based — inspects the author of
incoming `player_queue` and `status` version blocks to suppress feedback
loops from our own round-tripped updates (covers both queue and
status-only echoes)
- **Ynison-safe wire format**: all outbound
`version`/`timestamp_ms`/`progress_ms`/`duration_ms` fields are
string-typed (integers trigger HTTP 500 + WS teardown); inbound state is
normalized at ingestion so reconnect replays and queue edits stay safe
by construction
- **Per-instance QR auth + reactive refresh** (own mode): own-mode
tokens come from a Passport QR scan or manual paste; with `Remember
session` on the plugin refreshes the music token from a stored `x_token`
on 401 — no manual re-paste, no shared `yandex_music` instance required
- **Radio queue management**: proactive prefetch of next radio batch at
~80% track progress, `SyncStateFromEOV` for queue replenishment,
bounds-validated queue advancement
- **Pause-resume handling**: polling-based pause wait (1s intervals, 30s
deadline) to correctly handle same-track resume without blocking on
track-change events
- **Plugin source ownership**: clean `in_use_by` lifecycle — released on
pause, re-acquired on resume via `needs_reselect` flag
- **Player selection**: auto (first available) or manual target player
- **Metadata sync**: title, cover art, duration, and elapsed time pushed
to MA frontend via `StreamMetadata`

## Changed files

| File | Lines | Description |
|------|-------|-------------|
| `providers/yandex_ynison/__init__.py` | 311 | Plugin setup, config
entries, `ym_instance` dropdown, own-mode QR/clear actions, upgrade-path
preservation |
| `providers/yandex_ynison/provider.py` | 1457 | Core plugin: state
machine, streaming, queue management, echo detection, borrow/own auth,
reactive 401 refresh |
| `providers/yandex_ynison/ynison_client.py` | 734 | Ynison WebSocket
client: two-step connect, state sync, unbounded reconnect with backoff,
timestamp normalization |
| `providers/yandex_ynison/auth.py` | 70 | `ya-passport-auth` wrapper:
`perform_qr_auth` (QR popup → tokens) and `refresh_music_token` (x_token
→ fresh music token) |
| `providers/yandex_ynison/streaming.py` | 47 | PCM format helpers,
pacing args |
| `providers/yandex_ynison/constants.py` | 72 | Protocol URLs, config
keys (incl. `x_token`/`account_login`/QR action keys), `yandex_music`
config-key constants, defaults |
| `providers/yandex_ynison/protocols.py` | 35 | Protocol types for
provider/client decoupling |
| `providers/yandex_ynison/config_helpers.py` | 20 |
`list_yandex_music_instances()` — enumerates linked YM providers for the
dropdown |
| `providers/yandex_ynison/manifest.json` | 12 | Plugin metadata
(`ya-passport-auth==1.3.0`, `depends_on: yandex_music`) |
| `providers/yandex_ynison/icon.svg` | 3 | Provider icon |
| `requirements_all.txt` | +1 | Added `ya-passport-auth==1.3.0` |
| `tests/.../test_provider.py` | 2176 | Provider unit tests (state
machine, streaming, queue, echo detection, borrow/own/QR auth, x_token
refresh) |
| `tests/.../test_ynison_client.py` | 1676 | WebSocket client tests
(connect, unbounded reconnect, state parsing, timestamp coercion) |
| `tests/.../test_config_entries.py` | 304 | Config-flow tests
(dropdown, upgrade preservation, stale-ID clamp, QR/clear action
dispatch and guards) |
| `tests/.../test_auth.py` | 162 | Auth wrapper tests (QR
success/timeout/error, token refresh, error propagation) |
| `tests/.../test_streaming.py` | 83 | Streaming helper tests (format
creation, pacing) |

## Test plan

- [x] 218 unit tests pass (`pytest`)
- [x] ruff lint and format clean
- [x] mypy type check clean
- [x] Manual testing on HAOS: device appears in Yandex Music app, audio
plays through MA player (DLNA), track changes, pause/resume, seek, and
radio queue advancement work correctly
- [x] Manual testing of upgrade path: existing standalone-token configs
preserve own-mode; fresh installs auto-select the sole `yandex_music`
instance
- [x] Manual testing of own-mode QR: QR popup renders, scan-confirm
populates token and `x_token`, `Logged in as <login>` status is shown;
second instance can be bound to a different Yandex account; reset-auth
clears all three fields

## Related PRs

- Documentation PR: music-assistant/music-assistant.io#624

## Dependencies

-
[`ya-passport-auth==1.3.0`](https://pypi.org/project/ya-passport-auth/1.3.0/)
— async Yandex Passport client. Used for `refresh_music_token(x_token)`
(borrow + own modes) and the QR login flow
(`PassportClient.start_qr_login` + `poll_qr_until_confirmed`).
- **Requires `yandex_music` MusicProvider** (`depends_on` in manifest) —
hard requirement for audio streaming. Borrow mode additionally reads its
OAuth credentials. Runtime detection via
`_check_yandex_provider_match()` handles the edge case where the
provider is unloaded while the plugin is running; borrow-mode token
reads surface a clear `LoginFailed` if the linked instance was removed.

> **Source**:
[trudenboy/ma-provider-yandex-ynison](https://github.com/trudenboy/ma-provider-yandex-ynison)
· branch
[`dev`](https://github.com/trudenboy/ma-provider-yandex-ynison/tree/dev)
· v1.8.0

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants