How I wrote a library for the Yandex.Music service

Introduction



About me



Hello everyone, I am an ordinary student in the specialty of "software technician." Since childhood I have been fond of computers, since the 7th grade I began to learn programming itself. I have been an owner of a subscription to Yandex Music for more than a year and am generally satisfied with the service (although now in the playlist of the day there are continuous repetitions).







Background



I don’t remember exactly why I decided to look for the official API documentation for this service, like a bot I wanted to write for Telegram, but I came across the fact that it wasn’t ... After some time I came across issue in the yandex / audio-js repository. There, the guys ask exactly the same question as me: "Where is the API?" Not many people are eager to listen to music through a browser, they want an application, but there is no Linux application either! Integrate to your favorite player is impossible!







Then I got the idea to do it. Naturally, I need to somehow work with the service, making crutches around a web application is not an option. I understood that having such a service, having mobile applications and applications for Windows (from the Microsoft Store), it is simply impossible not to have your own internal API for interaction. I was right!







Mandatory reading before the main body



I am aware that, by studying their non-public API, I rummage through other people's dirty things. Below will be described various controversial issues, decisions of developers and, in general, how they wrote it and how they use it. In some places I was just shocked , but I'm sure that if they did so, then there were reasons for that ! Let's not forget that no one should have seen it. I also want to say that everything written below is my opinion . You can agree with him or not.







Main part



Training



Web application API



I already wrote above that I found the API. It was not at all difficult. First of all, I looked at their web application, their endpoint at the time of writing is here: https://music.yandex.ru/api/v2.1/



. They have sufficiently long urls in which I participate in the data, and they also send the form. I also ask you to pay attention to indicating the version of the API , it is .







You need to understand that what I found is used by them only in a web application. There is no OAuth. More precisely, it is more likely to exist, but there, in the bowels of our session on the site. In general, the library is not suitable in connection with crutches in authorization.







Application API



I set off to search further. I was too lazy to take the phone, therefore, I would get to mobile applications last. At that time, the computer was running Windows 10, and I actively used the official Yandex Music application from the Microsoft Store . As a result, I began to study how it works.







For research, I needed a sniffer to track all application traffic. It was possible to use Wireshark , but I settled on HTTP Analyzer . It seems to me more lightweight and perfectly suited to my task.







Turn on the sniffer, go to the application and you're done. Requests flow by stream. We sit, understand, try to call each handler that is in this application and find out about all the existing methods, their arguments and, of course, JSON answers .







Screenshot of one of the requests







From the screenshot above, you can immediately notice a completely different API address - api.music.yandex.net



. Moreover, pay attention to the headings. In addition to information about my client from which the request was made, there is an OAuth token - that's what you need!







Learning API



The study was conducted in conjunction with writing code. I wrote wrapper classes for service objects received from the API, implemented sending requests, sorted out the parameters and in some places just guessed what this name could mean. At this stage, I met various things that I did not expect to see here.







At the time of writing, the library contains 83 classes, and only some of them are auxiliary. The rest are Yandex Music classes, which indicates the scale of this service and the level of abstractions.







Sending ~ 47 methods was implemented. And this is far from all that is in the API (more on that below).







Pain



