Адрес сокет сервера:
wss://metadataws.hostingradio.ru
- для сокет-соединений.https://metadataws.hostingradio.ru
- для http-запросов.Общая схема:
Ключевую роль играют IDs станций. Именно по этим идентификаторам формируется подписка, а также их содержат данные присылаемые клиенту.
dr
- Дорожное радиоdr_dancerus
- Дорожное радио/Танцы по русскиdr_rock
- Дорожное радио/Рок-клубdr_nostalgia
- Дорожное радио/Ностальгияdr_keks
- Дорожное радио/Кексep
- Европа плюсep_top40
- Европа плюс/TOP40ep_party
- Европа плюс/Partyep_light
- Европа плюс/LIGHTep_new
- Европа плюс/NEWep_urban
- Европа плюс/URBANep_acoustic
- Европа плюс/Акустикаep_residance
- Европа плюс/ResiDANCEep_fresh
- Европа плюс/Свежееr7
- Радио 7r7_love
- Радио7/Настроение любитьr7_happiness
- Радио7/Настроение счастьяr7_alone
- Радио7/Наедине с музыкойrfm
- Ретро ФМrfm_70
- Ретро ФМ/70еrfm_80
- Ретро ФМ/80еrfm_90
- Ретро ФМ/90еrfm_vecherinka
- Ретро ФМ/Вечеринкаrfm_sanremo
- Ретро ФМ/Сан-Ремоnew_radio
- Новое радиоstudio21
- Studio 21Сервер поддерживает 3 команды:
subscribe
- подписка на станции. Может быть 3х типов:
current
- получать только текущую песню.next
- получать только 2 следующие песни.current_and_next
- получать и текущую и следующие песни.Каждый из типов содержит массив id станций.
unsubscribe
- отписаться от станции. Содержит массив id станций.
fetch
- выбрать метеданные единожды. Может быть 2 типов:
full
- получить полные метаданные.current
- получить только текущую песню.Каждый из типов содержит массив id станций.
Если используются все возможные команды сразу, то объект передаваемый серверу будет выглядеть так:
ws.send(JSON.stringify({
subscribe: {
// хотим получать только текущую песню для 4 станций
current: ['rfm', 'rfm_70', 'rfm_80', 'rfm_90'],
// а для выбранной станции и текущую и следующие
current_and_next: ['ep'],
},
// не хотим ничего более получать по станции Дорожное радио
unsubscribe: ['dr'],
fetch: {
// хотим сразу получить, то что сейчас в эфире
current: ['rfm', 'rfm_70', 'rfm_80', 'rfm_90'],
// А для выбранной станции хотим и предыдующие, и текущую, и следующие получить, чтобы сразу все отобразить
full: ['ep'],
},
}));
Сервер гарантирует, что на одну и ту же станцию нельзя подписаться более чем 1 раз (даже на разные типы).
Если клиент был подписан на current_and_next: ['ep']
, а потом подписался на current: ['ep']
,
то он будет будет получать данные согласно типу последней подписки на станцию, то есть лишь текущую композицию.
Поэтому, вообще говоря, команда unsubscribe
вряд ли нужна на практике, так как для переключения типов подписки
достаточно лишь команды subscribe
.
Также следует запрашивать только те данные, которые реально нужны. Например, при переключении станций, логично для выбранной станции начать запрашивать текущую песню и следующие, а для станции, которая играла до этого, теперь достаточно лишь текущей песни. Поэтому при переключении станций, надо менять подписку следующим образом:
// При переключении с Европы+ на Ретро ФМ
ws.send(JSON.stringify({
// Ни от чего не отписываемся, а только меняем тип подписки для 2 станций
subscribe: {
// Теперь для Европы+ достаточно отслеживать только текущую песню
current: ['ep'],
// а для Ретро ФМ и текущую и следующие
current_and_next: ['rfm'],
},
fetch: {
// Чтобы отобразить слудующие песни и предыдущие сразу же,
// запрашиваем полные метаданные для Ретро ФМ.
// Для Европы+ ничего не запрашиваем, потому что у нас и так должна быть текущая композиция.
full: ['rfm'],
},
}));
Также стоит отметить, что если поток hls содержит метаданные, и плеер играет, то текущую песню надо получать из метаданных потока. Тогда в подписке надо использовать тип next
вместо current_and_next
для выбранной станции.
Если плеер играет, и не нужно отслеживать метаданные для других станций, то соединение с сокет сервером надо разрывать вообще.
Если все потоки содержат метаданные и не надо отслеживать эфир станций, которые не играют в данный момент, то целесообразнее не устанавливать WebSocket соединение, а просто запросить данные через обычный http запрос по адресу
https://metadataws.hostingradio.ru/data/:stationId/current.json
Например:
await fetch('https://metadataws.hostingradio.ru/data/ep/current.json').then(res => res.json());
А дальше получать метаданные из потока.
Все данные которые приходят от сервера, представляют собой объекты следующего вида
{
station_id1: {
current: {/* Объект метаданных */},
previous: [/* Массив объектов метаданных */],
next: [/* Массив объектов метаданных */],
},
station_id2: {
// то же, что и в предыдущем объекте
}
// любое количество объектов для разных станций
}
Все объекты метаданных могут иметь следующий набор полей.
{
type: 3, // 1 - реклама, 2 - не музыка, 3 - музыка
startTime: 1574855886528, // время начала трека в эфире в мс
dbId: 100500, // число
title: "Symphony", // название песни
artist: "Space", // имя исполнителя
cover: "https://performer.emg.fm/thumb/api_300x300/songs/2017/21/5bc6590307fe10f18_1024x1024bb.jpg", // картика песни
hook: "https://performer.emg.fm/upload/songs/hook/2017/c9/2beb/590307fe1108e.mp3", // ссылка на часть трека
}
Первые 2 поля присутсвуют всегда, остальные могут отсутствовать.
Стоит, учесть, что каждый объект, который приходит от севера, может содержать данные для разных станций, поэтому данные надо обрабатывать, например, так:
for(const [stationId, data] of Object.entries(JSON.parse(jsonFromServer))) {
// работа с данными
}
Также в зависимости от типа подписки, любое из полей current
, next
и previous
может отсутсвовать.
Но если они есть, то формат именно таков, что current
- это объект метаданных,
а previous
и next
массивы объектов метаданных, даже если и пустые.
ВАЖНО. При обрыве соединения клиент должен пытаться постоянно восстановить его и, после успешного соединения, вновь подписаться на нужные станции.
'use strict';
function connect() {
console.log(`Trying to connect ...`);
window.ws = new WebSocket('wss://metadataws.hostingradio.ru');
ws.onopen = () => {
console.log(`%cConnection opened`, `color: green`);
ws.send(JSON.stringify({
subscribe: {
current: ['ep', 'rfm'],
},
fetch: {
full: ['ep', 'rfm'],
}
}));
};
ws.onerror = () => {};
ws.onclose = (code, reason) => {
console.warn(`Connection closed! `, code, reason);
// Важно переоткрыть соединение в случае разрыва!
connect();
};
ws.onmessage = (e) => {
console.log(`A message from the server has been gotten! \n\n`, JSON.parse(e.data));
};
}
connect();