Pinchflat-ngx es un fork comunitario de Pinchflat, el gestor autoalojado que descarga canales y listas de YouTube a una carpeta, y funciona como sustituto directo con Docker Compose. El 7 de octubre de 2026 lo instalé desde cero, le di el volumen de configuración de un Pinchflat antiguo y descargué dos vídeos con licencia Creative Commons a una estructura que Jellyfin entiende. Aquí tienes el compose, la migración y lo que falló por el camino. También tienes la versión en inglés.

Puntos clave

  • El boletín selfh.st del 2 de octubre de 2026[1] presenta el fork como "a fork of the popular YouTube video downloader project Pinchflat, which hasn’t seen any activity in ~10 months".
  • El último commit de Pinchflat es del 16 de diciembre de 2025 y su última versión es la v2025.9.26. Pinchflat-ngx publicó la 2026.9.28 el 27 de septiembre de 2026.
  • Pinchflat-ngx usa la misma licencia (AGPL-3.0), el mismo puerto (8945) y los mismos volúmenes /config y /downloads.
  • Migré cambiando solo la imagen: la base de datos antigua aplicó 33 migraciones y el perfil y la fuente siguieron ahí.
  • Con el perfil Media Center bajé 2 vídeos (10 MiB en total) con su .nfo y su miniatura, listos para Jellyfin o Plex.

Qué es Pinchflat-ngx y por qué importa ahora

Pinchflat-ngx es una bifurcación de Pinchflat[2] que mantiene una sola persona, TheBadFella, y que empezó el 16 de junio de 2026. Pinchflat te deja definir canales y listas de reproducción de YouTube, y una cola de yt-dlp[3] los descarga y los guarda con el nombre que tú elijas. Es lo que alimenta una biblioteca de Jellyfin o Plex sin tocar nada a mano.

El motivo del fork es de mantenimiento. El repositorio original tiene 5 396 estrellas, su último commit es del 16 de diciembre de 2025 y su última versión lleva fecha del 26 de septiembre de 2025. El fork tiene 152 estrellas, cinco versiones entre el 7 de septiembre y el 27 de septiembre de 2026 y, según su README, añade:

  • Base de datos: SQLite o PostgreSQL 18, con la imagen latest-postgres
  • Acceso: autenticación básica o inicio de sesión único con OIDC
  • Descargas: un proveedor opcional de PO tokens para cuando YouTube bloquea, y una carpeta de preparación en disco local para destinos en red
  • Fuentes: vídeos sueltos, además de canales y listas, y selección de qué vídeos de una lista se bajan
  • Operación: diagnóstico de la cola y control del canal de actualización de yt-dlp

Es un proyecto joven de un solo mantenedor, así que trátalo como tal: haz copia de seguridad antes de migrar y fija una versión en lugar de usar latest.

Instalar Pinchflat-ngx con Docker Compose

La instalación es un servicio con dos volúmenes. Usé la versión 2026.9.28 en una máquina arm64 con Docker, y el README del proyecto[4] y su wiki confirman que la imagen es multiplataforma (amd64 y arm64). Este compose.yaml es el mío, con la versión fijada:

services:
  pinchflat-ngx:
    image: ghcr.io/thebadfella/pinchflat-ngx:2026.9.28
    environment:
      TZ: Europe/Madrid
    ports:
      - "8945:8945"
    volumes:
      - ./config:/config
      - ./downloads:/downloads
    restart: unless-stopped

Crea las carpetas config y downloads, ejecuta docker compose up -d y abre http://localhost:8945. Mantén config en un disco local: la wiki avisa de que el modo WAL de SQLite no está pensado para los sistemas de ficheros en red habituales. La imagen pesa 990 MB en disco.

Dos detalles de mi prueba.

El contenedor corre como root, así que los ficheros descargados quedan con propietario root; si Jellyfin corre con otro usuario, comprueba que puede leerlos (la variable UMASK por defecto es 022, y deja los ficheros legibles). Y en el primer arranque el registro mostró Couldn't resolve latest stable yt-dlp version ... HTTP request failed with status code 403. La comprobación de versión choca con el límite de peticiones de GitHub desde una IP compartida. La aplicación sigue con el yt-dlp de la imagen (2026.09.16.232951).

Migrar de Pinchflat a Pinchflat-ngx sin perder fuentes

La migración consiste en arrancar la imagen nueva sobre el volumen /config de la instalación antigua, porque Pinchflat-ngx migra la base de datos SQLite al arrancar. El mantenedor avisa en la incidencia 82[5] de que no ha probado el salto completo desde el Pinchflat original. Allí, tres usuarios cuentan que cambiar la imagen les funcionó.

