Skip to content
abeguerr01Public

About

This web application provides a site to display and view video files from any device connected to the local network.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

📺 FlaskCast — Plataforma Multimedia Local

🌐 Read in English

FlaskCast Logo

FlaskCast es un portal de streaming multimedia personal y local construido con Python y Flask. Permite organizar catálogos de series y películas por carpetas, generar miniaturas automáticamente, transcodificar formatos incompatibles en segundo plano con FFmpeg, guardar el progreso de reproducción por usuario y gestionar el contenido mediante una API REST.


⚠ Aviso Legal y Exención de Responsabilidad

FlaskCast es una herramienta de uso privado y local diseñada exclusivamente para organizar y reproducir contenido multimedia al que el usuario posee los derechos legales de uso. En ningún caso FlaskCast facilita, promueve ni permite la obtención o distribución de contenido protegido por derechos de autor sin la debida autorización.

El usuario es el único responsable del contenido que alberga, organiza y reproduce mediante esta aplicación. El desarrollador de FlaskCast declina toda responsabilidad derivada del uso indebido de esta herramienta en relación con material sobre el que el usuario no tenga derechos legales.

El uso de FlaskCast implica la aceptación de estas condiciones.


Características principales

  • Catálogo por carpetas: organiza series, temporadas y capítulos directamente desde el sistema de archivos.
  • Diferenciación Películas/Series: detección automática por estructura de carpetas, con badge visual 🎬/📺 y filtro en catálogo. Soporte para override manual vía _meta.json o tabla content_metadata.
  • Continuar viendo: sección destacada en el catálogo que muestra los capítulos en progreso ordenados por recencia, con barra de porcentaje.
  • Transcodificación asíncrona: convierte .avi/.mkv a .mp4 en segundo plano usando FFmpeg, con detección automática del mejor códec H.264 disponible (libx264, libopenh264, h264_nvenc, etc.), barra de progreso en tiempo real y verificación de éxito/fallo.
  • Miniaturas dinámicas: extrae fotogramas como .jpg para previsualizaciones.
  • Seguimiento por usuario: guarda la posición exacta (segundos), marca "En progreso" y "Visto" según umbrales configurables.
  • Listas personalizadas: organiza contenido en Favoritos, Pendiente, Viendo y Visto con pestañas filtrables.
  • Paginación del catálogo: 24 elementos por página con controles de navegación.
  • Tema claro/oscuro: toggle entre tema oscuro (por defecto) y claro, guardado por usuario.
  • Transiciones SPA: navegación entre páginas con fade animations y fetch AJAX.
  • API REST completa: añade, elimina, lista, descarga vídeos y gestiona el progreso mediante endpoints protegidos por toggle.
  • Streaming en Vivo: reproduce streams en directo (HLS, iframes, vídeos) con soporte para listas M3U, modo SmartTV y fallback automático con múltiples fuentes. Incluye gestión web de streams desde el navegador (añadir/editar/eliminar/reordenar, tipo hls/video/iframe/m3u/auto), visible solo para cuentas registradas.
  • Modo SmartTV: reproductor optimizado para televisores conectados a la red local.
  • Auto-reproducción: el reproductor avanza automáticamente al siguiente capítulo de la temporada.
  • Interfaz responsive: diseño adaptable con sidebar colapsable en móvil (hamburger menu), breakpoints a 900px, 768px y 480px.
  • Interfaz ligera: HTML5, CSS y JavaScript Vanilla para reproducción y búsqueda en tiempo real.
  • Multi-idioma (i18n): soporte español/inglés con cambio por usuario. Géneros y descripciones de OMDb se traducen automáticamente.
  • Integración OMDb: obtención automática de portadas, descripciones, valoraciones y metadatos desde OMDb API. Clave guardada en .env y reutilizable desde la web o el panel de administración.
  • Biblioteca web (Gestionar Biblioteca): gestión completa de series, películas, temporadas y vídeos desde el navegador (/biblioteca), con la UI de administración integrada en el sidebar (justo antes de "Cerrar sesión") y conector OMDb incluido. El enlace solo aparece para cuentas registradas (oculto para invitados).
  • Diseño hero: vista detalle con banner de portada difuminada, metadata visual y botones de acción.
  • Panel de administración GUI: gestión visual de contenido, streams, configuración y OMDb con interfaz en tkinter (5 pestañas, bilingual ES/EN).
  • Autenticación opcional: protección con contraseña para acceder a la aplicación. Se activa/desactiva desde el panel de administración. Cuando está activa, todas las rutas web requieren autenticarse previamente con la contraseña configurada.

Tecnologías

  • Backend: Python 3 + Flask
  • Base de datos: SQLite3 (flaskcast.db)
  • Procesamiento de vídeo: FFmpeg (gestión automática con static-ffmpeg)
  • Concurrencia: threading para evitar colisiones en conversiones
  • Rate Limiting: Flask-Limiter (protección contra abuso de API)
  • Frontend: HTML5, CSS3 y JavaScript
  • Template Engine: Jinja2 con herencia de plantillas (base.html)
  • Servidores de producción: Waitress (Windows) / Gunicorn (Linux)
  • Compresión: py7zr (exportar/importar contenido)
  • Traducción: MyMemory API (descripciones) + diccionario local (géneros)

Instalación rápida

  1. Clona o descarga el proyecto y sitúate en la carpeta raíz:
git clone <repo> && cd FlaskCast
  1. Crea y activa un entorno virtual (recomendado):
python -m venv venv
venv\Scripts\activate    # Windows
source venv/bin/activate # Linux / macOS
  1. Instala las dependencias:
pip install -r requirements.txt
  1. Ejecuta la aplicación:
python app.py

Accede desde el navegador en http://localhost:5000 o usando la IP de tu equipo en la red local.

Notas sobre dependencias

⚠️ Linux: FFmpeg es obligatorio. La aplicación no arrancará sin él.

📥 Instalar FFmpeg en Linux (click para desplegar)
# Debian / Ubuntu / Linux Mint / Pop!_OS
sudo apt-get update && sudo apt-get install -y ffmpeg

# Fedora / RHEL / CentOS / Rocky / AlmaLinux
sudo dnf install -y ffmpeg

# Arch Linux / Manjaro / EndeavourOS
sudo pacman -S --noconfirm ffmpeg

# openSUSE / SUSE
sudo zypper install -y ffmpeg

# Alpine Linux
sudo apk add ffmpeg

# Void Linux
sudo xbps-install -Sy ffmpeg

# Gentoo
sudo emerge media-video/ffmpeg

🪟 Windows/macOS: static-ffmpeg descargará y configurará los binarios de FFmpeg automáticamente la primera vez que se ejecute la aplicación. No se necesita instalación manual.

  • py7zr se usa para las funciones de exportar/importar contenido multimedia en el panel de administración.
  • Flask-Limiter proporciona rate limiting para proteger contra abuso de la API.
  • waitress se usa como servidor WSGI de producción en Windows y Linux.

Despliegue en producción

En Windows y Linux, FlaskCast usa Waitress (6 threads). El estado de las conversiones se comparte en memoria dentro del único proceso, igual que antes con Gunicorn. El puerto se configura en data/config.json o mediante el panel de administración.

Instalar o compilar como ejecutable independiente (Windows/Linux)

FlaskCast puede usarse sin instalar Python de dos formas:

