API de Listagem de Rádios
Facets de géneros por eixo
GET /radios/facets?locale=pt mantém o array plano genres para clientes
existentes e acrescenta genreAxes, separando a taxonomia ortogonal entremusic e content:
{
"genres": [
{ "value": "pop", "count": 120, "label": "Pop" },
{ "value": "news", "count": 80, "label": "Notícias" }
],
"genreAxes": {
"music": [{ "value": "pop", "count": 120, "label": "Pop" }],
"content": [{ "value": "news", "count": 80, "label": "Notícias" }]
},
"languages": [],
"countries": []
}
Valores legados ainda não reconhecidos pela taxonomia continuam presentes emgenres, mas não são atribuídos artificialmente a nenhum eixo. O filtro
continua a enviar o valor canónico existente em ?genre=...; não há alteração
na semântica da pesquisa nem migração de dados.
Endpoint
GET /radios
Descrição
Endpoint público para listar todas as rádios disponíveis na plataforma Audissey. O endpoint está protegido com rate limiting (100 requisições por minuto).
Parâmetros de Query (Opcionais)
| Parâmetro | Tipo | Valores Aceites | Descrição |
|---|---|---|---|
genre |
string | - | Filtrar rádios por género específico |
language |
string | - | Filtrar rádios por idioma (ex: 'pt', 'en') |
sortBy |
string | 'home', 'name', 'popularity' | Ordenar resultados. home replica o ranking popular da Home (cliques/votos e diversidade), pelos idiomas do utilizador (ver abaixo). |
country |
string | - | Filtrar por país (nome em inglês). Com sortBy=home substitui Portugal e desliga a ordenação por idiomas. |
locale |
string | - | Locale da UI para os rótulos. Com sortBy=home e sem sessão, é também o idioma do dispositivo. |
countryCode |
string | ISO 3166-1 alpha-2 | Só com sortBy=home e sem sessão: país do dispositivo (ex: GB). Nunca filtra. |
page |
number | 1+ | Página (1-based) |
pageSize |
number | 1-200 | Itens por página (padrão 50) |
Resposta
Formato
[
{
"id": "string",
"name": "string",
"stream_url": "string",
"genre": ["string"],
"language": "string",
"country": "string",
"logo_url": "string"
}
]
Campos
- id: Identificador único da rádio
- name: Nome da rádio
- stream_url: URL do stream de áudio
- genre: Array de géneros musicais da rádio
- language: Idioma da rádio
- country: País de origem
- logo_url: URL do logotipo da rádio
Exemplos de Uso
Listar todas as rádios
GET /radios
Filtrar por género
GET /radios?genre=Rock
Filtrar por idioma
GET /radios?language=pt
Filtrar por género e idioma
GET /radios?genre=Pop&language=en
Ordenar por nome
GET /radios?sortBy=name
Combinação de filtros
GET /radios?genre=Jazz&language=pt&sortBy=name
Continuação de Rádios populares da Home
GET /radios?sortBy=home&page=1&pageSize=50
GET /radios?sortBy=home&page=2&pageSize=50
As duas páginas usam a mesma ordenação determinística; os empates são
resolvidos por _id e os resultados não se repetem entre páginas.
"Ver mais" pelos idiomas do utilizador
sortBy=home é o "Ver mais" do carrossel "Rádios populares" da Home e segue
os mesmos idiomas de conteúdo:
- com sessão (o
Authorizationque a app já envia): a lista de idiomas
guardada do utilizador (ou o idioma por omissão do seu país); - sem sessão:
countryCodeelocaledo dispositivo, como nos destaques
(en+GBdáen-GB). SemcountryCodenão há idiomas.
Com idiomas, a lista é:
- as rádios ativas de cada país das variantes do utilizador (por
origin_country, até 5 países, o da variante preferida primeiro), seguidas
das mais populares do mundo que ainda não estejam na lista, para nada ficar
escondido. Uma query por país e uma mundial, cada uma com no máximo 200
rádios (HOME_RANKING_CANDIDATE_LIMIT), por isso a lista tem no máximo
6 × 200 = 1 200 rádios; - cada bloco no ranking da Home de sempre (cliques, votos,
_id, diversidade
de géneros); - reordenada por idioma (
rerankByLanguage) com a força dos destaques da
Home (homeHighlightsLanguageStrength: 2 ×SUGGESTION_LANGUAGE_STRENGTH,
no máximo 2).
Um utilizador en-GB vê primeiro as rádios britânicas, depois as das outras
variantes da sua lista e as da mesma língua, depois as restantes. Um
utilizador pt-PT vê primeiro a lista de Portugal de sempre, seguida do resto
do mundo. A paginação (page/pageSize) corta a lista inteira, que não
depende da página.
Sem idiomas (convidado sem countryCode: dispositivo sem região e sem localização, ou uma app antiga), comSUGGESTION_LANGUAGE_STRENGTH=0, ou com um filtro country, é a lista de
sempre: as 200 rádios mais populares de Portugal (ou desse país). Também o é
quando nenhum dos países do utilizador tem rádios (com os filtros pedidos):
antes da migração 013 nenhuma rádio tem origin_country, e o top mundial
sozinho não ordenaria nada (pt e pt-BR têm a mesma língua base). Nesse
caso a query mundial nem é feita.
Pré-requisitos (runbook): a migração 20261023_013 (preencheorigin_country/locale) e o índiceis_active_1_origin_country_1_clickcount_-1_votes_-1__id_1 doindexes.json. Sem o índice, cada query por país vazia faz FETCH de todas as
rádios ativas e um SORT (cerca de 236 ms medidos em staging, até 5 por
página); sem a migração, a lista é a de sempre (acima). As verificaçõesver-mais-by-country e ver-mais-worldwide do explain-smoke confirmam os
planos.
Notas aceites na revisão:
- a query mundial ordena só por
clickcount/votes(servida pelo índiceis_active_1_clickcount_1_votes_1, sem SORT); entre rádios empatadas no
200.º lugar, as lidas seguem a ordem do índice, a mesma para um plano e dados
fixos, por isso as páginas de uma lista coincidem; - com sessão iniciada, o
OptionalJwtAuthGuardlê o utilizador (uma leitura
por pedido, como nos outros endpoints personalizados). A resposta desortBy=homelevaVary: Authorization, porque depende de quem pede. - Só se constroem os DTOs das rádios da página pedida (a lista inteira, até
1 200 rádios, é ordenada em memória a cada pedido).
# Convidado num dispositivo inglês no Reino Unido
GET /radios?sortBy=home&page=1&pageSize=50&locale=en&countryCode=GB
Para ver as parcelas da pontuação de cada rádio (administradores), ver
Debug da ordenação por idioma
(debugRanking=true, também em GET /radios/nearby e GET /radios/nearby-geo).
Rate Limiting
O endpoint está protegido com rate limiting:
- Limite: 100 requisições
- Janela de tempo: 60 segundos (1 minuto)
Se o limite for excedido, a API retornará o status HTTP 429 (Too Many Requests).
Os sinais autenticados têm também limites por utilizador (req.user._id),
independentes da rádio e do IP: POST /radios/:id/now-playing aceita 30
pedidos por minuto e POST /radios/:id/listen aceita 60. As duas contagens
são separadas; ultrapassar um limite devolve 429 e não consome a quota de
outro utilizador. Sem autenticação, estas rotas devolvem 401.
As contagens ficam em memória em cada réplica; com cinco réplicas, o limite
efetivo pode chegar a cinco vezes estes valores. O limite global por IP
continua a aplicar-se.
Códigos de Resposta
| Código | Descrição |
|---|---|
| 200 | Sucesso - Lista de rádios retornada |
| 429 | Too Many Requests - Rate limit excedido |
| 500 | Internal Server Error - Erro no servidor |
Notas
- Apenas rádios ativas (
is_active: true) são retornadas - A ordenação por 'popularity' está atualmente implementada como ordenação por nome (a ser expandida no futuro)
- Todos os campos opcionais podem estar ausentes na resposta se não estiverem definidos na base de dados