yamu
Status — shipped, open source. A way to put your Yandex Music playlist on a portfolio: no hosted service, no token anybody has to hand over, just a scheduled job in your own repo.
Status: shipped. github.com/abdurahmon27/yamu — MIT, and the playlist below is the first thing using it.
The exhibit
- The Ringer — Eminem5:37
- Something In The Way — Nirvana3:52
- Highway to Hell — Back In Black3:27
- Bring Me To Life — The Rock Orchestra, Erin Fox, Tony Maue4:24
- Numb - Unshatter Film Soundtrack (Live in São Paulo) — Linkin Park3:23
- Smells Like Teen Spirit — Nirvana5:01
552 tracks on yandex music · built with yamu
That list is a JSON file in this site’s repository, written by yamu. It used to sit on my home page; it lives here now, as the working example, and the home page shows what I am scrobbling on last.fm instead.
The gap
Spotify users have had this for years. spotify-github-profile has ~2,200
stars, novatorem has been forked 2,600+ times — every fork is one
developer putting their music on their profile. Search the same thing for
Yandex Music and you find OBS overlays and Windows mini-players. Nothing for a
portfolio or a README.
That is strange, because Yandex Music is what everyone around me actually uses. The reason isn’t demand — it’s that Yandex makes it awkward, and nobody had bothered to make it un-awkward.
What was actually in the way
Two things, and I had to check both before writing anything:
- There is no public API. Only the undocumented endpoints the web player
calls. The good news, which I confirmed with a plain
curl: a public playlist answers without any token at all — title, track count, every track with artists, duration and cover art. - You cannot call it from the browser. Send the same request with an
Originheader from another site and it comes back 403, no CORS headers. So the data has to be collected somewhere that isn’t the visitor’s browser.
Most projects would answer that with a small hosted service. That is exactly the answer I didn’t want.
The decision the whole thing rests on
A hosted “now playing” service for Yandex Music would have to collect users’ tokens. And a Yandex token isn’t a music key — it’s a Yandex ID: mail, Disk, taxi, payments. Running a box full of those, for a free widget, is a liability with no upside.
So: no service, no accounts, nothing of yours on my side. A scheduled GitHub Action runs inside your repository, writes a JSON file and an SVG card, commits them, and your existing deploy picks the commit up. If you ever do need a token for private data, it stays in your own repository’s secrets. There is nothing here that could leak it, including me.
The side effect is better than the original plan: your page no longer depends on Yandex being reachable when a visitor arrives. The worst case is a file that stops refreshing.
The whole configuration is one link
The first version asked for a login and a playlist number, because that is the
shape of the old URLs — /users/<login>/playlists/<kind>. Two fields, and the
kind is meaningless on its own: 3 is “Liked tracks” for everyone, so it only
identifies something once you say whose.
Then I looked at what Yandex Music actually hands out today and it is a single uuid link. Better still, the response for a uuid carries the owner — so liked tracks and the playlist list can be collected from the same link, with no login anywhere.
So the setup went from “find your login, find the number at the end of the URL, pick the right domain” to “paste the link”. That is the difference between a tool people try and a tool people finish setting up: every step that sends someone off to go look something up is a step where they quit. The old two-field shape is still supported, folded into a collapsed note in the README where it belongs.
What I cut, and why
“Now playing” is not in it. Reading the current track needs a token and the queue sync the official apps do, and a cron job that runs every few minutes cannot honestly claim to know what you are listening to right now. Shipping it would have meant a widget that lies by up to twenty minutes. A playlist, your liked tracks and your playlist list are all true for as long as they are on screen — so that is what it does.
Saying no to the feature everyone expects was the part I thought about longest. It is also the part I am most sure about.
Built to be fixed by someone else
Undocumented endpoints change. The repo is arranged so that when they do, the fix is small and obvious: every Yandex call lives in one file, every mapping in another, pinned by fixtures captured from real responses. A break should be a ten-line pull request from anybody, not an afternoon of archaeology for me.
Two rules hold the rest together:
- A missing field costs a line of a card, not the build. Every read is defensive.
- A failed fetch changes nothing. With
soft-failthe workflow leaves the committed files exactly as they are and stays green.
Where it fits
This is the same distribution thesis as shoshshi, aimed
at a different audience: every workflow file that uses it says
uses: abdurahmon27/yamu@v1, and every README card carries a link home. The
difference is that this one is small enough to finish, and useful the day it
ships — to me first, which is the only honest way to test it. See also
TypeScript.
Stub. What happens after the first outside user files the first issue — the part of open source I have not done much of yet.
comments