Yandex Music API
Делаю то, что по определённым причинам не сделала компания Yandex.
⚠️ Это неофициальная библиотека.
Сообщество разработчиков общаются и помогают друг другу в Telegram чате, присоединяйтесь!
Содержание
- Введение
- Установка
- Начало работы
- Получение помощи
- Список изменений
- Реализации на других языках
- Внесение своего вклада в проект
- Лицензия
Введение
Эта библиотека предоставляет Python интерфейс для никем незадокументированного и сделанного только для себя API Яндекс Музыки.
Она совместима с версиями Python 3.8+ и поддерживает работу как с синхронным, так и с асинхронным (asyncio) кодом.
В дополнение к реализации чистого API данная библиотека имеет ряд классов-обёрток — объектов высокого уровня, дабы сделать разработку клиентов и скриптов простой и понятной. Вся документация была написана с нуля исходя из логического анализа в ходе обратной разработки (reverse engineering) API.
Помимо HTTP API библиотека поддерживает Ynison, протокол синхронизации плеера между устройствами: текущий трек, очередь, список устройств и удалённое управление воспроизведением. Также доступны сессии радио: «Моя волна», волны по занятиям и генеративные станции с обратной связью о прослушиваниях.
📘 Всё API, которое покрывает библиотека, описано в формате OpenAPI: интерактивный справочник API Яндекс Музыки с параметрами, телами запросов, схемами ответов и примерами. Подробнее в разделе Справочник API (OpenAPI).
Доступ к вашим данным Яндекс.Музыка
Для большинства аккаунтов токен можно получить прямо из библиотеки через OAuth Device Flow:
from yandex_music import Client
def on_code(code):
print(f'Откройте {code.verification_url} и введите код: {code.user_code}')
client = Client()
token = client.device_auth(on_code=on_code)
# Сохраните токен куда-нибудь (переменная окружения, файл, БД),
# чтобы не проходить авторизацию при каждом запуске.
print(f'access_token: {token.access_token}')
print(f'refresh_token: {token.refresh_token}')
print(f'expires_in: {token.expires_in}')
client.init()Метод device_auth блокирующий: он ждёт, пока вы подтвердите вход на странице Яндекса, и возвращает объект OAuthToken с полями access_token, refresh_token, expires_in, token_type. Хранение токена — ответственность вызывающего кода: библиотека не сохраняет его на диск и не обновляет по истечении expires_in. Если Device Flow для вашего аккаунта не работает — смотрите альтернативные способы в документации.
Установка
Установить или обновить библиотеку:
pip install -U yandex-musicЭтой команды достаточно для работы с синхронным клиентом. Для асинхронного клиента (ClientAsync) нужны дополнительные зависимости aiohttp и aiofiles — они доступны как опциональный экстра async:
pip install -U "yandex-music[async]"Для Ynison нужны websockets и betterproto, они доступны как опциональный экстра ynison. Экстры можно комбинировать:
pip install -U "yandex-music[ynison]"
pip install -U "yandex-music[async,ynison]"Для расшифровки треков, полученных со способом доставки encraw (например, lossless через tracks_file_info), нужен cryptography, он доступен как опциональный экстра crypto:
pip install -U "yandex-music[crypto]"JSON обрабатывается самой быстрой из установленных библиотек: orjson, pydantic-core, ujson или стандартный json. Ускоренные библиотеки доступны как опциональные экстры orjson, pydantic-core и ujson:
pip install -U "yandex-music[orjson]"Библиотеку можно выбрать явно или подключить свою, подробнее в документации.
Установка из исходного кода:
git clone https://github.com/MarshalX/yandex-music-api
cd yandex-music-api
pip install . # синхронный клиент
pip install ".[async]" # с поддержкой асинхронного клиента
pip install ".[ynison]" # с поддержкой Ynison
pip install ".[crypto]" # с расшифровкой encrawНачало работы
Приступив к работе, первым делом необходимо создать экземпляр клиента.
Инициализация синхронного клиента:
from yandex_music import Client
client = Client()
client.init()
# или
client = Client().init()Инициализация асинхронного клиента:
from yandex_music import ClientAsync
client = ClientAsync()
await client.init()
# или
client = await Client().init()Вызов init() необходим для получения информации — упрощения будущих запросов.
Работа без авторизации ограничена. Так, например, для загрузки будут доступны только первые 30 секунд аудиофайла. Для понимания всех ограничений зайдите на сайт Яндекс.Музыка в режиме инкогнито и воспользуйтесь сервисом.
Для доступа к личным данным следует авторизоваться. Это осуществляется через токен аккаунта Яндекс.Музыка.
Авторизация:
from yandex_music import Client
client = Client('token').init()После успешного создания клиента вы вольны в выборе необходимого метода из API. Все они доступны у объекта класса Client. Подробнее в методах клиента в документации.
Пример получения первого трека из плейлиста "Мне нравится" и его загрузки:
from yandex_music import Client
client = Client('token').init()
client.users_likes_tracks()[0].fetch_track().download('example.mp3')В примере выше клиент получает список треков, которые были отмечены как понравившиеся. API возвращает объект TracksList, в котором содержится список с треками класса TrackShort. Данный класс содержит наиважнейшую информацию о треке и никаких подробностей, поэтому для получения полной версии трека со всей информацией необходимо обратиться к методу fetch_track(). Затем можно скачать трек методом download().
Пример получения треков по ID:
from yandex_music import Client
client = Client().init()
client.tracks(['10994777:1193829', '40133452:5206873', '48966383:6693286', '51385674:7163467'])В качестве ID трека выступает его уникальный номер и номер альбома. Первым треком из примера является следующий трек:music.yandex.ru/album/1193829/track/10994777
Выполнение запросов с использованием прокси в синхронной версии:
from yandex_music.utils.request import Request
from yandex_music import Client
request = Request(proxy_url='socks5://user:password@host:port')
client = Client(request=request).init()Примеры Proxy URL:
- socks5://user:password@host:port
- http://host:port
- https://host:port
- http://user:password@host
Больше примеров тут: proxies - advanced usage - requests
Выполнение запросов с использованием прокси в асинхронной версии:
from yandex_music.utils.request_async import Request
from yandex_music import ClientAsync
request = Request(proxy_url='http://user:pass@some.proxy.com')
client = await ClientAsync(request=request).init()Socks прокси не поддерживаются в асинхронной версии.
Про поддерживаемые прокси тут: proxy support - advanced usage - aiohttp
Изучение по примерам
Вот несколько примеров для обзора. Даже если это не ваш подход к обучению, пожалуйста, возьмите и бегло просмотрите их.
Код примеров опубликован в открытом доступе, поэтому вы можете взять его и начать писать вокруг него свой.
Посетите эту страницу, чтобы изучить официальные примеры.
Особенности использования асинхронного клиента
При работе с асинхронной версией библиотеке стоит всегда помнить следующие особенности:
- Клиент следует импортировать с названием
ClientAsync, а не простоClient. - При использовании методов-сокращений нужно выбирать метод с суффиксом
_async.
Пояснение ко второму пункту:
from yandex_music import ClientAsync
client = await ClientAsync('token').init()
liked_short_track = (await client.users_likes_tracks())[0]
# правильно
full_track = await liked_short_track.fetch_track_async()
await full_track.download_async()
# НЕПРАВИЛЬНО
full_track = await liked_short_track.fetch_track()
await full_track.download()Логирование
Данная библиотека использует модуль logging. Чтобы настроить логирование на стандартный вывод, поместите в начало вашего скрипта следующий код:
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')Вы также можете использовать логирование в вашем приложении, вызвав logging.getLogger() и установить уровень какой вы хотите:
logger = logging.getLogger()
logger.setLevel(logging.INFO)Если вы хотите DEBUG логирование:
logger.setLevel(logging.DEBUG)Расхождения с API
Ответы API со временем меняются. Если в ответе нет обязательного поля модели или оно равно null, библиотека не падает: поле получает значение None, а в лог пишется предупреждение. Оно выводится один раз на модель и набор полей и содержит тип модели, поля, запрос без идентификаторов, версию библиотеки и ссылку на заполненный issue. Пожалуйста, отправьте его, это помогает быстрее обновлять модели.
Поведение настраивается параметрами клиента:
report_unknown_fields=Trueдобавляет в отчёт новые поля из ответа, которых нет в моделях, и их структуру без значений, напримерlist[{id: int, title: str}].strict=TrueвызываетSchemaMismatchErrorвместо предупреждения. Подходит для тестов.on_schema_mismatchпринимает функцию, которая получает отчётSchemaMismatchвместо записи в лог. Например, для отправки в Sentry.
from yandex_music import Client
from yandex_music.utils.schema_mismatch import SchemaMismatch
def handle(mismatch: SchemaMismatch) -> None:
print(mismatch.describe())
print(mismatch.issue_url())
client = Client(report_unknown_fields=True, on_schema_mismatch=handle)Подробнее в документации.
Документация
Документация yandex-music-api расположена на ym.marshal.dev. Вашей отправной точкой должен быть класс Client, а точнее его методы. Именно они выполняют все запросы на API и возвращают вам готовые объекты. Класс Client на ym.marshal.dev.
Справочник API (OpenAPI)
На ym.marshal.dev/api опубликован интерактивный справочник API Яндекс Музыки: 150 методов, более 220 схем моделей, параметры, тела запросов, заголовки и примеры вызова через библиотеку и curl. У каждого метода есть ссылка на соответствующий метод Client в документации.
Справочник построен на спецификации openapi.json. Её можно импортировать в Postman, Insomnia или Bruno, сгенерировать по ней клиент на другом языке или дать как контекст ИИ-ассистенту. Спецификация собирается автоматически из кода библиотеки и обновляется с каждым релизом.
Получение помощи
Получить помощь можно несколькими путями:
- Задать вопрос в Telegram чате, где мы помогаем друг другу, присоединяйтесь!
- Сообщить о баге можно создав Bug Report.
- Предложить новую фичу или задать вопрос можно создав discussion.
- Найти ответ на вопрос в документации библиотеки.
Список изменений
Весь список изменений ведётся в файле CHANGES.md.
Реализации на других языках
Внесение своего вклада в проект
Внесение своего вклада максимально приветствуется! Есть перечень пунктов, который стоит соблюдать. Каждый пункт перечня расписан в CONTRIBUTING.md.
Вы можете помочь и сообщив о баге или о новом поле пришедшем от API.
Лицензия
Вы можете копировать, распространять и модифицировать программное обеспечение при условии, что модификации описаны и лицензированы бесплатно в соответствии с LGPL-3. Произведения производных (включая модификации или что-либо статически связанное с библиотекой) могут распространяться только в соответствии с LGPL-3, но приложения, которые используют библиотеку, необязательно.