1. Binarios precompilados (FlaskCast.exe en Windows, ELF FlaskCast en Linux):

  • El binario lleva Python embebido (PyInstaller), así que el usuario final no necesita instalar nada. Copia el binario donde quieras ejecutarlo.
  • ⚠️ Windows: al ser un .exe sin firma digital, Smart App Control / SmartScreen puede bloquearlo la primera vez (ver la Guía de instalación).
  • ⚠️ Linux: el ELF distribuido está compilado con la versión más nueva de Ubuntu y depende de su glibc. Funciona en esa distro y en las más recientes, pero puede fallar en distros más antiguas (error típico: GLIBC_x.x not found). Si falla, compila tu propio binario (punto 2).

2. Compilar tu propio binario (cada binario se genera en su propio sistema y se guarda en bin/; los binarios no se suben al repositorio):

  • Windows: ejecuta build_windows.bat (equivale a python -m PyInstaller --noconfirm --clean --distpath bin FlaskCast.spec).
  • Linux: ejecuta bash build_linux.sh. El script comprueba que Tkinter esté disponible (python3-tk), instala requirements.txt y PyInstaller automáticamente (funciona incluso en un entorno limpio tipo WSL) y equivale a python3 -m PyInstaller --noconfirm --clean --distpath bin FlaskCast.spec.
  • 💡 En Linux compila en la distro más antigua que quieras soportar (p. ej. Debian 11 / Ubuntu 20.04): el binario hereda la versión de glibc del sistema de compilación. Compilar dentro de WSL es válido; el ELF resultante corre en Linux (no en Windows).

Comportamiento del binario:

  • Al arrancar pregunta si quieres iniciar el servidor (Enter, por defecto) o abrir la configuración (C). Al cerrar la configuración vuelve a preguntar si quieres iniciar el servidor. Desde la web, el botón "Abrir Panel de Administración" de /ajustes lanza el panel dentro del propio ejecutable.
  • El puerto se elige al iniciar el servidor por consola. Si solo pulsas Enter, usa el de data/config.json (5000 por defecto). Si el puerto escrito está ocupado, muestra un error ("El puerto X está ocupado") y vuelve al menú sin iniciar el servicio. Con la opción de puerto eliminada del panel tkinter, el puerto ya no se configura ahí.
  • Espera una carpeta data/ junto a él. Si falta, crea automáticamente data/, data/media/, data/config.json, data/live_streams.json y .env en el directorio del ejecutable.
  • En la primera ejecución muestra un diálogo informando qué se creó (y avisa si data/media está vacía).
  • Incluye plantillas y estáticos; static-ffmpeg descarga FFmpeg la primera vez en la caché del usuario, así que el primer arranque puede tardar un poco.
  • La ventana de consola permanece abierta mostrando los logs del servidor y el menú de inicio.
  • El .exe de Windows lleva el icono de static/logo.png embebido (icon.ico se genera solo durante la compilación con generar_icono.py). En Linux los binarios ELF no incorporan iconos en el ejecutable: build_linux.sh genera bin/FlaskCast.desktop junto al binario apuntando a bin/logo.png para el lanzador.

Docker

docker-compose up --build

Nota para Docker: si ejecutas FlaskCast mediante docker-compose, el cambio de puerto desde config_admin.py no tendrá efecto. El puerto se define en el archivo docker-compose.yml mediante el mapeo ports:.


Variables de entorno

FlaskCast utiliza un archivo .env en la raíz del proyecto para almacenar credenciales sensibles. Este archivo está incluido en .gitignore y no se sube al repositorio.

Variable Descripción
OMDB_API_KEY Clave de API de OMDb para obtención de metadatos y portadas. Se guarda automáticamente al validar desde el panel de administración o se puede configurar con --omdb-key.

Estructura del proyecto

.
├── app.py                   # Aplicación Flask (rutas, API, BD, FFmpeg)
├── config_admin.py          # Panel de administración (GUI tkinter + CLI)
├── translations.py          # Sistema i18n (ES/EN), traducción de metadatos
├── requirements.txt
├── .env                     # Variables de entorno (OMDB_API_KEY) — gitignored
├── Dockerfile
├── docker-compose.yml
├── data/
│   ├── config.json          # Configuración del servidor
│   ├── flaskcast.db         # Base de datos SQLite
│   ├── live_streams.json    # Configuración de streams en vivo
│   └── media/               # Contenido multimedia
├── static/
│   ├── css/
│   │   └── estilos.css      # Estilos globales (tema, responsive, skeletons, badges, hero)
│   ├── js/
│   │   └── reproductor.js   # Lógica del reproductor de vídeo
│   └── logo.png
└── templates/
    ├── base.html            # Plantilla base (sidebar, SPA transitions, layout)
    ├── index.html           # Catálogo principal con paginación, filtros y continuar viendo
    ├── serie.html           # Detalle de serie/película con hero banner y capítulos
    ├── listas.html          # Listas personales (Favoritos, Pendiente, Viendo, Visto)
    ├── player_tv.html       # Reproductor SmartTV (sin sidebar)
    ├── live.html            # Lista de streams en vivo
    ├── live_tv.html         # Reproductor SmartTV para streams (sin sidebar)
    ├── usuarios.html        # Panel de gestión de usuarios
    └── ajustes.html         # Panel de configuración (tema, idioma, marcado automático)

Archivos de datos (no versionados)

Archivo Contenido
.env OMDB_API_KEY — clave de API de OMDb
data/config.json Puerto, botones de apagado, API habilitada, idioma del admin, autenticación (auth_enabled, auth_password)
data/flaskcast.db SQLite: usuarios, progreso, favoritos, listas, content_metadata
data/live_streams.json Definición de canales en vivo
data/media/ Carpetas de series/películas, portadas, miniaturas

Base de datos

FlaskCast usa SQLite con modo WAL para concurrencia. Las tablas se crean automáticamente al iniciar la aplicación.

Tabla Descripción
usuarios Perfiles de usuario (nombre, emoji, tema, idioma, auto_marcar, mostrar_progreso)
progreso Posición de reproducción por usuario y vídeo (segundos, visto, duración)
favoritos Series/películas marcadas como favoritas por usuario
listas Estado en lista por usuario y serie (0=Pendiente, 1=Viendo, 2=Visto)
content_metadata Override manual de tipo de contenido (pelicula/serie)

Herencia de Plantillas

Todas las plantillas heredan de base.html usando Jinja2:

{% extends 'base.html' %}

{% block title %}Mi Página{% endblock %}

{% block head %}
    <style>/* Estilos específicos */</style>
{% endblock %}

{% block content %}
    <!-- Contenido de la página -->
{% endblock %}

base.html incluye:

  • Sidebar de navegación (se oculta en reproductores SmartTV)
  • Bloques extensibles: title, head, content, body_class, sidebar

Estructura del catálogo multimedia (requerida)

Coloca tu contenido en data/media/ siguiendo este patrón:

data/
└── media/
    ├── Nombre de la Serie A/
    │   ├── _img.png                 <-- Portada (obligatoria para mostrar imagen)
    │   ├── _meta.json               <-- Metadatos (opcional, override manual)
    │   ├── Temporada 1/
    │   │   ├── Capitulo_01.mp4
    │   │   └── Capitulo_02.avi
    │   └── Temporada 2/
    │       ├── Capitulo_01.mkv
    │       └── Capitulo_02.mp4
    ├── Nombre de la Serie B (Sin Temporadas)/
    │   ├── _img.png
    │   ├── Video_Suelto_01.mp4
    │   └── Video_Suelto_02.mp4
    └── Mi Pelicula/
        ├── _img.png
        └── pelicula.mp4
  • El archivo de portada debe llamarse exactamente _img.png. Si no existe, la interfaz mostrará un icono genérico (🎬 o 📺 según el tipo).
  • Si no usas subcarpetas de temporada, los vídeos en la raíz aparecerán bajo "Contenido Disponible".