Reproduje el caso. Levanté el Pinchflat original (ghcr.io/kieraneglin/pinchflat:latest, con yt-dlp 2025.09.26), creé un perfil de medios y una fuente, lo paré y copié config a config.bak. Después arranqué Pinchflat-ngx sobre el mismo config y downloads. Un detalle: el manifiesto de esa etiqueta solo listaba linux/amd64 el 7 de octubre de 2026, así que lo ejecuté con emulación en mi máquina arm64.

El registro de Pinchflat-ngx mostró 33 líneas == Running ... de migraciones, desde 20260308222828 hasta 20260927170000. Tras ellas, la portada mostraba 1 perfil de medios y 1 fuente: nada se perdió. Si tu instalación usa Basic Auth, copia también BASIC_AUTH_USERNAME y BASIC_AUTH_PASSWORD. Estos son los pasos que seguiría en una instalación real:

  1. Copia de seguridad. Para el contenedor antiguo y copia la carpeta config entera, con los ficheros pinchflat.db-wal y -shm.
  2. Cambia la imagen en tu compose.yaml, sin tocar los volúmenes ni el puerto.
  3. Arranca y revisa la portada: perfiles, fuentes y biblioteca.
  4. Vuelve atrás si algo falla: restaura config.bak y la imagen antigua. Las migraciones no son reversibles, así que la copia es tu única salida.

El fork no copia datos de SQLite a PostgreSQL. Para una instalación existente, su README manda seguir con la imagen latest (SQLite).

Un perfil de medios para Jellyfin y Plex

Un perfil de medios decide cómo se nombran y se guardan los vídeos, y el preajuste Media Center deja la salida lista para un servidor de medios. En la pantalla Nuevo perfil, elige "Media Center (Plex, Jellyfin, Kodi, etc.)" en el desplegable y pulsa Load. Eso rellena la plantilla de salida y activa las miniaturas y los NFO:

/shows/{{ source_custom_name }}/
  {{ season_by_year__episode_by_date_and_index }} - {{ title }}.{{ ext }}

Creé el perfil "Jellyfin", bajé la resolución preferida a 360p para que las pruebas pesaran poco y desactivé los subtítulos. Las casillas "Create NFO data" y "Download Series Images" quedaron activadas. La etiqueta "(pro)" sigue junto a la primera, pero los NFO se generaron igualmente.

Descargar una lista de reproducción a una carpeta para Jellyfin

Una fuente es un canal o una lista, y su perfil decide dónde caen los ficheros. Antes de bajar nada, comprueba qué permite YouTube: sus condiciones del servicio[6] prohíben descargar contenido salvo que el propio servicio lo permita o que YouTube dé permiso por escrito. Por eso usé solo vídeos con licencia Creative Commons Attribution (CC BY), que yt-dlp informa en el campo license, y los cortos animados "Caminandes", hechos con Blender. Esto no es asesoramiento legal: revisa la licencia de cada vídeo y la tuya.

La lista tiene 13 elementos de autores distintos, y no quería bajarlos todos. Creé una fuente con la URL de la lista, el nombre "Caminandes", indexación única y duración máxima de 200 s. Añadí el filtro de título ^Caminandes (1|3): Llam, que deja pasar solo "Caminandes 1: Llama Drama" y "Caminandes 3: Llamigos", ambos CC BY. Pinchflat-ngx añade, además, una selección manual de elementos de una lista, que no usé.

El resultado en downloads:

shows/Caminandes/
  Season 2013/
    s2013e020900 - Caminandes 1: Llama Drama - ....mp4  (3,9 MiB)
    s2013e020900 - Caminandes 1: Llama Drama - ....nfo
    s2013e020900 - Caminandes 1: Llama Drama - ....jpg
  Season 2016/
    s2016e013000 - Caminandes 3: Llamigos.mp4           (6,6 MiB)
    s2016e013000 - Caminandes 3: Llamigos.nfo
    s2016e013000 - Caminandes 3: Llamigos.jpg

El vídeo de Llamigos es un H.264 de 640 por 360 con audio AAC. Los dos puntos de los títulos se guardan como el carácter de ancho completo :, porque : no es válido en algunos sistemas de ficheros. Cada NFO es un episodedetails que Jellyfin lee, con título, descripción, fecha de emisión, temporada y episodio:

<episodedetails>
  <title>Caminandes 3: Llamigos</title>
  <showtitle>Blender</showtitle>
  <uniqueid type="youtube" default="true">SkVqJ1SGeL0</uniqueid>
  <aired>2016-01-30</aired>
  <season>2016</season>
  <episode>013000</episode>
</episodedetails>