At first, I tried not to pay attention, I was simply surprised, because this is Yandex , how can this be. But then, at one fine moment, everything bombed. I'll start, perhaps, with him.







  1. Two objects with different levels of field attachment







    New version of the object







    The object itself is merely a "reference" to itself. To its full version. When requesting a list of tracks, we are given their ID, by which we can get more detailed information. Good practice, many do, but it is not always respected (paragraph 9).







    Old version of the object







    Having realized at the very beginning the class for this object, I thought that I would use it everywhere, but no matter how! It seems to me that comments are superfluous and everything can be seen in the screenshots.







    I did not fix this kind of jambs in my library, so having TrackShort



    class now has TrackShortOld



    .







    By the way, both of these objects live in the same method, in the landing'a method.







  2. API versions, methods







    I did not just ask you to pay attention to how the version is specified in the API for the web application. Generally, how do we usually indicate a version? Probably in one of the following ways:







    • make the version on a separate subdomain;
    • put the version in the request part;
    • pass the desired version of the API parameter to the request.


    Yandex decided in this case to do otherwise. We have a landing3 method - its current version at the time of writing. But no one forbids sending a request for landing2 - a completely different structure, other objects.







    I discovered this quite by accident, just forgetting to add a number to the end of the method name and catching a bunch of exceptions.







  3. Working with the new, do not give up on the old







    I saw this when I wrote sending methods "Like" for all the objects that are. There are actually not many of them (playlist, artist, track, album). What was my surprise when I saw different approaches to the same action.







    We like artists like this: https://api.music.yandex.net/users/<USER_ID>/likes/artists/add



    and transfer artist-id



    in the form.







    We like tracks like this: https://api.music.yandex.net/users/<USER_ID>/likes/tracks/add-multiple



    and in the form of track-ids



    .







    If you have not noticed, then when you like the track, the add-multiple method is used, not add . This method is not used with any other types, but they all exist (it was worth just trying to send a request)! And I implemented them in my library instead of add . After all, this method is universal. You can add one track or several.







  4. What is a unique track identifier







    A lot of time has passed, but I still don’t understand when to send just the id



    track, and when the concatenation of id and album_id through a colon ( id:album_id



    ). Sometimes a track is in several albums, sometimes there is no album. Too obscure cases looking from the side, I don’t know how they deal with it (or can’t do it, bagus 2).







  5. Many fields optional







    I got a couple of issues. If there is a problem, then it is related to the required field. I never cease to be surprised how, in my opinion, required fields simply do not return the API.







    • album_id of class TrackID and TrackShort;
    • order_id of class AutoRenewable (subscription);
    • next_revision in Feed;
    • cover_uri in Track;
    • birthday in Account;
    • tags in the playlist.


    The list goes on, but everything is in the history of commits. Perhaps this item is sucked out of the finger.







  6. Similarity methods except for some fields in the answer







    Account status response ( api.music.yandex.net/account/status



    ):







    Account Status Response







    Response radio account status ( https://api.music.yandex.net/rotor/account/status



    ):







    Account Status Radio Response







    I understand that the rights are different, the fields are now with a limit not on the number of tracks in the cache, but on the number of skips per hour, but more like some kind of duplication.







    I don’t know how in Yandex, but I merged it into one class.







  7. So one or many?







    I always thought that if a method returns a list, then even if the result is one element, then the list containing this element will be returned and nothing else, but here and then, and more.







    feature and features







    That feature will return, then features , then feature and features .







  8. Misuse of methods







    I wrote above that they use one or the other method to carry out one action. They went further.







    Sending deleted tracks when the back is well aware of them







    In addition to the playlist ID itself and the frames with and by which track to delete, they for some reason transmit tracks that will be deleted to the method of deleting tracks from the playlist. It is possible that I did not understand this, like everything else, but the method works without too much information. And what tracks were deleted is better to know on the back, than to pass by parameter.







  9. Very heavy requests







    I wrote above that giving a list with track IDs is good practice, you get detailed information about a track only when you really need it. This is not always used here.







    Take a look at how mercilessly they give detailed information of all my tracks from the "Like" playlist in one request:







    Heavy request







    It gave all 396 tracks ! Bytes Received: 3.75M , and this is another cover download!









Baguettes



  1. Download all tracks to the cache from "Like"







    When the limit was reached, an addition was made to the end and removed from the beginning. Thanks for the visualization of the queue, but I thought I would just download the last 100 tracks from the playlist. This happened in a mobile client for Android ( watch video ).







  2. Looks like I'm not confused when I need to send id, but when id: album_id







    Duplicate tracks









Notes



The number of attempts to activate the gift code is 10. Next ban for 24 hours.







Depending on the application from which you are sitting, different offers are made for you to purchase a subscription.







The limit on the number of tracks in the cache is an illusion, it’s just a number, and the application doesn’t allow you to load more (bagus 2).







All of these clever playlists, suggestions, text and button colors come from the API - here it is, real RESTFull.







The start time of the advertisement and the advertisement itself is returned even if you have a subscription.







A link to XML containing data about the location of the file to be downloaded lasts 1 minute, then a 410 error.







Conclusion



I wrote only what I remembered. After all, I came across all this for several months. All my notes are messages in a telegram, because when I came across something like that, I shared with friends. I tried to restore the key points.







In no case did I want to say how bad everything was, somehow to put out specially the jambs on the public. Perhaps this is not a jamb at all, but everything that I wrote above seems strange to me personally .







I shared with you how he wrote the library for the private Yandex.Music service API and what things he encountered during development.







Now you know how and on what their Windows application works, and therefore my library.







By the way, now I try to document it all, when documenting my library, I automatically document their API. It’s tight, and I still have to manage to find a company to go through industrial technological practice.







Thank you for reading right up to here!








All Articles