Archivo _meta.json

El archivo _meta.json permite definir metadatos y forzar el tipo de contenido. Formato completo:

{
  "tipo": "pelicula",
  "titulo": "Mi Película",
  "descripcion": "Una descripción de la película.",
  "anio": "2024",
  "genero": ["Acción", "Aventura"],
  "director": "Nombre del Director",
  "valoracion": "8.5",
  "duracion_min": 120,
  "temporadas": 1
}
Campo Tipo Descripción
tipo string "pelicula" o "serie" — fuerza el tipo detectado
titulo string Título display del contenido
descripcion string Descripción (se traduce automáticamente al español si el usuario tiene idioma ES)
anio string Año de estreno
genero array Lista de géneros en inglés (se traducen automáticamente)
director string Nombre del director
valoracion string Puntuación (ej: "8.5")
duracion_min integer Duración en minutos (películas)
temporadas integer Número de temporadas (series)

Los campos titulo, descripcion, anio, genero, director, valoracion, duracion_min y temporadas se rellenan automáticamente al aplicar metadatos de OMDb.

Diferenciación Películas / Series

FlaskCast detecta automáticamente si una carpeta es una película o una serie mediante un sistema de 3 niveles:

Prioridad Fuente Descripción
1 Tabla content_metadata (BD) Override manual guardado en la base de datos
2 Archivo _meta.json Campo tipo en el archivo de metadatos
3 Estructura de carpetas Subcarpetas = serie, solo vídeos = película

Diferencias en la UI:

  • Catálogo: badge 🎬 (dorado) o 📺 (azul) en cada card, con filtro "Todo / Películas / Series"
  • Vista detalle: las películas muestran "🎬 Película" como título de sección y ocultan el acordeón de temporadas; las series muestran "Temporadas Disponibles" con acordeón expandible
  • Hero banner: vista detalle con banner de portada difuminada, metadata visual (año, género, director, valoración, duración) y botones de acción

Traducción de metadatos (i18n)

FlaskCast traduce automáticamente los metadatos de OMDb según el idioma del usuario:

  • Géneros: se traducen localmente mediante un diccionario de 26 géneros (inglés → español) en translations.py.
  • Descripciones: se traducen en tiempo real mediante la API gratuita de MyMemory sin necesidad de clave de API.
  • Fallback: si la traducción falla, se muestra el texto original en inglés.

Gestión de formatos y transcodificación

  • Formatos web nativos (.mp4, .webm, .ogg) se reproducen directamente.
  • Formatos no nativos (.avi, .mkv) aparecen como "Pendiente" y pueden convertirse a .mp4 mediante un botón en la interfaz.
  • La conversión se realiza de forma asíncrona; la app usa threading y bloqueos para evitar conflictos en conversiones simultáneas.
  • Detección automática de códec: al iniciar, la app prueba ffmpeg -encoders y selecciona el mejor codificador H.264 disponible. Compatible con libx264 (Windows), libopenh264 (Linux/Fedora), h264_nvenc, h264_amf, h264_qsv, h264_vaapi.
  • Progreso en tiempo real: la barra de conversión muestra el porcentaje de avance parseando la salida de FFmpeg.
  • Verificación de éxito: se comprueba el código de salida de FFmpeg y la existencia del .mp4 antes de marcar como completado.
  • Ocultación durante conversión: el archivo .mp4 no aparece en la interfaz hasta que la conversión alcanza el 100%.
  • Aislamiento de procesos: FFmpeg se ejecuta en una nueva sesión para resistir Ctrl+C sin abortar la conversión.
  • Conversión: FFmpeg con códec detectado (vídeo) + AAC (audio), CRF 23.

Usuarios y seguimiento de progreso

  • Puedes crear perfiles de usuario con nombre y emoji desde el panel de usuarios.
  • El reproductor envía actualizaciones periódicas al servidor guardando la marca de tiempo actual en la base de datos.
  • Umbrales de marcado automático:
    • 10% reproducido → estado "Viendo" (azul).

    • 85% reproducido → estado "Visto" (verde).

  • También puedes marcar manualmente un capítulo como "Visto" desde la UI.
  • Cada usuario tiene sus propias preferencias: tema, idioma, marcado automático, mostrar progreso.

Continuar viendo

El catálogo principal incluye una sección "▶ Continuar viendo" que muestra hasta 12 capítulos en progreso (estado visto = 1), ordenados por los más recientemente vistos. Cada card muestra una barra de progreso porcentual. Al hacer clic, el reproductor retoma la posición guardada.


Listas personales

FlaskCast incluye una página de listas (/listas) donde los usuarios pueden organizar su contenido:

Pestañas de filtrado

