From 913da49b9030dfb149bf6d2dc86cca0c9ee097e2 Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Mon, 14 Sep 2026 06:03:07 -0300 Subject: [PATCH] =?UTF-8?q?docs(plan):=20C162=20=E2=80=94=20VOD=20do=20ace?= =?UTF-8?q?rvo=20sob=20demanda=20+=20YouTube=20default=20(Related=20#999)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acervo-vod-sob-demanda-ui-draft.html | 454 ++++++++++++++++++ docs/plans/acervo-vod-sob-demanda.md | 104 ++++ 2 files changed, 558 insertions(+) create mode 100644 docs/plans/acervo-vod-sob-demanda-ui-draft.html create mode 100644 docs/plans/acervo-vod-sob-demanda.md diff --git a/docs/plans/acervo-vod-sob-demanda-ui-draft.html b/docs/plans/acervo-vod-sob-demanda-ui-draft.html new file mode 100644 index 00000000..fae771f4 --- /dev/null +++ b/docs/plans/acervo-vod-sob-demanda-ui-draft.html @@ -0,0 +1,454 @@ + + + + + + + UI draft — Acervo de falas: VOD sob demanda + YouTube (C162) + + +
+

+ UI draft — Acervo de falas: VOD sob demanda + YouTube (C162) +

+

+ A assessoria de comunicação abre a fala, assiste o trecho exato e baixa o MP4 mesmo quando o + CDN da Câmara já apagou o arquivo: YouTube da sessão quando existe; VOD do trecho resolvido + sob demanda no clique; "Baixar" só entrega arquivo verificado. +

+

+ Cinza = estrutura existente · acento = novo neste item · + barras cinza = conteúdo não especificado. Cenas estáticas: sem interação, sem dados reais. +

+ + + + +
+

+ Cena 1 · desktop (~1280px) — detalhe com YouTube embed + ações +

+
+
+

← Voltar ao acervo

+

BREVES COMUNICAÇÕES

+

+ 11/08/2026 · 18:48 · Breves Comunicações · 4min25s · Presidiu: [placeholder] +

+ +
+
+ +
+
+ ▶ +
+ + default quando existe + +

+ Vídeo da sessão no YouTube +

+
+

+ Clique na transcrição posiciona o vídeo somando o offset do trecho na sessão. +

+ +
+ + +
+

+ O MP4 do trecho é resolvido e verificado na Câmara no clique — nunca um arquivo + morto. +

+ +

+ Transcrição (clique para posicionar) +

+
+
+ 00:00 + … agradeço, Presidente. Quero falar sobre a saúde pública … +
+
+ 00:43 + … o acesso a medicamentos na Bahia precisa chegar a quem mora no interior + … +
+
+ 02:10 + … e é preciso garantir o financiamento tripartite … +
+
+ 04:02 + … muito obrigado, Presidente. … +
+
+
+ + +
+
+
+
+ + + + +
+

+ Cena 2 · mobile (~390px) — mesma hierarquia +

+
+
+ ☰ + Comunicação + +
+
+

← Voltar ao acervo

+

BREVES COMUNICAÇÕES

+

11/08/2026 · 4min25s

+ +
+
+ ▶ +
+ default +

+ Vídeo da sessão no YouTube +

+
+

+ A transcrição posiciona o vídeo somando o offset do trecho. +

+ + + + +

+ Transcrição (clique para posicionar) +

+
+
+ 00:00 + … agradeço, Presidente. … +
+
+ 00:43 + … o acesso a medicamentos na Bahia … +
+
+ 02:10 + … o financiamento tripartite … +
+
+ +

Temas

+
+ Saúde + Bahia +
+

+ Fonte: Câmara dos Deputados · CC BY 4.0 +

+
+
+
+ + + + +
+

+ Cena 3 · resolvendo o trecho na Câmara — pendência do clique +

+
+
+

← Voltar ao acervo

+

BREVES COMUNICAÇÕES

+

11/08/2026 · 4min25s · só VOD (sem YouTube)

+ +
+
+
+
+

Resolvendo o trecho na Câmara…

+

+ Isso pode levar alguns segundos. Se demorar, tente novamente em instantes — a + página não trava. +

+
+ +
+ + +
+

+ O trecho pedido é o `excerptTMs` exato do acervo — nunca um vizinho. +

+ +

+ Transcrição (clique para posicionar) +

+
+
+ 00:00 + … agradeço, Presidente. … +
+
+ 00:43 + … o acesso a medicamentos na Bahia … +
+
+
+ + +
+
+
+
+ + + + +
+

+ Cena 4 · falha total — nem YouTube nem VOD (bloco indisponível + abrir fonte) +

+
+
+

← Voltar ao acervo

+

BREVES COMUNICAÇÕES

+

11/08/2026 · 4min25s

+ +
+
+

+ Não foi possível carregar o vídeo deste trecho +

+

+ Esta fala não tem vídeo no YouTube e a Câmara não está servindo o arquivo agora. A + transcrição e a fonte oficial continuam disponíveis. +

+
+ + +
+
+

+ "Abrir fonte" leva ao PDF oficial do Diário quando existir. +

+
+
+
+ + + + +
+

+ Cena 5 · VOD disponível — player nativo, como hoje (contraste) +

+
+
+

← Voltar ao acervo

+

BREVES COMUNICAÇÕES

+

11/08/2026 · 4min25s · só VOD

+ +
+
+
+ ▶ +
+ + resolvido no clique + +
+
+
+ +
+
+
+ ▶ + 00:43 / 04:25 + + + + +
+
+
+

+ Arquivo do trecho verificado antes de tocar; a transcrição usa os segundos do + arquivo (0-based). +

+ +
+ + +
+
+ +

+ Transcrição (clique para posicionar) +

+
+
+ 00:00 + … agradeço, Presidente. … +
+
+ 00:43 + … o acesso a medicamentos na Bahia … +
+
+ 02:10 + … o financiamento tripartite … +
+
+ +

+ Fonte: Câmara dos Deputados · CC BY 4.0 +

+
+
+
+
+ + diff --git a/docs/plans/acervo-vod-sob-demanda.md b/docs/plans/acervo-vod-sob-demanda.md new file mode 100644 index 00000000..b884f82b --- /dev/null +++ b/docs/plans/acervo-vod-sob-demanda.md @@ -0,0 +1,104 @@ +# Acervo de falas: player resolve o trecho sob demanda e YouTube vira default quando existe + +Status: plano — registrado (blocked até plano em main) +Atualizado em: 2026-09-14 +Issue: #999 +Priority: P1 +Impeccable: B — encaixe no detalhe do acervo (player + ações) +Rascunho UI: docs/plans/acervo-vod-sob-demanda-ui-draft.html +Appetite: ~1,5–2 dias eng; um outcome verificável — com o CDN da Câmara vazio, abrir uma fala ainda toca (YouTube quando houver) e "Baixar" nunca entrega arquivo inexistente +Responsável: — + +## Intenção + +O acervo guarda o link do MP4 do trecho ("vídeo sob demanda") que a própria Câmara gera — e apaga. Medido em 2026-09-14: entre 04:35 e 08:05 o CDN derrubou os 924 MP4s do acervo, a página do evento da Câmara falha no mesmo URL, o endpoint de download responde "Não existe o arquivo …" e um probe Range dá 403/timeout. Não é regressão do C160 (que só tocou `officialTextUrl`): o link gravado sempre foi efêmero — o banco é cache, não fonte da verdade. O detalhe da fala precisa tocar e baixar mesmo assim: o player passa a usar o YouTube da sessão (estável, presente em 802 das 997 falas) quando existir e a resolver o trecho exato sob demanda na API da Câmara no clique; o "Baixar" só entrega arquivo verificado. Sem espelhar MP4 no S3. + +## Persona e fluxo + +- **Persona / contexto:** assessoria de comunicação da campanha (vertical `/campanha/comunicacao`; communicator, coordenação e candidatura), no escritório ou em campo, montando peça com prazo curto. +- **Job principal:** assistir e baixar o trecho exato de uma fala do acervo, confiando que o vídeo/arquivo existe — mesmo quando o link gravado já morreu. +- **Fluxo desejado:** abre a fala → o player toca (YouTube da sessão quando existe; senão, um clique resolve o VOD na Câmara) → clica na transcrição e vai ao ponto exato → "Baixar vídeo (MP4)" resolve e só entrega arquivo verificado → "Abrir fonte" segue para o Diário (C160). +- **Anti-goals de produto:** segundo player/editor; espelhar ou transcodificar MP4; regenerar os 924 em lote; ajustar o trecho por vizinhança; expor o acervo fora de `/campanha`; novo `Consent`/collection. + +### Esboço de fluxo (B/C/D) + +```text +[abre a fala] → YouTube (default quando existe) | capa "resolver trecho" (só VOD) +→ clique em assistir/baixar → "Resolvendo o trecho na Câmara…" +→ PRONTO → player nativo no trecho (segmentos 0-based) | no YouTube, seek = offset + segmento +→ "Baixar" → arquivo verificado | falha → estado honesto + "Abrir fonte" +``` + +### Rascunho UI (B/C/D) + +- Rascunho UI (gate): `docs/plans/acervo-vod-sob-demanda-ui-draft.html` — cenas desktop e mobile do detalhe, resolvendo, indisponível e VOD nativo. + +## Objetivo e aceite + +- **Com ambos (773 falas):** o detalhe toca a sessão no YouTube no load (sem chamada à Câmara no render); "Baixar vídeo (MP4)" resolve o trecho exato na Câmara no clique e só entrega arquivo verificado. +- **Só VOD (151):** o player oferece resolver o trecho no clique; `PRONTO` → player nativo como hoje; `GERANDO` → pendência visível (com limite; convite a tentar de novo, sem travar a página); `INDISPONIVEL`/`PRONTO` com hash morto → estado honesto, nunca arquivo morto. +- **Só YouTube (29):** player embed; sem botão de MP4 (não há arquivo) — "Abrir fonte" cobre. +- **Nenhum (44):** bloco "vídeo indisponível neste momento" + "Abrir fonte" quando houver (PDF do Diário do C160). +- A resolução usa `excerptTMs` verbatim (nunca arredonda/ajusta); clique na transcrição com YouTube posiciona somando o offset da sessão — nunca cai em outro orador. +- O "Baixar" direto do card da lista (mesmo link efêmero) sai; o download passa a ser do detalhe, que resolve e verifica no clique. +- **Guardrails:** link do banco é cache (pode ser atualizado ou ignorado; nunca requisito — render não chama a Câmara); resolução só no clique; crédito "Fonte: Câmara dos Deputados · CC BY 4.0" mantido; gate do acervo vale para a resolução; URLs públicas do acervo intocadas; sem S3/espelho, sem novo consent/collection. + +## Dados (intenção) + +- **Vou apresentar dados?** Não — a superfície é player + ações; nenhum KPI/gráfico novo. +- **Decisões desbloqueadas:** a assessoria decide cortar/usar o trecho sem arriscar arquivo morto; a coordenação decide, pelo uso, se o download continua no card da lista. +- **Forma:** _adiada ao plano de implementação_ — restrição: o estado "resolvendo/indisponível" é feedback de ação, não dado de acervo. + +## Dados da decisão (literais) + +- **API (resolução sob demanda):** `https://www.camara.leg.br/evento-legislativo/{eventId}/video-sob-demanda?idAudio={audioId}&trecho={excerptTMs}` → `{ estado: 'GERANDO' | 'PRONTO' | 'INDISPONIVEL', video: { linkParaReproducao, linkParaDownload, duracao, titulo } }`. +- **Trecho exato:** `trecho` = `excerptTMs` do banco (epoch ms); valor vizinho cai em outro orador — nunca alterar. Elegibilidade para tentar a Câmara: ter `eventId` + `audioId` + `excerptTMs` **e** VOD armazenado (ambos/só VOD); sem VOD armazenado, não tentar (o cache orienta a oferta, não a verdade do arquivo). +- **Offset no YouTube:** `excerptTMs` (epoch ms) → hora BRT (`Intl`, America/Sao_Paulo) − `eventStartAt` (naive); ex.: `1786473834650` = 15:43:54 BRT, sessão 15:00 → 43m54s (2634 s). Segmentos ASR são 0-based no MP4 do trecho: no VOD, seek direto; no YouTube, seek = offset + `startSeconds`. +- **Quadrantes (997 falas, 2026-09-14):** 773 ambos · 151 só VOD · 29 só YouTube · 44 nenhum; o CDN apagou os 924 MP4s entre 04:35 e 08:05. +- **Regeneração observada:** ausente → `GERANDO` → `PRONTO` com hash novo (arquivo responde 206 `video/mp4`); `PRONTO` velho pode devolver hash morto e não aceita forçar (id 996) → tratar como indisponível. +- **Default de produto:** YouTube quando existir; VOD da Câmara sob demanda para o trecho exato/download. Crédito mantido: `Fonte: Câmara dos Deputados · CC BY 4.0`. + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/components/campaign/speech/SpeechDetailPlayer.tsx` (player + transcrição); `src/utilities/speech/` (resolução VOD server-side); `src/app/(campaign)/campanha/(app)/comunicacao/acervo/[id]/page.tsx` + `speechPageData.ts`/`speechViewModels.ts` (levar `eventId`/`audioId`/`excerptTMs`/`eventStartAt` ao view — hoje não chegam); `src/app/(campaign)/campanha/actions/` ou rota JSON com `campaignJsonMutationRoute`; `SpeechResultCard.tsx` (se o "Baixar" da lista sair). +- **Precedente a olhar:** fetch externo com timeout em `src/utilities/speech/speechClassifier.ts:89-105` e `src/utilities/googleCalendarClient.ts:32`; pendência com `useActionState` em `src/components/campaign/advisor/AdvisorPasswordResetButton.tsx`; embed `youtube-nocookie` em `src/components/CampaignStorySection.tsx:54-61`; ladder `getCampaignActionContext` + `runCampaignFormAction`; e2e `tests/e2e/campaignSpeechAcervo.e2e.spec.ts` (contrato `