![](https://habrastorage.org/webt/3p/mb/iu/3pmbiuv8wfkjlr5yjfdndeyhfe4.gif)
Под катом история, как я это сделал несмотря на то, что официального открытого API нет.
С чего все началось?
Я инженер. Постоянно изучаю, как работают разные технологии и вещи вокруг, а также делаю много интересных проектов сам. Когда друзья подарили мне Яндекс.Станцию, я зареверсил протокол активации и развил идею передачи данных, ориентированной на wow-эффект.
У меня глупый (не smart) телевизор, а в качестве основной медиа приставки я использую Станцию. Все отлично, да только YouTube смотреть на ней совсем неудобно. Нельзя войти в аккаунт Ютуба, а значит, никаких рекомендаций и подписок. Кроме того, поиск по видео в Станции, как я понял, осуществляется через Яндекс.Видео. К сожалению такая схема не очень хорошо работает. Иногда не находятся видео даже если дословно произнести название, а новые видео вообще нельзя посмотреть, пока поисковик Яндекса их не проиндексирует.
Я почти смирился с тем, что YouTube на Станции смотреть нельзя, но все изменилось пару недель назад.
Что же произошло?
В субботу утром я решил посмотреть последний сезон «Кремниевой долины». Зашел на «Кинопоиск» и увидел следующее:
![](https://habrastorage.org/webt/l9/ot/u7/l9otu7l6_zwt1v_zc2qsvgbdp6g.png)
После клика по кнопке видео улетело на Яндекс.Станцию и воспроизвелось дальше там. Прямо как ChromeCast или AirPlay. Восторг! Но я обрадовался не самому функционалу, а потенциальной возможности отправить любое видео на станцию.
Я и думать забыл про сериал — на все выходные ушел в реверс инжиниринг и разработку.
Давайте разбираться.
Открываем «Кинопоиск» или «Яндекс.Видео» в Хроме — там отличные инструменты для web разработки. Находим нужную кнопку, кликаем правой клавишей мыши, выбираем «Исследовать элемент».
![](https://habrastorage.org/webt/ny/rq/et/nyrqetlz0e8rti6gmv33pe1bg5a.png)
Можно много, что там поизучать, но нас интересует, какой запрос выполняется при клике по этой кнопке. Переходим во вкладку «Network» инструментов разработчика и смотрим запросы.
![](https://habrastorage.org/webt/pg/pc/zc/pgpczch8nxzxytxn7cucxl9gark.png)
Да, отлетает много статистики, но сразу видно 2 интересных запроса. Это devices_online_stats и station.
Получаем список устройств
devices_online_stats — запрос активных устройств пользователя. Простой GET запрос. Если вы авторизованы в Яндексе, то можете узнать о своих устройствах просто открыв в браузере ссылку:
quasar.yandex.ru/devices_online_stats
Что в ответе:
{
"items":[
{
"icon":"https://avatars.mds.yandex.net/get-yandex-station/1540981/yandexstationicon/orig",
"id":"************",
"name":"Яндекс Станция",
"online":true,
"platform":"yandexstation",
"screen_capable":true,
"screen_present":true
}
],
"status":"ok"
}
Интересно и достаточно интуитивно. ID Станции в примере я заменил на звездочки на всякий случай, но именно он понадобится нам в дальнейшем.
Воспроизводим видео
Запрос на yandex.ru/video/station отправляется методом POST. Повторим его из консоли, получив команду следующим образом:
![](https://habrastorage.org/webt/90/cz/dx/90czdx3um7nns9uufhik5ufzvlq.png)
Запускаем в терминале и получаем ответ:
{
"status": "play",
"msg": "success",
"code": 1
}
Через пару секунд видео запускается на станции. Успех!
Собираем
Я удалил все «лишние» поля из запроса так, чтобы он остался рабочим. Для отправки видео на Станцию в тело и заголовки POST запроса нужно положить всего 4 параметра:
- SessionID — авторизация в Яндексе
- x-csrf-token
- provider_item_id — ссылка на видео (или идентификатор для некоторых сервисов)
- device — Идентификатор устройства, который мы получили ранее
Что за x-csrf-token? Не будем сейчас углубляться. Его можно получить просто GET запросом на frontend.vh.yandex.ru/csrf_token если вы авторизованы в Яндексе.
К этому моменту я уже стал оборачивать все в скрипт на Python. В итоге функция для отправки видео на станцию выглядит примерно так:
def sendToScreen(video_url):
# Auth and getting Session_id
auth_data = {
'login': config.login,
'passwd': config.password
}
s = requests.Session()
s.get("https://passport.yandex.ru/")
s.post("https://passport.yandex.ru/passport?mode=auth&retpath=https://yandex.ru", data=auth_data)
Session_id = s.cookies["Session_id"]
# Getting x-csrf-token
token = s.get('https://frontend.vh.yandex.ru/csrf_token').text
# Getting devices info TODO: device selection here
devices_online_stats = s.get("https://quasar.yandex.ru/devices_online_stats").text
devices = json.loads(devices_online_stats)["items"]
# Preparing request
headers = {
"x-csrf-token": token,
}
data = {
"msg": {
"provider_item_id": video_url
},
"device": devices[0]["id"]
}
if "https://www.youtube" in video_url:
data["msg"]["player_id"] = "youtube"
# Sending command with video to device
res = s.post("https://yandex.ru/video/station", data=json.dumps(data), headers=headers)
return res.text
Вы могли заметить, что я добавляю поле player_id если прислана ссылка с Ютуба. Дело в том, что на Станции есть несколько плееров с кодами youtube, vh и ott. По умолчанию используется vh, но тогда ломается превью и название ролика. Кроме того, его состояние не сбрасывается при смене ролика, что часто вызывает ошибки (Возможно, не все поля в запросе были «лишними»). Плеер ott, как я понял, используется для стриминговых сервисов, а это значит, что в перспективе можно смотреть IPTV через станцию.
Что в итоге?
Сейчас у меня есть бот, через которого мы отправляем видео с Ютуба на Станцию. Просто нажимаем «Поделиться» в приложении YouTube и отправляем ссылку Боту. Кстати, я назвал его «Ящик» и сделал логотип).
![](https://habrastorage.org/webt/rv/su/bm/rvsubmacu1ugpftjfa5espxdbcq.jpeg)
Я не стал делать его публичным, чтобы не собирать логины и пароли. Но вы можете развернуть такого же для себя или доработать для OAuth авторизации или отправки видео с других сайтов. Все исходники доступны на GitHub.
Я хотел сделать расширение для браузера, чтобы работало совсем как AirPlay с любыми видео, но понял, что удобнее отправлять из приложения с телефона. А для такого сценария лучше подходит бот. Вот видео его работы:
Заключение
Когда инженеру нехватает функционала, он доделывает его сам. Мы теперь действительно регулярно пользуемся этим ботом — очень удобно :)
Разработчики Яндекса, пожалуйста не ломайте этот запрос. Это не уязвимость. Работает только с аутентификацией. А если есть возможность — сделайте API устройств публичным — столько всего можно еще сделать!
Спасибо, что читаете мои статьи! Надеюсь, вам было интересно.
Успехов!
Комментарии (21)
KMVp
23.12.2019 18:40+2Вот еще бы со звуком так, для мини станций. Тогда можно было б уведомления от умного дома кидать
alexey-m-ukolov
24.12.2019 07:54В Яндекс.Музыке есть кнопка «Слушать на Станции», так что это теоретически возможно. Нужно разобраться только, есть ли там плеер, который сможет проиграть трек по произвольной ссылке.
TimsTims
24.12.2019 10:13Правильно ли я понял, что если немного докрутить настройки, дома поднять http-сервер, то можно в video_url подставлять локальную ссылку на файл, и так транслировать фильмы на станцию?
Krupnikas Автор
24.12.2019 11:03Я Хотел так сделать. Попробовал на своем публичном сервере разместить видео, и отправил ссылку на станцию. Не сработало. Но думаю, что если поэкспериментировать с форматами видео и настройками сервера, то может сработать.
vitt76
24.12.2019 12:37У меня не получилось скормить колонке локальные mp3 и mp4, в ответ приходит ошибка. Если завернуть mp4 в самый простой web-плеер, то в ответ приходит success, но колонка моргает красным и ничего не показывает. Нужно найти правильные форматы.
Tutucu
24.12.2019 12:37+1Расширение для браузера на пк и андроид: https://chrome.google.com/webstore/detail/yastation-cast/kgikiadkcnpogmbomapbkmcpmdknjbjj
Приложение для андроид с точно таким же методом отправки:
https://play.google.com/store/apps/details?id=org.sitx.ycastMrTims
25.12.2019 05:28в Казахстане Google play пишет «недоступно в вашей стране» для приложения на Андроид. можно ли устранить подобную дискриминацию?
grishkaa
24.12.2019 21:47Мы с одним моим знакомым ещё давно выяснили, что у яндекс станции внутри на самом деле андроид, но USB-порт так и не нашли. Всё-таки интересно, возможно ли как-нибудь её дореверсить до того, чтобы можно было подключиться по adb и запускать андроидные приложения.
and7ey
24.12.2019 21:47+1А зачем с каждой ссылкой делается логин? Почему нельзя делать логин раз в сутки, например, и хранить детали сессии?
Krupnikas Автор
24.12.2019 21:53Да, так было бы правильнее сделать. Дело в том, что я пока не выяснил, как долго сессионный ключ остается валидным. Действительно, релогин можно делать только в случае, если ключ заэкспайрился и запрос не выполнился.
А еще я пока продолжаю эксперименты с этой функцией вне проекта с ботом. Поэтому мне удобнее, чтобы пока работало так.
VladVin
25.12.2019 08:21+1Топ! Тоже попробую, спасибо
VladVin
25.12.2019 08:24Давно хочу поставить свой сервер на Raspberry Pi в квартире, чтобы можно было произвольное видео смотреть. Похоже появилась надежда.
Главное не злоупотреблять — если популяризовать эту историю, Яндекс может быстро прикрыть такое простое API :)
VladVin
25.12.2019 08:28Есть открытый сервер для стрима. Туда можно RTSP стрим затащить или стримить видео из файла. https://github.com/mpromonet/webrtc-streamer
dlinyj
Блин, это именно то чего мне не хватало в яндекс станции! Точно так же страдал. Спасибо!
Krupnikas Автор
Пользуйтесь! Здорово, что кому-то пригодилось)
dlinyj
нужен сервант для бота, так-то буду
Sitx90
Не рекламы ради. Но уже давно как написал приложение для андроида для отправки на станцию. Оно доступно в маркете. Это для тех кто не захочет заморачиваться с переделкой бота. А о принципе работы автор хорошо написал, молодец.
Krupnikas Автор
Круто! Поделитесь ссылкой?