Pestaña Color Descripción
⭐ Favoritos Dorado (#f5a623) Series/películas marcadas como favoritas
📋 Pendiente Gris (#888) Contenido pendiente de ver
👁️ Viendo Azul (#0d6efd) Contenido en progreso
✅ Visto Verde (#1fcc72) Contenido completado
  • Al abrir la página, la pestaña "Favoritos" se muestra seleccionada por defecto.
  • Clic en una pestaña muestra solo esa sección; clic de nuevo la oculta (toggle).
  • Cada card muestra un badge de tipo (🎬/📺) según el contenido.
  • La favoritos se gestionan desde el botón ⭐ en la vista de detalle de cada serie.
  • Pendiente/Viendo/Visto se gestionan desde el botón "+ Añadir" en la vista de detalle.

Paginación del catálogo

El catálogo principal muestra 24 elementos por página con controles de navegación:

  • Botones de página con ellipsis (...) para saltos largos.
  • Botones "Anterior" / "Siguiente" para navegación secuencial.
  • Indicador de rango: "Mostrando X–Y de Z elementos".
  • La paginación es server-side; cada página carga su propio subset de datos.

Diseño responsive

FlaskCast se adapta automáticamente al tamaño de pantalla:

Breakpoint Comportamiento
> 900px Layout completo con sidebar fijo
≤ 900px Sidebar colapsable con hamburger menu
≤ 768px Grid de cards ajustado, header compacto
≤ 480px Grid de 2 columnas, controles apilados
  • Hamburger menu: botón de 3 líneas que abre/cierra el sidebar en móvil.
  • Overlay: al abrir el sidebar, se muestra un overlay oscuro que lo cierra al hacer clic.
  • Transiciones SPA: la navegación entre páginas usa fade animations con skeleton loading durante la carga.

Transiciones SPA (Single Page Application)

FlaskCast simula navegación SPA usando AJAX:

  1. Al hacer clic en un enlace interno, el contenido actual hace fade-out.
  2. Se muestra un skeleton placeholder mientras se carga la nueva página.
  3. El nuevo contenido se inyecta con fade-in animation.
  4. La URL se actualiza con history.pushState().
  5. El sidebar se actualiza para reflejar la sección activa.

Excluidos de las transiciones: enlaces externos, # anchors, modales, reproductores, y elementos con data-no-transition.


Streaming en Vivo (Contenido en Directo)

FlaskCast incluye una sección de streaming en vivo que permite reproducir canales de televisión, radios o cualquier stream en directo desde la interfaz web.

Configuración de streams

Los streams se configuran en el archivo data/live_streams.json. Si el archivo no existe, créalo manualmente con el siguiente formato:

[
  {
    "titulo": "Canal de Ejemplo",
    "url": "http://ejemplo.com/stream.m3u8",
    "tipo": "auto"
  },
  {
    "titulo": "Canal HLS con Fallback",
    "urls": [
      "https://principal.com/stream.m3u8",
      "https://backup1.com/stream.m3u8",
      "https://backup2.com/stream.m3u8"
    ],
    "tipo": "hls"
  },
  {
    "titulo": "Canal Iframe",
    "url": "https://ejemplo.com/embebed-player",
    "tipo": "iframe"
  },
  {
    "titulo": "Lista M3U Completa",
    "url": "https://ejemplo.com/canales.m3u",
    "tipo": "m3u"
  }
]

Los streams también se pueden gestionar visualmente desde:

  • La pestaña "Streamings" del panel de administración (config_admin.py).
  • Desde el navegador: botón ⚙️ Gestionar Streams en la cabecera de En Directo (/live), que abre /live/gestion con CRUD completo, reordenación (▲/▼) y soporte de tipos hls, video, iframe, m3u y auto (los dos últimos no existen en la pestaña del panel). Incluye validación (título y URL obligatorios), confirmación al eliminar y límites de peticiones por minuto en todos los endpoints. El botón solo aparece para cuentas registradas (los invitados no lo ven) y las rutas /live/gestion y /live/streams/* redirigen o rechazan sin sesión de cuenta.

Gestión web de streams

Endpoint Método Descripción Límite
/live/gestion GET Página de gestión de streams (título, URL principal, backups por línea, tipo) —
/live/streams/crear POST Añade un stream nuevo (titulo, url, urls, tipo) 10/min
/live/streams/editar POST Actualiza el stream del índice (indice + datos) 10/min
/live/streams/eliminar POST Elimina el stream del índice (indice) 10/min
/live/streams/mover POST Reordena el stream (indice, direccion: arriba/abajo) 20/min

Los streams se guardan en data/live_streams.json con bloqueo (threading.RLock) para escrituras concurrentes seguras.

Múltiples URLs y fallback automático

Cada stream puede definir múltiples fuentes de reproducción mediante el campo urls (array). Cuando una fuente falla, el reproductor salta automáticamente a la siguiente sin intervención del usuario.

  • Si solo se usa "url" (string), se comporta como una única fuente.
  • Si se usa "urls" (array), el player intentará cada fuente en orden hasta encontrar una que funcione.
  • El campo "url" se mantiene para retrocompatibilidad; si se proporciona "urls", este tiene prioridad.

Tipos de streams soportados

Tipo Descripción Ejemplo
auto Detecta automáticamente el tipo por extensión (.mp4, .m3u8, etc.) http://server/video.mp4
hls Stream HLS (m3u8) con soporte nativo o mediante HLS.js https://server/live.m3u8
video Archivo de vídeo directo (mp4, webm, ogg) http://server/film.mp4
iframe Página embebida en iframe (reproductores de terceros) https://tv.com/player/123
m3u Lista M3U que se parsea automáticamente en múltiples canales https://list.com/channels.m3u

Formato M3U

El parser soporta tanto listas M3U remotas (HTTP/HTTPS) como locales. Formato esperado:

#EXTM3U
#EXTINF:-1 tvg-name="Canal 1",Canal 1
http://server/canal1/stream.m3u8
#EXTINF:-1 tvg-name="Canal 2",Canal 2
http://server/canal2/stream.m3u8

Acceso

  • Lista de canales: http://localhost:5000/live
  • Reproductor SmartTV: http://localhost:5000/live/tv/<indice> (donde <indice> es la posición del canal en la lista, empezando por 0)

Funcionalidades del reproductor en vivo

  • Modal en PC: al hacer clic en "Ver", se abre un reproductor modal superpuesto.
  • Modo SmartTV: vista optimizada con pantalla completa y controles grandes para televisores.
  • Soporte HLS: usa HLS.js como fallback cuando el navegador no soporta HLS nativo (todos excepto Safari).
  • Fallback automático: si un stream falla, el player intenta la siguiente URL disponible sin intervención del usuario.
  • SmartTV con HLS.js: el reproductor SmartTV incluye HLS.js desde CDN, permitiendo reproducción HLS en navegadores sin soporte nativo.
  • Tecla Escape: cierra el reproductor modal.

Modo SmartTV

FlaskCast incluye un reproductor optimizado para Smart TV que permite ver tanto vídeos del catálogo como streams en vivo.

Reproductor de vídeos (SmartTV)

http://localhost:5000/tv/reproducir/<nombre_serie>/<temporada>/<archivo.mp4>

Características:

  • Reproducción automática al cargar
  • Pantalla completa por defecto
  • Barra de información con título del vídeo
  • Botón para volver a la lista de streams

Reproductor de streams en vivo (SmartTV)

http://localhost:5000/live/tv/<indice>
  • Soporta vídeo directo, HLS (con HLS.js) e iframes
  • Fallback automático entre múltiples fuentes
  • Diseñado para ser controlado con el mando del televisor

Ajustes

Desde el panel de ajustes (/ajustes) puedes configurar:

  • Idioma: alterna entre español e inglés. La preferencia se guarda por usuario en la BD y se aplica a toda la interfaz y a los metadatos de OMDb.
  • Tema: alterna entre tema oscuro (por defecto) y tema claro. La preferencia se guarda por usuario en la BD.
  • Marcado automático: activa o desactiva el cambio automático de estado "Viendo"/"Visto" según el progreso de reproducción.
  • Mostrar progreso: activa o desactiva la barra de progreso en las cards de capítulos.
  • Habilitar API: activa o desactiva los endpoints REST. Al activarla, los endpoints requieren sesión de usuario. Un botón informativo (i) muestra la documentación completa de la API en un modal. Esta opción se gestiona desde el panel de administración (config_admin.py).

Autenticación

FlaskCast incluye un sistema de autenticación opcional que protege el acceso a toda la aplicación con una contraseña global.

Cómo activarla

  1. Abre el panel de administración (python config_admin.py).
  2. En la pestaña General, marca la casilla "Activar autenticación".
  3. Escribe la contraseña que quieras usar en el campo de al lado.
  4. Pulsa "Guardar y Cerrar".
  5. Reinicia FlaskCast para que los cambios surtan efecto.

Comportamiento

  • Activada: al acceder a cualquier página de la aplicación, se redirige a una pantalla de login donde debes introducir la contraseña.
  • Desactivada: la aplicación funciona exactamente como antes, sin ningún paso de autenticación.
  • En el sidebar aparece un enlace "Cerrar sesión" 🔒 solo cuando la autenticación está activa y has iniciado sesión.
  • La contraseña se guarda en texto plano en data/config.json. No se sube al repositorio (está en .gitignore).

Gestión desde CLI

También puedes gestionar la autenticación desde la línea de comandos:

# Activar/desactivar autenticación
python config_admin.py --auth

# Establecer la contraseña
python config_admin.py --auth-password "miclave123"

# Ver estado (incluye autenticación)
python config_admin.py --status

Multi-idioma (i18n)

FlaskCast soporta español e inglés en toda la interfaz:

  • Web: ~160 cadenas traducidas en translations.py (sección TRANSLATIONS). Cambio por usuario desde ajustes.
  • Panel de administración: ~140 cadenas traducidas (sección ADMIN_TRANSLATIONS). Cambio desde la pestaña "Language".
  • Géneros: 26 géneros traducidos localmente (inglés → español) en GENRE_TRANSLATIONS.
  • Descripciones: traducción automática en tiempo real vía API de MyMemory (gratuita, sin clave).
  • Fallback: si el idioma es inglés, los metadatos se muestran sin traducir; si falla la traducción, se muestra el texto original.

Rate Limiting (Protección contra abuso)

FlaskCast incluye rate limiting mediante Flask-Limiter para proteger la API y las rutas web contra floods de requests y abuso.

Límites configurados

Endpoint Límite Razón
General (todas las rutas) 200/min Protección base
POST /api/videos/add 10/min Evitar uploads masivos
POST /api/videos/rm 10/min Evitar eliminaciones masivas
POST /api/convertir/... 5/min Las conversiones son pesadas
POST /api/eliminar/... 10/min Evitar eliminaciones masivas
POST /api/progreso/guardar 60/min Se llama frecuentemente durante reproducción
POST /api/favoritos/toggle 30/min Operación moderada
POST /api/lista/guardar 30/min Operación moderada
POST /usuarios/crear 5/min Evitar creación masiva de usuarios
POST /usuarios/editar 10/min Moderado
POST /usuarios/eliminar 5/min Operación destructiva
GET /api/off 2/min Crítico
GET /api/off/all 1/min Crítico

Respuesta cuando se supera el límite

{
  "error": "Too Many Requests",
  "message": "You have exceeded the rate limit. Please slow down.",
  "retry_after": 42
}

Código de estado HTTP: 429 Too Many Requests


Panel de administración (config_admin.py)

FlaskCast incluye un panel de administración (config_admin.py) con interfaz gráfica (GUI) en tkinter y modo línea de comandos (CLI). Tiene 5 pestañas y soporte bilingüe (ES/EN).

Modo gráfico (GUI)

Se abre la ventana de administración sin pasar ningún argumento:

python config_admin.py

Pestaña General

  • Mostrar botón "Apagar Servidor": activa/desactiva la visibilidad del botón que apaga solo el proceso de Flask.
  • Mostrar botón "Apagar Todo": activa/desactiva la visibilidad del botón que apaga todo el sistema operativo.
  • Habilitar API REST: activa/desactiva los endpoints de la API REST.
  • Activar autenticación: activa/desactiva la protección con contraseña. Al activarla, aparece un campo para definir la contraseña de acceso.
  • Puerto: cambia el puerto en el que escucha el servidor (requiere reiniciar la aplicación).
  • Exportar data/ (.fkmedia): comprime toda la carpeta data/ en un archivo .fkmedia (formato 7z internamente): media/ (vídeos, miniaturas y metadatos), config.json, live_streams.json y flaskcast.db. La base de datos se copia con la API de backup de SQLite, por lo que el archivo es consistente aunque el servidor esté escribiendo. No se incluyen los archivos -wal/-shm.
    • Eliges tú la ruta con el diálogo "Guardar como" (nombre sugerido flaskcast-AAAA-MM-DD.fkmedia); al terminar te muestra la ruta exacta y el SHA-256.
    • Barra de progreso con porcentaje, velocidad, tiempo restante y Cancelar. Si cancelas, se borra el archivo parcial y data/ no se toca.
    • Modo de compresión: Rápido (copia sin recomprimir, muy veloz) o Compacto (LZMA2, bastante más pequeño pero más lento).
    • Exclusiones: nombres de carpeta/archivo separados por comas, admitiendo comodines * y ?. Un patrón que empieza por / se ancla a la raíz de data/. Por defecto se excluye .thumbnails.
    • Tamaño mínimo (MB): omite cualquier archivo por encima de ese tamaño, útil para respaldar ajustes y bases de datos sin los vídeos grandes.
    • Junto al .fkmedia se escribe un .sha256 para poder comprobar que el archivo no se ha corrompido.
  • Restaurar data/ (.fkmedia): extrae un .fkmedia sobre data/. Los archivos con el mismo nombre se sobreescriben y tu configuración actual se sustituye por la del archivo. Los .fkmedia antiguos (que solo contenían media/) siguen siendo compatibles.
    • Al elegir el archivo se muestra una vista previa con su formato, fecha y qué contiene.
    • Puedes restaurar todo, solo los datos (ajustes, streams y base de datos) o solo los vídeos, y Deshacer (rollback) devuelve el estado anterior.
    • Se descomprime primero en una carpeta temporal y solo se mueve sobre data/ cuando todo ha salido bien: si algo falla, data/ queda intacto. Necesitas espacio libre equivalente al tamaño sin comprimir.
    • Deshacer está marcado por defecto y copia tu estado actual (ajustes, streams y base de datos; no los vídeos, así que tarda segundos) a un .fkmedia junto al que vas a restaurar, por si necesitas volver atrás.
  • Ver contenido: muestra la fecha, el formato y el resumen de un .fkmedia sin extraerlo, y te dice si su .sha256 sigue siendo correcto.
  • Guardar y Cerrar: aplica los cambios y cierra la ventana.

Pestaña OMDb

  • Campo de entrada para la clave de API de OMDb con validación en tiempo real.
  • La clave se guarda automáticamente en el archivo .env al validar con éxito.
  • Árbol de biblioteca que muestra todas las carpetas multimedia con columnas: nombre, tipo (película/serie), tiene metadatos, tiene portada.
  • Botón "Aplicar OMDb" que busca y aplica metadatos automáticamente (título, descripción, año, género, director, valoración, duración/temporadas) y descarga la portada como _img.png.

💡 Esta funcionalidad también está disponible desde el navegador en la Biblioteca web.

Pestaña Biblioteca

  • Árbol jerárquico con toda la estructura multimedia (Series → Temporadas → Vídeos, Películas → Vídeos).
  • Muestra tamaños de archivo en MB.
  • Acciones disponibles:
    • Añadir película o serie (diálogo único con campos de metadata: título, descripción, año, género, director, valoración, tipo, duración, temporadas).
    • Añadir temporada.
    • Añadir vídeo (copia desde máquina local).
    • Editar metadata (actualiza _meta.json y tabla content_metadata de la BD).
    • Renombrar (cascada en BD: content_metadata, favoritos, progreso, listas).
    • Eliminar (con confirmación, limpia miniaturas y progreso).
  • Menú contextual (clic derecho) con opciones según el nivel del nodo seleccionado.

💡 Esta funcionalidad también está disponible desde el navegador: Biblioteca web (Gestionar Biblioteca en el sidebar, solo para cuentas registradas).

Pestaña Streamings

  • CRUD completo de streams en vivo almacenados en data/live_streams.json.
  • Árbol con columnas: título, URL principal, tipo.
  • Acciones: añadir, editar, eliminar, mover arriba/abajo (reordenar), actualizar.
  • Cada stream tiene: título, URL principal, URLs de backup (una por línea), tipo (hls/iframe/video).
  • Alternativa web: ⚙️ Gestionar Streams desde /live (ver Gestión web de streams), con tipos adicionales m3u y auto.

Pestaña Language (Idioma)

  • Botones de radio para Español (ES) y English (EN).
  • Al cambiar el idioma, toda la interfaz se reconstruye en el idioma seleccionado.
  • La preferencia se guarda en data/config.json (admin_idioma).

Nota para Linux

config_admin.py usa tkinter, que no siempre viene incluido por defecto en algunas distribuciones Linux. Si al ejecutarlo obtienes un error como ModuleNotFoundError: No module named 'tkinter', instálalo con:

sudo apt install python3-tk    # Debian / Ubuntu
sudo dnf install python3-tkinter  # Fedora
sudo pacman -S tk              # Arch Linux

Modo línea de comandos (CLI)

Útil para servidores sin interfaz gráfica (headless). Permite modificar la configuración y gestionar archivos multimedia directamente desde la terminal.

python config_admin.py [OPCIONES]
Bandera Descripción
--status Muestra la configuración actual del servidor (incluye estado de la clave OMDb)
--toggle-server Activa/desactiva el botón "Apagar Servidor"
--toggle-all Activa/desactiva el botón "Apagar Todo"
--api Activa/desactiva la API REST
--auth Activa/desactiva la autenticación
--auth-password CONTRASEÑA Establece la contraseña de autenticación
--port PUERTO Cambia el puerto del servidor (1-65535)
--omdb-key API_KEY Guarda una clave de API de OMDb en el archivo .env
--export ARCHIVO Exporta toda la carpeta data/ a un archivo .fkmedia
--import ARCHIVO Restaura toda la carpeta data/ desde un archivo .fkmedia
--compresion MODO rapido (copia directa, muy veloz) o compactado (LZMA2). Se guarda como predeterminado
--exclude PATRÓN Excluye carpeta/archivo; admite * y ?, y /ruta para anclar a la raíz de data/. Repetible
--exclude-mb MB Omite archivos mayores de ese tamaño (0 = sin límite)
--alcance PARTE Al restaurar: todo, datos o media
--rollback Antes de restaurar, guarda tu estado actual (ajustes, streams y base de datos) en un .fkmedia junto al archivo, para poder deshacer
--solo-datos Al exportar, guarda solo ajustes, streams y base de datos (sin vídeos): una copia de seguridad rápida
--list ARCHIVO Muestra qué contiene un .fkmedia sin extraerlo
--verificar ARCHIVO Comprueba el archivo y su .sha256 para detectar corrupción

Se pueden combinar varias banderas en una sola ejecución:

python config_admin.py --api --toggle-all --port 8080

Ejemplos prácticos:

# Ver configuración actual
python config_admin.py --status

# Activar la API REST
python config_admin.py --api

# Activar autenticación con contraseña
python config_admin.py --auth --auth-password "miclave123"

# Cambiar puerto a 8080
python config_admin.py --port 8080

# Guardar clave de OMDb
python config_admin.py --omdb-key tu_clave_aqui

# Exportar todo el contenido multimedia
python config_admin.py --export backup.fkmedia

# Exportar más compacto (más lento, archivo más pequeño)
python config_admin.py --export backup.fkmedia --compresion compactado

# Copia de seguridad rápida: solo ajustes, streams y base de datos
python config_admin.py --export ajustes.fkmedia --solo-datos

# Dejar fuera miniaturas y cualquier .nfo
python config_admin.py --export backup.fkmedia --exclude .thumbnails --exclude "*.nfo"

# Ver qué contiene un backup y comprobar que no se ha corrompido
python config_admin.py --list backup.fkmedia
python config_admin.py --verificar backup.fkmedia

# Importar contenido desde un backup
python config_admin.py --import backup.fkmedia

# Restaurar solo la base de datos y los ajustes, dejando los vídeos
python config_admin.py --import backup.fkmedia --alcance datos

# Restaurar guardando antes tu estado actual para poder deshacer
python config_admin.py --import backup.fkmedia --rollback

Biblioteca web (gestión desde el navegador)

Además del panel de escritorio, FlaskCast incluye una gestión completa de contenido desde el navegador. Se accede desde el sidebar con el enlace 🗂️ Gestionar Biblioteca, situado justo antes de "Cerrar sesión" (ruta GET /biblioteca). No depende del toggle de la API REST, por lo que funciona siempre que se tenga acceso a la web. Solo está disponible para cuentas registradas: el enlace no aparece para invitados y la ruta redirige a / si no hay sesión (lo mismo aplica a todos los endpoints /biblioteca/... y /live/streams/..., protegidos con requiere_cuenta).

Árbol de contenido

  • Muestra toda la estructura multimedia (Series → Temporadas → Vídeos, Películas → Vídeos) con el tamaño de cada vídeo en MB.
  • Todo aparece colapsado por defecto; un clic en una serie o temporada la expande/oculta y la selecciona.
  • Las acciones de la barra superior se habilitan según el elemento seleccionado.

Acciones disponibles

Botón Requiere Función
+Añadir Película/Serie — Crea la carpeta + _meta.json; para series genera automáticamente Season N según el número de temporadas indicado
+Añadir Temporada Serie seleccionada Crea la subcarpeta de temporada (sugiere Season N automáticamente)
+Añadir Vídeo Película, serie sin temporadas o temporada Sube uno o varios vídeos (.mp4, .webm, .ogg, .avi, .mkv) al destino correcto
Editar Metadata Película/Serie seleccionada Actualiza _meta.json y la tabla content_metadata
Renombrar Cualquier nodo Renombra serie (cascada en favoritos/progreso/listas), temporada o vídeo
Eliminar Cualquier nodo Borra con confirmación la serie completa, una temporada o un vídeo (limpia miniaturas y progreso)
OMDb Película/Serie seleccionada Abre el modal de integración con OMDb
Refrescar — Recarga el árbol desde disco

Integración OMDb desde la web

El botón OMDb abre un modal que replica la pestaña OMDb del panel de administración:

  • Campo de API key que, si ya existe una clave guardada en el archivo .env, aparece precargada (junto con el indicador "✓ API key válida (guardada)").
  • Botón Validar que comprueba la clave contra la API de OMDb y la guarda en .env.
  • Enlace "Obtener API Key" con acceso a la página de registro de OMDb.
  • Checkbox "Descargar portada" (activado por defecto) que descarga el póster como _img.png.
  • Botón "Aplicar OMDb": busca el contenido seleccionado por el nombre de su carpeta, elige la mejor coincidencia y rellena automáticamente título, descripción, año, género, director, valoración y duración/temporadas.

Endpoints de la gestión web

Método Ruta Descripción Rate Limit
GET /biblioteca Página de gestión con el árbol de contenido —
POST /biblioteca/crear Crear película/serie con metadata 5/min
POST /biblioteca/temporada Crear temporada en una serie 5/min
POST /biblioteca/videos/add Subir uno o varios vídeos (multipart) 10/min
POST /biblioteca/meta Guardar/actualizar metadata 10/min
POST /biblioteca/renombrar Renombrar serie, temporada o vídeo 10/min
POST /biblioteca/eliminar Eliminar serie, temporada o vídeo 5/min
GET /biblioteca/omdb/estado Muestra si hay clave OMDb guardada y su valor —
POST /biblioteca/omdb/validar Valida y guarda la API key de OMDb 5/min
POST /biblioteca/omdb/aplicar Aplica metadatos OMDb al contenido seleccionado 2/min

API REST

FlaskCast incluye una API REST protegida por sesión de usuario y activada desde el panel de administración. Todos los endpoints requieren el encabezado de cookie de sesión y que el usuario tenga la API habilitada. Todos los endpoints están protegidos con rate limiting.

📤 Agregar Video

POST /api/videos/add
Content-Type: multipart/form-data
Parámetro Tipo Descripción
serie string (obligatorio) Nombre de la serie
temporada string Obligatorio si la serie tiene subcarpetas. No usar si no las tiene.
archivo file (obligatorio) Archivo de vídeo a subir
curl -X POST http://localhost:5000/api/videos/add \
  -b "session=TU_SESSION" \
  -F "serie=Mi Serie" \
  -F "temporada=Temporada 1" \
  -F "archivo=@/ruta/al/video.mp4"

📋 Listar Estructura

GET /api/videos             → Todas las series y sus capítulos
GET /api/videos/Mi%20Serie  → Una serie específica
curl http://localhost:5000/api/videos -b "session=TU_SESSION"

🎬 Obtener Video

GET /api/video/<serie>/<ruta/al/archivo.mp4>
curl http://localhost:5000/api/video/Mi%20Serie/Temporada%201/cap1.mp4 \
  -b "session=TU_SESSION" -o cap1.mp4

🗑️ Eliminar Video (API)

POST /api/videos/rm
Content-Type: application/json
Parámetro Tipo Descripción
serie string (obligatorio) Nombre de la serie
filename string (obligatorio) Ruta del archivo dentro de la serie
curl -X POST http://localhost:5000/api/videos/rm \
  -b "session=TU_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"serie": "Mi Serie", "filename": "Temporada 1/video.mp4"}'

🔄 Convertir Vídeo (API)

Inicia la conversión de un vídeo incompatible (.avi, .mkv) a .mp4 en segundo plano.

POST /api/convertir/<serie>/<ruta/archivo.avi>

Respuesta:

{"status": "procesando"}

Si ya existe un archivo .mp4 con el mismo nombre:

{"status": "ya_existe_mp4"}

Si ya hay una conversión en curso:

{"status": "ya_en_progreso"}
curl -X POST http://localhost:5000/api/convertir/Mi%20Serie/Temporada%201/cap1.avi \
  -b "session=TU_SESSION"

🗑️ Eliminar Archivo Directo (API)

Elimina un archivo específico sin necesidad de usar el endpoint de "videos/rm".

POST /api/eliminar/<serie>/<ruta/archivo.mp4>
curl -X POST http://localhost:5000/api/eliminar/Mi%20Serie/Temporada%201/cap1.mp4 \
  -b "session=TU_SESSION"

📊 Consultar Conversiones Activas (API)

Devuelve la lista de identificadores de vídeos que se están convirtiendo actualmente, junto con el porcentaje de progreso de cada una.

GET /api/estados

Respuesta:

{"activos": ["Mi Serie/Temporada 1/cap1.avi"], "progreso": {"Mi Serie/Temporada 1/cap1.avi": 42}}
curl http://localhost:5000/api/estados -b "session=TU_SESSION"

🔍 Consultar Resultado de Conversión (API)

Devuelve el resultado de una conversión completada (éxito o fallo).

GET /api/conversion_result/<serie>/<archivo>

Respuesta:

{"status": "ok", "mp4_exists": true}
curl http://localhost:5000/api/conversion_result/Mi%20Serie/Temporada%201/cap1.avi \
  -b "session=TU_SESSION"

💾 Guardar Progreso de Reproducción (API)

Guarda la posición de reproducción de un vídeo para el usuario actual.

POST /api/progreso/guardar
Content-Type: application/json
Parámetro Tipo Descripción
serie string (obligatorio) Nombre de la serie
filename string (obligatorio) Ruta del archivo (ej: Temporada 1/cap1.mp4)
segundos number Posición actual en segundos
duracion number Duración total del vídeo
visto number Estado forzado (0=Sin ver, 1=Viendo, 2=Visto) — opcional

Nota: Si se envía el campo visto, se ignora el cálculo automático y se fuerza ese estado.

curl -X POST http://localhost:5000/api/progreso/guardar \
  -b "session=TU_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"serie": "Mi Serie", "filename": "Temporada 1/cap1.mp4", "segundos": 1250, "duracion": 3600}'

📥 Obtener Progreso de Reproducción (API)

Obtiene la posición guardada y el estado de un vídeo para el usuario actual.

GET /api/progreso/obtener?serie=<serie>&filename=<archivo>

Respuesta:

{"segundos": 1250, "visto": 1}
curl "http://localhost:5000/api/progreso/obtener?serie=Mi%20Serie&filename=Temporada%201/cap1.mp4" \
  -b "session=TU_SESSION"

⭐ Toggle Favoritos (API)

Añade o elimina una serie/película de la lista de favoritos.

POST /api/favoritos/toggle
Content-Type: application/json
Parámetro Tipo Descripción
serie string (obligatorio) Nombre de la serie/película

Respuesta:

{"favorito": true}

📋 Guardar Estado de Lista (API)

Guarda el estado de una serie en la lista del usuario.

POST /api/lista/guardar
Content-Type: application/json
Parámetro Tipo Descripción
serie string (obligatorio) Nombre de la serie
estado integer 0=Pendiente, 1=Viendo, 2=Visto

📥 Obtener Estado de Lista (API)

GET /api/lista/estado?serie=<serie>

📥 Obtener Todas las Listas (API)

GET /api/lista/obtener

🖥️ Abrir Panel de Administración (API)

Abre la ventana de config_admin.py (solo accesible desde localhost).

GET /api/abrir_config_admin

🏓 Ping (API)

Verifica que el servidor está activo.

GET /api/ping

Respuesta:

{"status": "servidor en linea"}
curl http://localhost:5000/api/ping

⏻ Apagar Servidor (API)

Detiene únicamente el proceso de FlaskCast. Solo funciona si está habilitado en config_admin.py.

GET /api/off

Respuesta:

{"status": "Apagando servidor..."}

⏻ Apagar Sistema (API)

Apaga todo el sistema operativo. Solo funciona si está habilitado en config_admin.py.

GET /api/off/all

Respuesta:

{"status": "Apagando sistema..."}

Endpoints de Servicio Multimedia

Estos endpoints sirven el contenido audiovisual directamente desde el navegador. No requieren autenticación.

Endpoint Descripción
GET /video/<serie>/<archivo> Sirve un archivo de vídeo para reproducción en el navegador
GET /thumbnail/<serie>/<archivo> Sirve o genera automáticamente una miniatura del vídeo (fotograma a los 3 segundos)
GET /portada/<serie> Sirve la imagen de portada _img.png de una serie
GET /serie/<nombre_serie> Página web con el catálogo de capítulos de una serie
GET /tv/reproducir/<serie>/<archivo> Reproductor optimizado para SmartTV

Ejemplos

http://localhost:5000/video/Mi%20Serie/Temporada%201/cap1.mp4
http://localhost:5000/thumbnail/Mi%20Serie/Temporada%201/cap1.mp4
http://localhost:5000/portada/Mi%20Serie
http://localhost:5000/serie/Mi%20Serie
http://localhost:5000/tv/reproducir/Mi%20Serie/Temporada%201/cap1.mp4

Generación automática de miniaturas

Cuando se solicita una miniatura que no existe, FlaskCast genera automáticamente un fotograma extraído a los 3 segundos del vídeo usando FFmpeg. Las miniaturas se almacenan en:

data/media/<Serie>/.thumbnails/<nombre_archivo>.jpg

Reproductor y Auto-reproducción

El reproductor de FlaskCast incluye funciones avanzadas de seguimiento y auto-reproducción.

Seguimiento automático

  • Cada 10 segundos, el reproductor envía la posición actual al servidor.
  • Si el usuario tiene activada la opción "Marcado automático" en Ajustes:
    • >10% reproducido → Estado cambia a "Viendo" (badge azul)
    • >85% reproducido → Estado cambia a "Visto" (badge verde)
  • Si se desactiva el marcado automático, los estados solo cambian al hacer clic manualmente sobre la etiqueta del capítulo.

Auto-reproducción del siguiente capítulo

Al finalizar un vídeo, el reproductor carga automáticamente el siguiente capítulo de la misma temporada (si existe). Esta función:

  • Solo aplica a vídeos en formatos web (.mp4, .webm, .ogg)
  • No avanza si es el último capítulo de la temporada
  • Muestra un botón "Siguiente" al finalizar

Formatos soportados en el reproductor

Formato Soporte nativo Conversión necesaria
.mp4 (H.264) ✅ Sí No
.webm ✅ Sí No
.ogg ✅ Sí No
.avi ❌ No Sí (a .mp4)
.mkv ❌ No Sí (a .mp4)

Resumen de Endpoints

Rutas web (requieren navegador)

Método Ruta Descripción
GET / Catálogo principal con paginación, filtros y continuar viendo
GET /page/<n> Catálogo paginado
GET /serie/<nombre> Detalle de una serie/película con hero banner y capítulos
GET /listas Listas personales (Favoritos, Pendiente, Viendo, Visto)
GET /tv/reproducir/<serie>/<archivo> Reproductor SmartTV
GET /live Lista de streams en vivo
GET /live/tv/<indice> Reproductor SmartTV para streams en vivo
GET /live/gestion Gestión web de streams (ver Gestión web de streams)
POST /live/streams/crear Añadir stream (ver Gestión web de streams)
POST /live/streams/editar Editar stream (ver Gestión web de streams)
POST /live/streams/eliminar Eliminar stream (ver Gestión web de streams)
POST /live/streams/mover Reordenar stream (ver Gestión web de streams)
GET /usuarios_panel Panel de gestión de usuarios
GET /ajustes Panel de configuración (tema, idioma, marcado automático)
GET/POST /ajustes Guardar ajustes del usuario
GET/POST /login Pantalla de autenticación (solo si auth habilitada)
GET /logout Cerrar sesión de autenticación
GET /biblioteca Gestión web de la biblioteca (Ver Biblioteca web)

API REST (requieren sesión + API habilitada)

Método Ruta Descripción Rate Limit
POST /api/videos/add Subir vídeo a una serie 10/min
POST /api/videos/rm Eliminar vídeo por nombre 10/min
GET /api/videos Listar todas las series 200/min
GET /api/videos/<serie> Obtener estructura de una serie 200/min
GET /api/video/<serie>/<archivo> Descargar/archivo de vídeo 200/min
POST /api/convertir/<serie>/<archivo> Convertir vídeo incompatible a MP4 5/min
POST /api/eliminar/<serie>/<archivo> Eliminar archivo directo 10/min
GET /api/estados Consultar conversiones activas con progreso 200/min
GET /api/conversion_result/<serie>/<archivo> Consultar resultado de conversión 200/min
POST /api/progreso/guardar Guardar posición de reproducción 60/min
GET /api/progreso/obtener Obtener posición guardada 200/min
POST /api/favoritos/toggle Añadir/quitar de favoritos 30/min
GET /api/favoritos Obtener lista de favoritos 200/min
GET /api/lista/estado Obtener estado de lista de una serie 200/min
POST /api/lista/guardar Guardar estado en lista (Pendiente/Viendo/Visto) 30/min
GET /api/lista/obtener Obtener todas las listas del usuario 200/min
GET /api/abrir_config_admin Abrir panel de administración (solo localhost; dentro del ejecutable) 200/min
GET /api/ping Verificar estado del servidor 200/min
GET /api/off Apagar servidor (si habilitado) 2/min
GET /api/off/all Apagar sistema (si habilitado) 1/min

Endpoints de contenido

Método Ruta Descripción
GET /video/<serie>/<archivo> Servir archivo de vídeo
GET /thumbnail/<serie>/<archivo> Servir/generar miniatura
GET /portada/<serie> Servir portada de serie/película

Comandos útiles

  • Ejecutar localmente: python app.py
  • Entorno virtual (Windows): venv\Scripts\activate
  • Docker: docker-compose up --build
  • Ver config del admin: python config_admin.py --status
  • Guardar clave OMDb: python config_admin.py --omdb-key tu_clave

Changelog

v2.1 — Corrección de transcodificación y mejoras (2026-08-21)

Correcciones críticas:

  • Corregido: transacción fallaba en Linux — El codificador libx264 estaba hardcodeado pero no disponible en distribuciones Linux (Fedora/RHEL). Ahora la app detecta automáticamente el mejor codificador H.264 disponible al iniciar: libx264 → libopenh264 → h264_nvenc → h264_amf → h264_qsv → h264_vaapi → h264_v4l2m2m.
  • Corregido: Ctrl+C abortaba conversiones — FFmpeg se ejecutaba como hijo directo del proceso Python y recibía SIGINT al pulsar Ctrl+C (returncode=255). Ahora se usa start_new_session=True para aislar FFmpeg en una nueva sesión de procesos.
  • Corregido: estado inconsistente entre workers de Gunicorn — Con --workers 4, cada worker tenía su propio conversiones_activas en memoria. El frontend recibía "desconocido" al consultar un worker que no tenía la conversión. Solución: --workers 1 --threads 6 para compartir el estado.
  • Corregido: verificación de éxito de conversión — Antes se asumía que si el identificador desaparecía de conversiones_activas, la conversión había tenido éxito. Ahora se verifica returncode == 0, os.path.exists(mp4) y getsize > 0.

Nuevas funcionalidades:

  • Barra de progreso en tiempo real — Durante la conversión se muestra una barra de progreso con porcentaje en la tarjeta del capítulo, parseando la salida time=HH:MM:SS de FFmpeg.
  • Ocultación de .mp4 durante conversión — Los archivos .mp4 generados no aparecen en la interfaz hasta que la conversión alcanza el 100%.
  • Endpoint /api/conversion_result — Nuevo endpoint para consultar el resultado de una conversión completada (éxito/fallo + existencia del .mp4).
  • Logging detallado — Cada paso de la conversión se registra en la consola: inicio, PID de FFmpeg, progreso cada 10%, resultado final con tamaño del archivo, y errores con las últimas líneas de stderr.

Cambios técnicos:

  • hilo_conversion() reescrito con subprocess.Popen() en vez de subprocess.run()
  • resultados_conversiones dict almacena éxito/fallo por identificador
  • progreso_conversiones dict almacena el porcentaje actual por conversión
  • GET /api/estados ahora devuelve {"activos": [...], "progreso": {...}}
  • Frontend (verificarEstados()) bifurca entre éxito y fallo al consultar el resultado
  • Funciones auxiliares _obtener_duracion() (ffprobe) y _parsear_progreso_ffmpeg()
  • CSS: .conversion-progress, .conversion-progress-bar, .conversion-progress-text
  • Plantilla serie.html: barra de progreso añadida a tarjetas incompatibles

Contribuir y soporte

Si quieres contribuir, abre un issue o crea un pull request. Para cambios mayores, escribe primero un issue describiendo la propuesta.


Licencia

Revisa el archivo LICENSE incluido en el repositorio.

About

This web application provides a site to display and view video files from any device connected to the local network.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages