🌐 English · Русский
Unofficial asynchronous library for the Yandex Music API. Runs on .NET 8, .NET 9 and .NET 10.
⚠️ Unofficial project, not affiliated with Yandex. Use at your own risk and comply with the service's terms of use.
- ✅ Fully asynchronous API with
CancellationTokensupport on every call - ✅ Full catalogue coverage — tracks (metadata, direct download/stream link, lyrics, full-info, similar, trailer), search (+ autocomplete), albums, artists, playlists, genres, labels, clips, credits, disclaimers, concerts, meta-tag pages
- ✅ Personalised endpoints — account & settings, library likes/dislikes (read & write), playlist editing, radio (rotor) stations, landing & feed, cross-device queues, pins, pre-saves, listening history
- ✅ Ynison real-time — subscribe to the account's playback state across all devices and remote-control it (pause, tracks, volume) over the same websocket protocol the official clients use
- ✅ Smart speakers — find them on the local network over mDNS and drive them directly, with their TLS certificate pinned; a speaker never joins the account's session, so this is the only way to reach one
- ✅ Multiple sign-in flows — OAuth token, the official OAuth device-code flow, and best-effort cookie, QR or login + password; all over a serializable session you can persist and restore
- ✅
System.Text.Jsonsource generation — allocation-conscious and trim/AOT-friendly (IsAotCompatible) - ✅ Typed exceptions, first-class dependency-injection integration, full XML documentation
- ✅ Clean, extensible design: add an endpoint group and you have a new domain
samples/YandexMusicTerminal is a full interactive TUI built on the
library — search, browse your albums and playlists, and a live "now playing" view with an animated
equalizer, a real-time progress bar and keyboard volume/transport controls.
Install — one command, no .NET needed (the builds are self-contained). It installs into your
user profile, needs no administrator rights, and puts ymt on your PATH:
irm https://raw.githubusercontent.com/jrfrigat/YandexMusic/main/scripts/install.ps1 | iexcurl -fsSL https://raw.githubusercontent.com/jrfrigat/YandexMusic/main/scripts/install.sh | shThen run it from anywhere:
ymtRe-running the same command updates in place, but you rarely have to: the player checks GitHub for a
newer release at startup and every half hour after that, says so on the main menu when one exists,
and installs it on u. "About" (i) shows the current version and checks on demand. Set
YM_PLAYER_NO_UPDATE_CHECK=1 to turn the automatic check off; the manual one still works. To pin a
version or change the location, see scripts/.
Or grab the archives by hand from the
Releases page (ymt-<version>-win-x64.zip,
ymt-<version>-linux-x64.tar.gz), or run it from source:
dotnet run --project samples/YandexMusicTerminal- Sign in with an OAuth token, the device-code flow, a QR code, or login + password; the session is cached so the next run starts already signed in.
- Playback uses NAudio on Windows; everywhere else (and as a
fallback) it runs a silent simulation that drives the same UI. The audio backend is a single
IAudioPlayerseam, so swapping in a cross-platform backend changes one line. - Remote control — the screen lists both the account's Ynison devices and the speakers answering
on this network, numbered in one row. Pick one with
1-9and the transport keys drive it;0hands them back to the session,rrescans. - Per-track actions (now-playing view) —
llike ·xdislike (and skip) ·tlyrics ·ian endless radio of similar tracks ·rsend the track to a speaker, which then fetches and plays it itself. Playback starts and skips are reported back to the API, so "My Wave" keeps learning from what you play. - Search — tabs for tracks, artists, albums and playlists, paging via a "more" row, and drill-in to a picked artist's, album's or playlist's tracks.
- Main menu is cursor-driven with a hotkey bar along the bottom — single-key shortcuts jump
straight to a section (
ssearch ·aalbums ·lplaylists ·popen player ·rremote ·grequest log ·qquit). - Controls (now-playing view):
spaceplay/pause ·←/→prev/next ·↑/↓volume ·sstop ·qback — plusl/x/t/ifor like, dislike, lyrics and similar (see above).
See the sample's README for the architecture.
# Core client
dotnet add package YandexMusic
# Optional: real-time state and remote control
dotnet add package YandexMusic.Ynison
# Optional: smart speakers on the local network
dotnet add package YandexMusic.Quasar
# Optional: dependency-injection integration
dotnet add package YandexMusic.DependencyInjection| Package | Purpose |
|---|---|
YandexMusic |
The YandexMusicClient, models, authentication and endpoint groups. |
YandexMusic.Ynison |
CreateYnisonClient() — the account's live playback state and the remote. |
YandexMusic.Quasar |
Finds Yandex speakers on the local network and drives them directly. |
YandexMusic.DependencyInjection |
AddYandexMusic() — a scoped client over an IHttpClientFactory pool. |
The core package is standalone and depends on nothing but the BCL — most consumers want the REST API and nothing else, so the websocket-based remote and the speaker support live in their own packages rather than in everyone's dependency tree.
using YandexMusic;
await using var client = new YandexMusicClient();
// Authorize with an OAuth token (never hardcode it — use an environment variable or a secure store)
client.Authentication.SignInWithToken(Environment.GetEnvironmentVariable("YANDEX_MUSIC_TOKEN")!);
// Track metadata and a direct media link
var track = await client.Tracks.GetAsync("4");
Console.WriteLine(track?.Title);
var link = await client.Tracks.GetDirectLinkAsync("4");
// Search and autocomplete
var results = await client.Search.SearchAsync("Queen");
var hints = await client.Search.SuggestAsync("que");
// Albums, artists, playlists (all catalogue ids are strings)
var album = await client.Albums.GetWithTracksAsync("3");
var artist = await client.Artists.GetBriefInfoAsync("79215");
var playlist = await client.Playlists.GetAsync("yamusic-daily", "1000");
// Account and library
var status = await client.Account.GetStatusAsync();
var uid = status!.Account.Uid.ToString();
var liked = await client.Library.GetLikedTracksAsync(uid);
await client.Library.AddLikedTracksAsync(uid, ["4"]);
// Discovery: radio, landing, charts
var dashboard = await client.Radio.GetStationsDashboardAsync();
var chart = await client.Landing.GetChartAsync("russia");
var newReleases = await client.Landing.GetNewReleasesAsync();No password handling — show the user a short code, then poll until they confirm it:
await using var client = new YandexMusicClient();
var token = await client.Authentication.SignInWithDeviceFlowAsync(code =>
Console.WriteLine($"Open {code.VerificationUrl} and enter code {code.UserCode}"));
// The client is now authenticated; persist token.AccessToken if you want to reuse it.Ynison is what synchronizes the web player, the phone apps and smart speakers. The client subscribes
to the account's playback state and can control any device of the session. It ships separately, in
YandexMusic.Ynison:
using YandexMusic.Ynison;
await using var ynison = client.CreateYnisonClient();
var run = Task.Run(() => ynison.RunAsync());
var state = await ynison.WaitForStateAsync(TimeSpan.FromSeconds(10));
Console.WriteLine(state.Devices.Count + " device(s) in the session");
ynison.StateReceived += (_, s) => Console.WriteLine(s.PlayerState?.PlayerQueue?.PlayableList[
Math.Max(0, s.PlayerState.PlayerQueue.CurrentPlayableIndex)]?.Title);
await ynison.SetPausedAsync(paused: false); // remote control
await ynison.NextTrackAsync();A smart speaker never joins the account's Ynison session, so the only way to reach one is to talk to
it directly. YandexMusic.Quasar finds them over mDNS and connects to each speaker itself:
using YandexMusic.Quasar;
// Discovery alone needs no account, no token and no internet connection.
var scanner = new LocalDeviceScanner();
await foreach (var found in scanner.DiscoverAsync(TimeSpan.FromSeconds(3)))
{
Console.WriteLine($"{found.Platform} at {found.Endpoint}");
}
// Driving one does: the account supplies its name, its certificate and a per-device token.
using var quasar = client.CreateQuasarClient();
var speaker = (await quasar.GetDevicesAsync()).First(d => d.Platform == "yandexmini");
await using var control = await quasar.ConnectAsync(speaker);
_ = control.RunAsync();
await control.WaitForStateAsync(TimeSpan.FromSeconds(10));
await control.PlayTrackAsync("38633712"); // the speaker fetches and plays it itself
await control.SetVolumeAsync(0.4);The connection pins the speaker's TLS certificate against the one the account publishes for it —
the certificate is self-signed and names localhost, so ordinary validation could never succeed and
"trust anything" would be the only alternative.
Every method accepts a CancellationToken:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var track = await client.Tracks.GetAsync("4", cts.Token);The simplest way to obtain a token is Yandex's OAuth implicit flow. Open this URL in a browser, sign in, and confirm access:
https://oauth.yandex.ru/authorize?response_type=token&client_id=23cabbbdc6cd418abb4b39c32c41195d
You'll be redirected to a music.yandex.ru URL with the token in the fragment (after the #):
https://music.yandex.ru/#access_token=y0__xExampleFAKEtokenDoNotUse000000000000000000&token_type=bearer&expires_in=24752795&cid=ab1cd23efghij4klmn5opqrs6
Copy the value of access_token (here y0__xExampleFAKEtokenDoNotUse000000000000000000) — that
is your token. Keep it secret; pass it via the YANDEX_MUSIC_TOKEN environment variable (or paste it
into the sample player's OAuth token sign-in). The token_type, expires_in and cid parts are
not needed.
Sign in with an OAuth token, then export the session to resume it later:
client.Authentication.SignInWithToken("<oauth-token>");
var snapshot = client.Authentication.Session.Export(); // serializable record
var json = System.Text.Json.JsonSerializer.Serialize(snapshot);
// ... store json securely ...
client.Authentication.Session.Import(
System.Text.Json.JsonSerializer.Deserialize<YandexMusic.Authentication.AuthSnapshot>(json)!);services.AddYandexMusic(options =>
{
options.Timeout = TimeSpan.FromSeconds(30);
options.DeviceId = "my-app";
});
// IYandexMusicClient is registered as scoped, isolated per scope.Full guides and API reference: https://jrfrigat.github.io/YandexMusic/
.
├── src/
│ ├── YandexMusic/ # core library (client, models, endpoints, auth, JSON)
│ ├── YandexMusic.Ynison/ # real-time state and remote control (websocket)
│ ├── YandexMusic.Quasar/ # speakers on the local network (mDNS + websocket)
│ └── YandexMusic.DependencyInjection/ # AddYandexMusic() integration
├── tests/
│ └── YandexMusic.Tests/ # unit + (token-gated) integration tests (xUnit)
├── samples/
│ └── YandexMusicTerminal/ # interactive terminal music player (TUI demo)
├── scripts/ # one-command installers for the player (ps1 + sh)
├── docs/ # documentation site (DocFX)
└── .github/workflows/ # CI, release (NuGet), docs publishing
dotnet restore
dotnet build -c Release
dotnet test -c ReleaseThe .NET SDK 10 is required (it builds the net8.0/net9.0/net10.0 targets). Integration tests hit the
real API and are skipped automatically unless YANDEX_MUSIC_TOKEN is set:
YANDEX_MUSIC_TOKEN=<your-token> dotnet test -c ReleaseMIT © FrigaT