Descoberta — avaliação, recomendados, buscas populares, pessoas e compartilhamento¶
ADR-0179 (descoberta) e ADR-0181 (prévia do link compartilhado).
Rotas /me/* e /search/popular, /people: Authorization: Bearer <JWT> (cliente ou admin).
Avaliação e recomendação são por perfil: o header opcional X-Profile-Id escolhe o perfil;
sem ele vale o perfil padrão (a conta); perfil de outra conta → 403
(perfis).
Avaliação (polegar)¶
Uma por perfil e vídeo: dislike, like ou love.
| Método | Rota | Corpo | Resposta |
|---|---|---|---|
PUT |
/api/v1/me/ratings/{video_id} |
{"rating": "love"} |
204; 404 se o vídeo não existe |
DELETE |
/api/v1/me/ratings/{video_id} |
— | 204 |
GET |
/api/v1/me/ratings |
— | {"ratings": {"<video_id>": "like", ...}} |
PUT /api/v1/me/ratings/507f1f77bcf86cd799439011
Authorization: Bearer <JWT>
X-Profile-Id: 6720a1b2c3d4e5f607182931
Content-Type: application/json
{"rating": "like"}
Recomendados — GET /api/v1/me/recommendations?limit=20¶
Ids de vídeos publicados, do mais para o menos indicado ao perfil. limit de 1 a 50 (padrão 20).
Como é calculado (explicável, evolui depois):
- cada categoria/tag dos vídeos que o perfil curtiu vale 2 pontos e dos que assistiu, 1;
- cada vídeo publicado ganha a soma dos pontos das categorias/tags que tem;
- ficam de fora o que o perfil já viu e o que levou
dislike; - empate, ou falta de sinal, desempata pela data (os mais recentes primeiro).
O app busca os vídeos por id (GET /videos/{id}) — a rota devolve só os ids.
Buscas¶
POST /api/v1/me/search-log¶
204. Corpo {"query": "no diva"} (≤ 200 caracteres). O app chama quando a pessoa
confirma a busca, não a cada tecla. O termo é guardado sem acento e em minúsculas, por
30 dias; menos de 2 caracteres não entra.
GET /api/v1/search/popular?limit=8¶
| Regra | Valor |
|---|---|
| Janela | últimos 30 dias |
| Contagem | pessoas distintas por termo (repetir o termo não sobe o ranking) |
| Mínimo | termo só aparece com 5 ou mais pessoas |
limit |
1–20 (padrão 8) |
| Cache | 5 minutos por réplica (um ranking de 20, fatiado pelo limit) |
Rota fixa
/search/popular é registrada antes do /search/{collection} administrativo
(Pesquisa Global), que capturaria "popular". Quem não é admin nunca cai lá.
Pessoas — GET /api/v1/people¶
Quem aparece nos vídeos publicados (people e cast), com quantos títulos — para os chips do
filtro por pessoa. Sem foto nesta fase.
Os campos people/cast são cadastrados no vídeo (ficha do título).
Compartilhamento — prévia do link (Open Graph)¶
WhatsApp, Instagram e Facebook leem og:* sem rodar JavaScript, e o app web é Flutter.
Estas rotas públicas devolvem uma página HTML mínima com as metatags e mandam a pessoa
para o app.
| Rota | Redireciona para |
|---|---|
GET /api/v1/share/videos/{video_id} |
APP_PUBLIC_URL/watch/<id> |
GET /api/v1/share/series/{season_id} |
APP_PUBLIC_URL/series/<id> |
- Resposta
text/htmlcomog:title,og:description(≤ 200 caracteres),og:image,og:url,twitter:card,<link rel="canonical">emeta refreshpara o app. Tudo escapado.Cache-Control: public, max-age=3600. og:imageé a capa horizontal (senão a vertical) por link assinado de 30 dias em/media/images/{id}(o WhatsApp guarda a prévia em cache).- Título desligado (
enable=false), inexistente, ou série sem episódio publicado: prévia genérica do FD Play (200), sem dizer se o id existe.
Depende do front/infra
Só funciona se o link compartilhado (ou o proxy do domínio do app) chegar a estas rotas:
a hospedagem do app (fallback de SPA, encaminhar robôs de link para /share/...) é do
front/infra, não da API.
Erros¶
| HTTP | Quando |
|---|---|
| 401 | Sem login |
| 403 | X-Profile-Id de outra conta |
| 404 | PUT /me/ratings/{video_id} com vídeo inexistente |
| 422 | rating fora de dislike/like/love, limit fora da faixa, query > 200 |