Yo no conecté Jellyfin a esta carpeta, así que no puedo confirmar cómo la muestra. Lo que sí está en la documentación de Jellyfin[7] es que "Jellyfin can read and write local .nfo metadata files", y que el NFO de un episodio debe llamarse como su fichero de vídeo, que es lo que hace esta salida. Falta además el tvshow.nfo con el póster de la serie: la opción "Download Series Images" solo funciona con canales completos, no con listas. Para montar el servidor, mira cómo instalar Jellyfin con Docker y apunta su biblioteca a shows; si ya lo tienes, la guía para actualizar Jellyfin 12 con Docker cubre el cambio de versión.

Qué pasa cuando YouTube bloquea la descarga

Mi primera descarga falló con ERROR: unable to download video data: HTTP Error 403: Forbidden. Pasó con el yt-dlp 2026.09.16 de la imagen nueva, tras migrar: obtuvo la lista de formatos pero YouTube rechazó los trozos de vídeo. La misma fuente, con el yt-dlp 2025.09.26 del Pinchflat original, ya había fallado antes con The page needs to be reloaded y el aviso de que YouTube fuerza el streaming SABR.

Para probar el remedio que ofrece el fork, añadí el proveedor de PO tokens brainicism/bgutil-ytdlp-pot-provider:2.0.0 como segundo servicio de Compose, con el perfil pot-provider para que sea opcional, y la variable POT_PROVIDER_URL:

services:
  pinchflat-ngx:
    environment:
      POT_PROVIDER_URL: http://pot-provider:4416

  pot-provider:
    image: brainicism/bgutil-ytdlp-pot-provider:2.0.0
    profiles: [pot-provider]
    restart: unless-stopped

Se arranca con docker compose --profile pot-provider up -d; es lo que explica la guía de perfiles de Docker Compose. Después de levantarlo, pulsé el botón de descarga del elemento y las dos descargas terminaron. No puedo atribuirlo al proveedor: probé yt-dlp a mano dentro del contenedor y también descargó sin él, con PO Token Providers: none en su traza, así que el 403 pudo ser intermitente. Mi conclusión es que ante un 403 conviene reintentar, actualizar yt-dlp y, si persiste, activar el proveedor, que es lo que recomienda el PO Token Guide de yt-dlp[8].

Cuándo no merece la pena migrar

Quédate en Pinchflat si funciona y no necesitas nada del fork: su imagen no cambia, y yt-dlp se puede actualizar sin cambiar de aplicación. Migra si te importa que alguien publique correcciones, si necesitas PostgreSQL u OIDC, o si tu yt-dlp antiguo ya falla contra YouTube, como me pasó. Pesa en contra que el fork tiene un solo mantenedor y 152 estrellas frente a 5 396, y que la ruta de migración sigue sin documentación oficial.

Preguntas frecuentes

¿Pinchflat-ngx es compatible con mi base de datos de Pinchflat?

En mi prueba sí: la base de datos SQLite del Pinchflat original aplicó 33 migraciones y conservó el perfil y la fuente. El mantenedor no lo ha probado de punta a punta y no hay guía oficial, así que haz una copia de config antes.

¿Puedo usar Pinchflat-ngx con Plex en lugar de Jellyfin?

Sí. La salida con temporadas, episodios y NFO que genera el preajuste Media Center es la misma para Plex, Jellyfin y Kodi, según la propia descripción del preajuste. Yo solo verifiqué los ficheros, no la lectura desde Plex ni Jellyfin.

Depende del vídeo. Las condiciones de YouTube prohíben descargar salvo permiso del servicio o por escrito. Limítate a tu propio contenido o a vídeos con licencia que lo permita, como Creative Commons. Respeta la atribución de cada licencia.

Conclusión

Pinchflat-ngx cumple lo que promete como sustituto de Pinchflat: mismo puerto, mismos volúmenes y una migración automática que, en mi prueba, conservó el perfil y la fuente. Descarga con la estructura y los NFO que Jellyfin espera, y trae el proveedor de PO tokens para cuando YouTube bloquea.

Antes de migrar tu instalación real, copia config, fija la versión de la imagen y revisa la licencia de lo que descargas. Si algo falla con YouTube, el primer paso es actualizar yt-dlp.

Fuentes: [1] Self-Host Weekly, 2 de octubre de 2026[1], [2] Pinchflat-ngx en GitHub[4], [3] Incidencia 82: migración desde Pinchflat[5], [4] Pinchflat original en GitHub[2], [5] Metadatos .nfo locales en Jellyfin[7], [6] Condiciones del servicio de YouTube[6], [7] PO Token Guide de yt-dlp[8].

Fuentes

  1. boletín selfh.st del 2 de octubre de 2026
  2. Pinchflat
  3. yt-dlp
  4. README del proyecto
  5. incidencia 82
  6. condiciones del servicio
  7. documentación de Jellyfin
  8. PO Token Guide de yt-dlp