---
name: comfyui_fetch_output_video
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def comfyui_fetch_output_video(prompt_id: str, *, server: str = \"127.0.0.1:8188\", dest: str | None = None, outputs: dict | None = None, timeout: float = 120.0) -> dict"
description: "Localiza y descarga el output de video/animacion de un workflow ComfyUI a disco local. Hermana de comfyui_fetch_output_image y comfyui_fetch_output_mesh pero para los nodos de video (SaveAnimatedWEBP, SaveVideo nativo, VHS_VideoCombine): esos exponen su salida en GET /history bajo 'images', 'gifs' o 'videos' con items {filename, subfolder, type}. Localiza el primer .mp4/.webm/.webp/.gif/.mkv/.mov/.avif, lo baja via GET /view y opcionalmente lo escribe en dest. Acepta outputs= ya obtenido de comfyui_wait_result para evitar re-consultar /history. Impura: HTTP GET + escritura en disco, solo stdlib."
tags: [comfyui, video, fetch, animation, ml, download, workflow]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: error_go_core
imports: []
params:
  - name: prompt_id
    desc: "id devuelto por comfyui_submit_workflow, de un workflow cuyo nodo de video (SaveAnimatedWEBP/SaveVideo/VHS_VideoCombine) ya termino (usa comfyui_wait_result antes si dudas). Se ignora si se pasa outputs."
  - name: server
    desc: "host:port del servidor ComfyUI sin esquema. keyword-only."
  - name: dest
    desc: "Ruta destino. Si None, escribe el basename del video en el cwd. Si es un directorio existente (o termina en separador), escribe el basename dentro. Si es una ruta de archivo, escribe ahi. keyword-only."
  - name: outputs
    desc: "dict de outputs ya obtenido (el que devuelve comfyui_wait_result). Si se pasa, se busca el video ahi y NO se consulta /history (evita una peticion de red extra). keyword-only."
  - name: timeout
    desc: "Timeout de cada peticion HTTP en segundos. keyword-only."
output: "dict {ok, path, format, bytes, error}. path = ruta local del archivo de video guardado, format = extension sin punto (ej. 'mp4' o 'webp'), bytes = bytes descargados. Si falla, ok=False y error explica (sin video en los outputs, HTTP, conexion o escritura)."
tested: true
tests:
  - "test_is_video_item_por_extension"
  - "test_is_video_item_fallback_format"
  - "test_find_saveanimatedwebp_bajo_images"
  - "test_find_savevideo_mp4_bajo_images"
  - "test_find_vhs_bajo_gifs"
  - "test_find_prioriza_clave_video_sobre_images"
  - "test_find_sin_video_devuelve_none"
test_file_path: "python/functions/ml/comfyui_fetch_output_video_test.py"
file_path: "python/functions/ml/comfyui_fetch_output_video.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_fetch_output_video import comfyui_fetch_output_video

# Tras comfyui_submit_workflow + comfyui_wait_result de un workflow de video
# (SVD img2vid, LTX, AnimateDiff...), baja el .mp4/.webp al disco.
res = comfyui_fetch_output_video("8a278988-8a94-4225-add3-88a406f7101c", dest="/tmp/videos")
# res == {"ok": True, "path": "/tmp/videos/video_00003_.mp4",
#         "format": "mp4", "bytes": 199413, "error": ""}

# Si ya tienes los outputs de comfyui_wait_result, pasalos y evita re-consultar /history:
outputs = {"79": {"images": [{"filename": "video_00003_.mp4", "subfolder": "", "type": "output"}]}}
res2 = comfyui_fetch_output_video("ignored", dest="/tmp/videos", outputs=outputs)
```

Lánzalo con el python del venv (import de arriba o heredoc). Nota: `./fn run` directo no aplica porque la firma usa `*` (keyword-only), no soportado por el generador de runner de `fn run`.

## Cuando usarla

Después de generar un vídeo o animación con ComfyUI (img2vid SVD, LTX, AnimateDiff,
Wan, cualquier workflow con SaveAnimatedWEBP / SaveVideo / VHS_VideoCombine), cuando
necesites el archivo `.mp4`/`.webp`/`.webm`/`.gif` real en disco (no solo su nombre):
para reproducirlo, subirlo a un vault, o post-procesarlo. Es la hermana de
`comfyui_fetch_output_image` (imágenes estáticas) y `comfyui_fetch_output_mesh`
(mallas 3D). Para el flujo completo de un workflow ajeno usa el pipeline
`comfyui_run_foreign_workflow_oneshot`, que ya elige este fetch según el tipo de output.

## Gotchas

- Impura: hace HTTP GET a /history y /view y escribe en disco. Requiere el server
  vivo y que el prompt YA haya terminado (usa `comfyui_wait_result` antes, o pásale
  `outputs=`).
- Distintos nodos exponen el vídeo bajo distintas claves: SVD y SaveVideo nativo lo
  ponen bajo `"images"`, VHS_VideoCombine bajo `"gifs"`, otros bajo `"videos"`. La
  función inspecciona primero las claves preferentes (gifs/videos/animated) y luego
  cualquier clave, así que cubre los tres casos.
- Un `.webp` se trata como animación/vídeo (los nodos de animación de ComfyUI lo
  usan). Si tu workflow guarda una imagen `.webp` ESTÁTICA, esta función la bajaría
  igual; para garantizar imagen estática usa `comfyui_fetch_output_image` con el
  filename concreto.
- Toma el PRIMER archivo de vídeo que encuentra. Si un workflow exporta varios,
  baja solo uno; para los demás llama otra vez o usa GET /view con el filename concreto.
- El history se purga al reiniciar el server: si el prompt ya no está, devuelve
  `ok=False`. Pasar `outputs=` evita esa consulta y el problema.
- `dest` se interpreta: None -> cwd; directorio EXISTENTE -> dentro; ruta de archivo
  -> esa ruta. Un directorio que aún no existe se trata como ruta de archivo: créalo
  antes (o termina la ruta en separador).
