mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
Some checks are pending
Deploy / preflight (push) Waiting to run
Deploy / verify (push) Blocked by required conditions
Deploy / deploy staging (teqo-staging) (push) Blocked by required conditions
Deploy / requeue when main advanced (push) Blocked by required conditions
Deploy / deploy production (teqo-1313) (push) Blocked by required conditions
Peça de vídeo publicada e com arquivo passa a mostrar um frame estático leve no card público antes do play, sem nenhum request do arquivo antes do gesto (`preload="none"` do S27 intacto). O frame é um derivado privado em `contentMedia` (nome determinístico), gerado por um dono só — `ensureContentPieceFrame` — chamado pelo job C211 (que já tem o arquivo em disco: a extração sai de graça) e pela rota `GET /conteudos/<slug>/frame` em miss, que cura o acervo anterior sem backfill, fila, collection nova ou migration. A porta reusa o gate de slug publicado e o proxy de mídia privada do `/midia`: o kill switch fecha as duas de uma vez. Sem frame possível, o slot mostra o estado neutro honesto com play e o marcador — nunca imagem quebrada, nunca retry. A projeção declara o frame por elegibilidade (vídeo com arquivo), não pela existência do derivado, então a cura é invisível para o cache da listagem e não há tag para bustar. O frame também aparece na página da peça e no card da home (variante compacta de 124px, cena 05). A passagem de design (tier primário) achou dois bugs que só o browser mostra: o glyph de imagem quebrada numa requisição que falha, e — ao esconder a imagem até decodificar — o frame sumindo para sempre no caminho mais rápido (uma imagem que carrega antes da hidratação não dispara `load` nem `error` de novo; o `ref` decide os dois desfechos). Também: o guard de falha de e2e aceita `RegExp` e confere os paths declarados antes do caso do favicon (todo 404 do browser traz a mesma mensagem), o manifest de e2e mapeia os módulos novos, e o job C211 passa o arquivo que já tem em disco em vez de rebaixar o vídeo. Design tier: central-conteudos-preview-frame-video Closes #1352
55 lines
1.8 KiB
JavaScript
Executable file
55 lines
1.8 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
/**
|
|
* C167/C199 test double for ffmpeg: copies the `-i` input to the output path so
|
|
* the cut/recording pipelines can run without a real encoder (the developer
|
|
* machine has none). A `%0Nd` output pattern (C199's `-f segment`) produces
|
|
* numbered copies instead of one literal file, mirroring what the segmented
|
|
* command writes. `FAKE_FFMPEG_FAIL=1` makes it exit 1; `FAKE_FFMPEG_LOG=<path>`
|
|
* records argv. The real binary is exercised by the `skipIf(!hasFfmpeg())`
|
|
* block (CI).
|
|
*
|
|
* `FAKE_FFMPEG_FAIL_STILL=1` (C226) fails only the still command — the one
|
|
* carrying `-frames:v 1` — so a spec can pin a pipeline that ingests perfectly
|
|
* and then fails to produce a frame, which `FAKE_FFMPEG_FAIL` cannot express
|
|
* (it would fail the audio extraction too).
|
|
*/
|
|
import { copyFileSync, writeFileSync } from 'node:fs'
|
|
import { argv, env, exit } from 'node:process'
|
|
|
|
const args = argv.slice(2)
|
|
|
|
if (env.FAKE_FFMPEG_LOG) {
|
|
writeFileSync(env.FAKE_FFMPEG_LOG, JSON.stringify(args))
|
|
}
|
|
|
|
if (env.FAKE_FFMPEG_FAIL === '1') {
|
|
process.stderr.write('fake-ffmpeg: forced failure\n')
|
|
exit(1)
|
|
}
|
|
|
|
if (env.FAKE_FFMPEG_FAIL_STILL === '1' && args.includes('-frames:v')) {
|
|
process.stderr.write('fake-ffmpeg: forced still failure\n')
|
|
exit(1)
|
|
}
|
|
|
|
const inputIndex = args.indexOf('-i')
|
|
const input = inputIndex >= 0 ? args[inputIndex + 1] : undefined
|
|
const output = args.at(-1)
|
|
|
|
if (!input || !output) {
|
|
process.stderr.write('fake-ffmpeg: missing -i input or output path\n')
|
|
exit(2)
|
|
}
|
|
|
|
const segmentPattern = /%0?(\d+)d/.exec(output)
|
|
if (segmentPattern) {
|
|
const width = Number(segmentPattern[1])
|
|
const count = Number(env.FAKE_FFMPEG_SEGMENTS ?? '2')
|
|
for (let index = 0; index < count; index += 1) {
|
|
const name = output.replace(segmentPattern[0], String(index).padStart(width, '0'))
|
|
copyFileSync(input, name)
|
|
}
|
|
exit(0)
|
|
}
|
|
|
|
copyFileSync(input, output)
|