Введение
Обо мне
Всем привет, я обычный учащийся по специальности "техник-программист". С детства увлекаюсь компьютерами, с класса 7-го начал познавать само программирование. Являюсь владельцем подписки на Яндексу Музыку уже больше года и в целом доволен сервисом (правда сейчас в плейлисте дня сплошные повторы).
Предыстория
Уж не помню точно, из-за чего я решил поискать официальную документацию API данного сервиса, вроде бота хотел для Telegram написать, но столкнулся с тем, что её нет… Спустя некоторое время наткнулся на issue в репозитории yandex/audio-js. Там ребятки задают точно такой же вопрос, как и я: "А где API?". Не многие горят желанием слушать музыку через браузер, они хотят приложение, но приложения под Linux тоже нет! Интегрировать к своему любимому плееру невозможно!
Тут я загорелся идеей сделать это. Естественно, мне нужно как-то работать с сервисом, городить костыли вокруг веб-приложения не вариант. Я понимал, что имея такой сервис, имея мобильные приложения и приложения под Windows (из Microsoft Store) просто невозможно не иметь своё внутреннее API для взаимодействия. Я оказался прав!
Обязательно к прочтению перед основной частью
Я отдаю себе отчёт в том, что, изучая их непубличное API я роюсь в чужих грязных вещах. Ниже будут описаны различные спорные моменты, решения разработчиков и в целом то, как это написали, как они этим пользуются. Местами я был просто шокирован, но я уверен, что если они так сделали, то на это были свои причины! Не будем забывать, что это никто не должен был видеть. Так же хочу сказать, что всё написанное ниже моё мнение. Вы можете с ним согласить или нет.
Основная часть
Подготовка
API веб-приложения
Выше я уже написал, что нашёл API. Это было вовсе не сложно. Первым делом я глянул на их веб-приложение, их эндпоинт на момент написания статьи находится здесь: https://music.yandex.ru/api/v2.1/
. У них достаточно длинные урлы получаются в которых участвую данные, а еще и форму отправляют. Так же прошу обратить внимание на указание версии API, оно есть.
Надо понимать, что то, что я нашел, используется ими только в веб-приложении. Тут нет OAuth. Точнее оно скорее и есть, но там, в недрах нашей сессии на сайте. В общем для библиотеки не годится в связи с костылями в авторизации.
API приложений
Отправился я искать дальше. Телефон брать было лень, следовательно, до мобильных приложений я дошёл бы в последнюю очередь. На то время компьютер работал под ОС Windows 10, и я активно пользовался официальным приложением Яндекс Музыки из Microsoft Store. Вследствие чего я приступил к изучению того, как оно работает.
Для изучения мне понадобился сниффер, чтобы отслеживать весь трафик приложения. Можно было использовать Wireshark, но я остановился на HTTP Analyzer. Он мне кажется более легковесным и отлично подходящим под мою задачу.
Включаем сниффер, заходим в приложение и готово. Запросы текут ручьем. Сидим, разбираемся, пытаемся вызвать каждый обработчик что есть в этом приложении и узнать о всех существующих методах, их аргументах и конечно же JSON ответах.
Из скриншота выше сразу можно заметить совершенно другой адрес API — api.music.yandex.net
. Более того, обратите внимание на заголовки. Помимо информации о моём клиенте с которого был выполнен запрос там есть OAuth токен — то, что надо!
Изучение API
Изучение проходило совместно с написанием кода. Я писал классы-обёртки для объектов сервиса получаемого от API, реализовывал отправку запросов, разбирался с параметрами и местами просто догадывался что это название может означать. На этом этапе я и повстречал различные вещи, которые не ожидал тут увидеть.
На момент написания статьи библиотека содержит 83 класса и лишь некоторые из них вспомогательные. Остальные же являются классами Яндекс Музыки, что говорит о масштабности данного сервиса и уровню абстракций.
Была реализована отправка ~47 методов. И это далеко не все, что есть в API (об этом ниже).
Боль
На первых порах я старался не обращать внимание, просто удивлялся, ведь это Яндекс, как такое может быть. Но потом, в один прекрасный момент, всё, бомбанул. Начну, пожалуй, с него.
Два объекта с разным уровнем вложения поля
Сам объект является что ль "ссылкой" на самого себя. На свою полную версию. При запросе списка треков нам отдают их ID, по которым мы можем получить более подробную информацию. Хорошая практика, так делают многие, но она не везде соблюдается (пункт 9).
Реализовав в самом начале класс для данного объекта я думал, что буду использовать его везде, но как бы не так! Мне кажется, комментарии излишни и всё видно на скриншотах.
Я никак не исправлял подобного рода косяки в своей библиотеке, поэтому имея класс
TrackShort
теперь естьTrackShortOld
.
Кстати, оба этих объекта живут в одном методе, в методе получения landing'a.
Версии API, методов
Я не просто так попросил Вас обратить внимание на то, как указывается версия в API для веб-приложения. Вообще, как мы обычно указываем версию? Наверное, одним из следующих способов:
- вынести версию на отдельный поддомен;
- вынести версию в часть запроса;
- передавать желаемую версию API параметром к запросу.
В Яндекс решили в данном случае сделать иначе. У нас есть метод landing3 — актуальная его версия на момент написания статьи. Но никто не запрещает отправить запрос на landing2 — совершенно другая структура, другие объекты.
Обнаружил я это совершенно случайно, просто забыв дописать цифру в конец названия метода и словив груду исключений.
Работая с новым, не отказываемся от старого
Увидел я это когда писал отправку методов "Мне нравится" для всех объектов что есть. Их на самом деле не много (плейлист, артист, трек, альбом). Какого было моё удивление, когда я увидел разные подходы к одному и тому же действию.
Артистов мы лайкаем так:
https://api.music.yandex.net/users/<USER_ID>/likes/artists/add
и в форме передаемartist-id
.
Треки мы лайкаем так:
https://api.music.yandex.net/users/<USER_ID>/likes/tracks/add-multiple
и в формеtrack-ids
.
Если Вы не заметили, то при лайке трека используется метод add-multiple, а не add. Ни с какими другими типами этот метод не используется, но они все существуют (стоило просто попробовать отправить запрос)! И именно их я реализовал в своей библиотеке вместо add. Ведь данный метод универсален. Можно добавить как один трек, так и несколько.
Что такое уникальный идентификатор трека
Прошло уже много времени, но я до сих пор не пойму, когда надо отправлять просто
id
трека, а когда конкатенацию id и album_id через двоеточие (id:album_id
). Иногда трек в нескольких альбомах, иногда альбома нет. Слишком непонятные кейсы глядя со стороны, я не знаю как они с этим справляются (или не справляются, багусик 2).
Необязательность многих полей
Мне накидали пару issues. Если есть проблема, то она связана с обязательностью поля. Я не перестаю удивляться, как, на мой взгляд, обязательные поля просто не возвращаются API.
- album_id класса TrackID и TrackShort;
- order_id класса AutoRenewable (подписка);
- next_revision в Feed;
- cover_uri в Track;
- birthday в Account;
- tags в Playlist.
Список можно продолжать дальше, но всё есть в истории коммитов. Возможно, данный пункт высосан из пальца.
Схожесть методов за исключением некоторых полей в ответе
Ответ статуса аккаунта (
api.music.yandex.net/account/status
):
Ответ радио статуса аккаунта (
https://api.music.yandex.net/rotor/account/status
):
Я понимаю, что права разные, поля теперь с лимитом не на количество треков в кеше, а на количество скипов в час, но больше смахивает на какое-то дублирование.
Не знаю как в Яндексе, но я у себя слил в один класс.
Дык один или много?
Я всегда считал, что если метод возвращает список, то даже если результатом является один элемент, то вернётся список содержащий этот элемент и никак иначе, а тут и то, и другое.
То feature вернется, то features, то feature и features.
Неправильное использование методов
Выше я написал о том, что используют то один, то другой метод для осуществления одного действия. Они пошли дальше.
На метод удаления треков из плейлиста, помимо самого ID плейлиста и рамок с и по какой трек удалить, они зачем-то передают треки, которые будут удалены. Вполне возможно, что это я не понял, как и всё остальное, но метод работает и без лишней информации. А какие треки были удалены лучше узнать на беке, нежели передавать параметром.
Очень тяжёлые запросы
Выше я писал, что отдавать список с ID треков является хорошей практикой, Вы получаете подробную информацию о треке только тогда, когда она Вам реально нужна. Это используется тут далеко не всегда.
Гляньте как они беспощадно отдают подробную информацию всех моих треков из плейлиста "Мне нравится" в одном запросе:
Оно отдало все 396 треков! Bytes Received: 3,75M, а это ещё обложки загрузить!
Багусики
Загрузка всех треков в кеш из "Мне нравится"
При достижении лимита происходило добавление в конец и удалялось с начала. Спасибо за визуализацию очереди, но я думал мне просто загрузит 100 последних треков из плейлиста. Произошло это в мобильном клиенте под Android (смотреть видео).
Видать не один я путаюсь, когда надо отправить id, а когда id:album_id
Заметки
Количество попыток на активацию подарочного кода — 10. Дальше бан на 24 часа.
В зависимости от приложения, с которого Вы сидите, Вам делают разные предложения о покупке подписки.
Лимит на количество треков в кеше иллюзия, просто число, а уже приложение не дает загрузить больше (багусик 2).
Все эти умные плейлисты, предложения, текста и цвета кнопок приходят от API — вот он, настоящий RESTFull.
Время начала рекламы и сама реклама возвращается даже если у Вас есть подписка.
Ссылка на XML, содержащий данные о расположении файла для загрузки живёт 1 минуту, потом 410 ошибка.
Заключение
Написал лишь то, что вспомнил. Ведь сталкивался со всем этим я на протяжении нескольких месяцев. Все мои записи — это сообщения в телеграмме, ибо когда я натыкался на что-то этакое, я делился с друзьями. Постарался восстановить ключевые моменты.
Я ни в коем случае не хотел сказать как всё плохо, как-то выставить специально косяки на публику. Возможно, это и не косяки вовсе, но всё что я написал выше кажется лично для меня странным.
Поделился с Вами тем, как писал библиотеку для закрытого API сервиса "Яндекс.Музыка" и с какими вещами столкнулся во время разработки.
Теперь Вы знаете, как и на чём работает их приложение для Windows, а следовательно, и моя библиотека.
Кстати, сейчас я стараюсь это всё задокументировать, документируя свою библиотеку я автоматически документирую их API. Туго идёт, да и надо себе ещё успеть компанию для прохождения производственной технологической практики найти.
Спасибо что дочитали аж до сюда!
Комментарии (41)
and7ey
05.08.2019 21:58Мне вот не хватает в Яндекс Музыке отсутствия поддержки Google Assistant (нет, колонку с Алисой я покупать не буду :). Свой клиент что ли писать?
Яндекс тут свои запросы к серверу никак не «шифрует»? Ключей-секретов никаких не использует?
prs123
06.08.2019 11:30Так с google assistant крайне непросто вот так связаться. да и зачем? там наверняка могло бы быть две команды: пауза и играть
and7ey
06.08.2019 11:43В чем сложность? https://developer.android.com/guide/topics/media-apps/interacting-with-assistant.html
Команд может быть гораздо больше — например, "включи плейлист такой-то".
Мне с колонкой Google Home было бы очень удобно — стартовать всё голосом, чтоб даже не брать телефон в руки.
MarshalX Автор
06.08.2019 16:11Яндекс тут свои запросы к серверу никак не «шифрует»? Ключей-секретов никаких не использует?
Не совсем понял Ваш вопрос. Обычное веб API с аутентификацией по токену. Из всего шифрования что тут есть — это HTTPS. Токен получается на oauth.yandex.ru
Diversus
05.08.2019 23:35+1Вы не хотите стать сотрудником Яндекса? Надо же кому-то написать документацию к их API Яндекс Музыка :)
MarshalX Автор
06.08.2019 16:12Вы не хотите стать сотрудником Яндекса?
Пройти свою технологическую практику осенью у них — моя мечта.Diversus
06.08.2019 16:18Хех. Задал вопрос с юмором, а попал оказывается в точку :)
Пройти свою технологическую практику осенью у них — моя мечта.
Так в чем же дело? Пишите письма, выходите на HR/руководителей проекта.
Дайте ссылку на эту публикацию и говорите, что хотите сделать API Яндекс Музыки лучше. Пробуйте и все получится.
arkamax
06.08.2019 17:57+1Попробуйте задокументировать все это на английском (при необходимости — выучить), и податься на internship к примеру в Google… или еще куда. Перспективы поинтереснее будут. P.S. Это реально и не гербалайф. «Вы не забиваете 100% тех шайб, которые боитесь бросить» (У. Гретцки)
Gorniv
06.08.2019 08:25А я еще на Apple Music API жаловался :D
У них, кстати, все достаточно хорошо и четко, кроме пары багов, в паре мест возращается не совсем тот объект.
warner
06.08.2019 10:22Вот кстати как раз на днях решил загрузить плейлист «Мне нравится» на телефон, так как собирался в места с очень плохим интернетом. Приложение радостно отрапортовало в статус-баре, что скачано почти 400 треков. И каково же было моё удивление, когда я потом включил оффлайн режим и увидел, что на самом деле у меня всего 88 песен. Приехал домой, попробовал снова скачать — такая-же беда. Максимально удалось 99 треков загрузить.
warner
06.08.2019 13:56UPD: в техподдержке сказали, что ограничение на 99 треков это потому что у меня подписка на яндекс музыку за 99 рублей, в более дорогой такого нет.
myrrc
06.08.2019 15:50Боюсь представить, сколько бы мне пришлось им заплатить, если бы я выложил свою библиотеку на 40к треков и захотел её скачать.
TheKnight
06.08.2019 16:061700 рублей за год. Правда у меня в сохраненых не так уж много треков, всего лишь 189.
nightvich
06.08.2019 20:01У google бесплатно, они считают, если вы загружаете к ним треки, то вы их как-то купили, соответственно, можно пользоваться бесплатно в рамках play.music
MarshalX Автор
06.08.2019 16:15Честно говоря немного удивлён. Всегда считал, что у всех лимит в 100 треков. Да и год назад где-то даже читал об этом перед покупкой подписки. А они пишут где-нибудь об этом вообще?
ganzmavag
06.08.2019 18:26Пишут, когда выбираешь подписку. Указано, чем отличается подписка за 99 от более дорогой.
Magn
06.08.2019 10:31но приложения под Linux тоже нет
Существует MellowPlayer для страждущих. Пользуюсь, работает.penton7
06.08.2019 17:28Попробовал я это приложение, тестировал на ю.музик, не особо удобное, ничем не отличается если бы я держал открытую вкладку в браузере. Плюс если в браузере я могу включить adblock (реклама без подписки почти каждый трек), то в этом такого функционала нету. Возможно с другими приложениями оно предоставляет расширенный функционал, то с youtube music нету вообще смысла его использовать.
Propp
06.08.2019 20:47С Youtube Music в Mellow Player все плохо. Для меня киллер-фича Mellow Player — это управление проигрыванием с помощью медиа-клавиш и интеграция с виджетом плеера системы. Для я.музыки и, к примеру, youtube все работает, для youtube music — нет.
penton7
06.08.2019 23:25Ну я его тестировал только с ю.музик, поэтому так и сказал. Я еще не видел приложения под мои нужды, то есть только управление треками, переключение и тд. Когда включаешь предложенный микс и работаешь, не сильно удобно всегда заходить в вкладку и листать дальше. Думаю пока как реализовать свою идею)
Propp
07.08.2019 07:34Еще мне как-то рекомендовали такое расширение для управления плеером в браузере медиа-клавишами: github.com/berrberr/streamkeys (если я правильно понял, что вам нужно)
TIMOHIUS
06.08.2019 11:38В яндекс музыке очень интересно устроен механиз построения ссылки до mp3 трека, пару месяцев назад разбирал это. В итоге на питоне есть несколько строк кода, которые могут стянуть трек по id трека =)
Win332
06.08.2019 15:06Да, вот реализовал когда-то на C#
github.com/Winster332/Yandex.Music.Api/blob/master/Yandex.Music.Api/YandexMusicApi.cs#L310
310 строка начало метода. Замысловато, но не эффективно. У спотифай и соундклауда не много сложнее
Daniyar94
06.08.2019 14:11Время начала рекламы и сама реклама возвращается даже если у Вас есть подписка.
А вот это не круто, я им плачу не для того что бы мне скрытый трафик накручивало на мобильном интернете
Win332
06.08.2019 15:01Хм, тоже когда-то писал либу для яндекс.музыки. Точнее это API клиент с возможностью скачивания, стриминга, поиска по альбомам, артистам, свои треки и т.д…
Может кому пригодится: github.com/Winster332/Yandex.Music.Api
Ну и воспроизвести музыку тоже можно через терминал, напрямую интегрируясь с яндекс.музыкой: github.com/Winster332/Yandex.Music.Terminal
И телеграм бот для яндекс музыки на этой либе: github.com/Winster332/Lofi
Правда телеграм бот кривой, может в какой-то момент упасть(не стал заморачиваться с API телеги).
Кстати еще если покопаться в разных респонсах яндекс музыки, можно заметить что они используют MassTransit в своей инфраструктуреMarshalX Автор
06.08.2019 16:21Ого, не нашел. Перед тем как приступить к работе я шерстил google и github на наличие того, что я хочу сделать. Встретил только либу 15 года на JS. Тогда и я оставлю ссылочку на своё творение.
Исходники — github
Документация — readthedocs.io
dmitry_dvm
06.08.2019 23:55За "7. Дык один или много?" я бы увольнял по статье. Думаю это следствие нетипизированных языков на бэке и халатности.
enabokov
07.08.2019 01:40This is backend, man!
i.pinimg.com/originals/4d/52/de/4d52decc9385a1009c3e7c178410671c.png
B_bird
07.08.2019 10:32Полезность вашей библиотеки напрямую зависит от возможности и желания ее править с каждым релизом api.
Я проходил это всё давным давно когда делал своё расширение для хрома, каждый релиз в те времена ломал всё, потому что даже базовые сущности периодически нещадно рефакторились. Спасибо разработчикам, сделали api для расширений на самой витрине (консоль разработчика, далее externalAPI.help()), с тех пор проблем не было, все работает как часы.
pankraty
Касаемо удаления треков из плейлиста. Представим, что реализовано через указание ID плейлиста и номеров С и По. А дальше смоделируем следующие ситуации:
Так что существующее решение родилось не пустом месте и не ради усложнения жизни разработчикам.
batyrmastyr
Так автор и удивляется, что от диапазона не полностью отказались.
pankraty
По-моему, тут явно удивление тому, зачем передавать треки, а не зачем передавать «с» и «по».
batyrmastyr
Да, вы правы.
MarshalX Автор
Большое спасибо за Ваш комментарий! Теперь для меня в этом их решении появился смысл.