🌐 Español · English
Plugin para Jellyfin que reemplaza SQLite por PostgreSQL como motor de base de datos, sin modificar el núcleo de Jellyfin. Migración bidireccional, búsqueda casi instantánea, health check automático, mantenimiento programado e integración opcional con JellyTrend.
v3 / Jellyfin 12.1: requiere .NET 10 y PostgreSQL 16+. Consulta la guía de actualización y pruebas antes de sustituir el proveedor.
¿Vienes de Jellyfin 10.11.x con PostgreSQL? Sigue el manual de migración 10.11.x → 12.x: necesitas el plugin 2.0.1 para exportar PostgreSQL a SQLite antes de actualizar el servidor y el plugin 3.0.0 para importar de vuelta a PostgreSQL.
| Documento | Contenido |
|---|---|
| Migración 10.11.x → 12.x · EN | Manual paso a paso, con diagrama y plan de contingencia |
| Novedades de 3.0.0 · EN | Qué cambia en 3.0.0 frente a 2.0.1 |
| Adaptación a Jellyfin 12.1 | Notas técnicas y cómo ejecutar la suite de pruebas |
| Verificación automatizada | Resumen ejecutivo generado desde la suite real |
| Integración para desarrolladores · EN | Contrato público, esquemas privados, migraciones y mantenimiento administrado |
- 🐘 PostgreSQL como backend nativo — EF Core + Npgsql, sin tocar el core de Jellyfin.
- 🔍 Búsqueda casi instantánea (< 15 ms típico) con índice GIN trigram (
pg_trgm); fallback automático aILIKE. - 🔄 Migración bidireccional — SQLite → PostgreSQL y PostgreSQL → SQLite sin herramientas externas.
- 🩺 Health Check automático al arrancar: diagnostica bloat, índices inválidos, secuencias desfasadas y queries lentas.
- 🛡️ Prevención de errores — interceptores EF Core para upserts, logging de errores DB y normalización de
DateTime.Kind. - 🔧 Optimización automática — índices GIN CONCURRENTLY, tuning de autovacuum en tablas críticas.
- 💾 Backups programados con
pg_dump, compresión ZIP opcional y restore desde la UI. - 🔐 Host de esquemas privados — contrato reutilizable para que otros plugins persistan únicamente sus propios datos, sin credenciales ni acceso al esquema
publicde Jellyfin. - 📊 Estadísticas de BD — tamaño, conexiones activas y análisis tabla por tabla desde la UI.
- 🧪 Consola SQL de solo lectura — lanza consultas de diagnóstico desde el panel con 10 plantillas e historial; rechaza cualquier sentencia que modifique datos.
- 🔁 Rollback a SQLite en un clic desde la configuración.
PG Provider puede servir como almacén PostgreSQL privado para otros plugins, sin darles acceso a credenciales ni al esquema public de Jellyfin. Desde Integraciones, el administrador consulta las integraciones registradas, sus tablas y señales de mantenimiento, y decide qué esquemas participan en las tareas programadas.
Consulta la guía de integración para desarrolladores para usar el contrato público, diseñar migraciones y conocer sus límites de seguridad.
| Componente | Versión |
|---|---|
| Jellyfin | 12.1.x — para Jellyfin 10.11.x usa el plugin 2.0.1 |
| PostgreSQL | 16 + (recomendado 17) |
| .NET | 10.0 |
ℹ️ El plugin implementa
IJellyfinDatabaseProvider, el mismo contrato que usa el proveedor SQLite incluido en Jellyfin 12.1. No requiere modificar el núcleo de Jellyfin.
-
En Jellyfin entra en Panel → Avanzado → Repositorios de complementos.
-
Pulsa Añadir repositorio y usa esta URL:
https://raw.githubusercontent.com/BORNIOS/Jellyfin-Database-Providers-Postgres/main/manifest.json -
Guarda, ve al Catálogo, busca PostgreSQL Database Provider e Instala.
-
Acepta el reinicio cuando te lo pida.
- Descarga el ZIP del Release.
- Descomprímelo en la carpeta de plugins de Jellyfin.
- Reinicia Jellyfin.
💡 Ubicaciones habituales de la carpeta de plugins:
- Linux / Docker:
/config/plugins/- Windows:
%LOCALAPPDATA%\jellyfin\plugins\
El plugin añade una página propia en Panel → Complementos → PostgreSQL Database Provider con seis pestañas, en este orden: Configuración, Migración, Mantenimiento, Health, Consola SQL e 🧩 Integraciones. La barra se adapta a pantallas pequeñas y conserva el nombre de cada sección como ayuda contextual.
Es el punto de entrada: define a qué PostgreSQL te conectas, con qué parámetros de pool y qué motor usa Jellyfin ahora mismo (SQLite o PostgreSQL).
Estado actual — resumen en vivo de lo que el plugin está usando de verdad: motor activo,
archivo SQLite detectado, esquema y una línea con Pool: min-max · Timeout · Prepared statements.
Conexión PostgreSQL
| Parámetro | Descripción | Default |
|---|---|---|
| Connection string | Cadena completa de Npgsql | — |
| Schema | Schema PostgreSQL a usar | public |
| PgBin path | Ruta a pg_dump / psql / pg_restore |
auto-detect |
| Backup directory | Carpeta donde se guardan los backups | <DataPath>/postgres-backups |
| Backup compression | Comprimir el backup en ZIP | true |
Opciones avanzadas
| Parámetro | Descripción | Default |
|---|---|---|
| Min pool size | Conexiones mínimas que mantiene abiertas Npgsql | 4 |
| Max pool size | Conexiones máximas del pool | 100 |
| Max auto-prepare | Sentencias preparadas en el servidor (0 = desactivado) | 50 |
| Command timeout | Tiempo máximo de una query EF Core (segundos) | 600 |
ℹ️ Si tu cadena de conexión ya incluye una de estas claves, ese valor manda y la configuración solo rellena lo que falte. Los cambios de pool requieren reiniciar Jellyfin para aplicarse.
Acciones
| Botón | Función |
|---|---|
| Probar conexion | Valida la cadena y devuelve la versión del servidor PostgreSQL |
| Guardar configuracion | Persiste conexión, opciones avanzadas y rutas (rechaza max < min) |
| Activar PostgreSQL y reiniciar | Solo aparece cuando Jellyfin usa SQLite; valida la conexión antes de escribir config/database.xml en modo PLUGIN_PROVIDER y reinicia el servidor |
| Revertir a SQLite y reiniciar | Solo aparece cuando PostgreSQL está activo; valida que exista una base SQLite utilizable, elimina config/database.xml y reinicia |
Flujo recomendado: 1) Probar conexión → 2) ajustar pool y timeout → 3) Guardar configuración → 4) migrar los datos → 5) Activar PostgreSQL.
Dos operaciones disponibles con progreso en vivo:
Copia jellyfin.db a PostgreSQL tabla por tabla.
- La ruta de
jellyfin.dbse autodetecta ({DataPath}/jellyfin.db). - Ajusta el batch size (default 1000).
- Activa Truncar tablas antes de insertar si repites la migración sobre datos existentes.
- Pulsa Iniciar migración y sigue el progreso.
- Al llegar al 100 %, activa PostgreSQL desde la pestaña Configuración.
⚠️ La opción--truncatehaceTRUNCATE + RESTART IDENTITY + CASCADEen el destino. Úsala en reintentos para evitar duplicados; es destructiva con datos existentes.
Exporta toda la base directamente a un archivo .db nativo sin herramientas externas.
- Si el
.dbno existe → lo crea con el schema derivado de PostgreSQL. - Si el
.dbya existe → preserva las tablas y reemplaza solo el contenido (DELETE+INSERT). - Escritura en transacciones de 10 000 filas con
PRAGMA journal_mode=WAL. - Cuando Jellyfin 12.1 requiere el archivo heredado
library.db, se crea mediante SQLite y se valida conPRAGMA integrity_check; el export falla de forma explícita en vez de dejar un archivo inválido.
Casos de uso: revertir a SQLite, copia portable de seguridad, inspección local.
Operaciones de mantenimiento, backups y estadísticas de la base de datos.
| Acción | Función |
|---|---|
| VACUUM ANALYZE | Mantiene las tablas public de Jellyfin; los esquemas privados solo participan si el administrador los habilita en Integraciones |
| REINDEX DATABASE | Reconstruye índices de public; los esquemas privados requieren habilitación explícita en Integraciones |
| Aplicar optimizaciones | Crea 9 índices GIN CONCURRENTLY y ajusta autovacuum en las tablas críticas |
| Crear backup ahora | Genera un .sql con pg_dump (y .zip si la compresión está activa) |
| Restablecer backup | Restaura desde .sql o .zip, con selector de backups disponibles |
| Actualizar estadisticas | Tamaño total, conexiones activas y métricas tabla por tabla |
💡 Aplicar optimizaciones activa también la búsqueda casi instantánea cuando
pg_trgmestá disponible, y es el paso que crea los índices GIN que usa el endpoint de búsqueda.
Comprueba la salud de la base 10 segundos después del arranque y permite relanzar el chequeo a mano desde la propia pestaña.
| Check | Qué comprueba |
|---|---|
| Conexión | Que PostgreSQL responde, y con qué latencia |
| Extensiones | Que pg_trgm y pg_stat_statements están disponibles |
| Índices inválidos | Índices en estado invalid, con reparación en un clic |
| Bloat de tablas | Tablas con más de 20 % de tuplas muertas |
| Secuencias desfasadas | Secuencias fuera de rango respecto a los datos |
| Estadísticas obsoletas | Tablas sin ANALYZE reciente |
| Queries lentas | Top consultas por tiempo acumulado (vía pg_stat_statements) |
| Presión de buffers | Porcentaje de aciertos en caché compartida, bloques leídos de disco, uso temporal y WAL de las consultas lentas |
Cada resultado lleva semáforo Info / Warn / Error, y los problemas marcados como reparables se
corrigen desde la misma card. El resumen del arranque queda además en el log del plugin:
[HealthCheck] Resumen arranque: 0 error(es), 0 advertencia(s), 65 informativo(s) | Severidad: Ok
Herramienta de diagnóstico para lanzar SELECT contra la base del plugin sin salir del panel ni
abrir una sesión psql.
- Solo lectura por diseño: rechaza
INSERT/UPDATE/DELETE/ DDL y también varias sentencias enviadas a la vez. - 10 plantillas listas para usar: consultas lentas, tamaño por tabla, índices sin uso, conexiones activas, bloat, bloqueos, y más.
- Las plantillas filtran por base de datos y excluyen sentencias administrativas, así que no arrastran ruido de otras bases del mismo servidor PostgreSQL.
- Historial de las últimas consultas conservado en la sesión del navegador, con botón para limpiarlo.
Permite revisar únicamente los esquemas registrados mediante el contrato público del proveedor, sin
exponer credenciales, public ni datos de otra integración. Elige una integración y después una
tabla para consultar una muestra limitada y ordenable de sus datos.
- La tabla de estado muestra filas estimadas, tamaño, índices, tuplas muertas y cambios.
- ANALYZE programado está activo inicialmente;
VACUUM (ANALYZE)yREINDEXprogramados solo se ejecutan cuando el administrador los selecciona para ese esquema. - El backup completo incluye todos los esquemas privados registrados; las acciones manuales quedan limitadas al esquema o tabla elegidos.
Consulta la guía de integración para desarrolladores para el contrato, el aislamiento y la estrategia de migraciones.
Cuando los índices GIN están activos, el plugin expone un endpoint propio que evita EF Core:
- Latencia típica < 15 ms en bibliotecas medianas y grandes (depende del hardware y del cliente).
- Búsqueda por nombre, path y tipo de ítem.
- Fallback automático a
ILIKEsi los índices GIN aún no existen. - Se activa en Mantenimiento → Aplicar optimizaciones.
- Configura y prueba la conexión en la pestaña Configuración.
- Migra los datos (Migración → SQLite → PostgreSQL).
- Pulsa Activar PostgreSQL y confirma el reinicio.
Resultado: database.xml se escribe en modo PLUGIN_PROVIDER apuntando a este plugin.
- En Configuración pulsa Desactivar / Volver a SQLite.
- El plugin elimina
database.xml. - Reinicia Jellyfin.
Cuándo hacer rollback: caída de conectividad a PostgreSQL, mantenimiento urgente o migración incompleta.
En Configuración:
- PgBin path — ruta a
pg_dump/psql/pg_restore. Déjalo vacío para usar el PATH del sistema. - Backup directory — carpeta destino de los archivos.
- Backup compression — activa ZIP del
.sql.
En Mantenimiento: Crear backup ahora / Restablecer backup (acepta .sql o .zip).
| Tarea | Default | Descripción |
|---|---|---|
| PostgreSQL Backup | Diario 02:00 | Backup con pg_dump |
| PostgreSQL VACUUM ANALYZE (managed schemas) | Domingo 03:00 | Mantiene public y solo los esquemas privados autorizados en Integraciones |
| PostgreSQL REINDEX (managed schemas) | Domingo 04:00 | Reconstruye índices de public y únicamente los esquemas privados autorizados |
| Optimize GIN Indexes | Domingo 05:00 | Mantiene los índices GIN trigram frescos |
⚠️ Evita solapar REINDEX, VACUUM y Backup en la misma ventana horaria.
- Login correcto con los usuarios existentes.
- Progreso de reproducción actualizando correctamente.
- Conteos clave validados (UserData, Users, BaseItems).
- Sin errores de conexión PostgreSQL en logs de Jellyfin.
- Health Check ejecutado sin errores (
Warnaceptable,Errorrequiere acción). - Backup manual probado al menos una vez.
- Índices GIN aplicados (Mantenimiento → Aplicar optimizaciones).
Instalé el plugin pero no migró datos automáticamente.
Es el comportamiento esperado. Ejecuta la migración desde Migración → SQLite → PostgreSQL y luego activa PostgreSQL desde Configuración.
La migración falla o da resultados raros en reintentos.
Activa Truncar tablas antes de insertar para reiniciar las tablas destino antes de insertar. Es destructivo sobre datos existentes en PostgreSQL, pero garantiza un resultado limpio.
¿Puedo editar database.xml manualmente?
Sí, pero se recomienda usar la UI del plugin para evitar errores de formato.
¿Qué pasa si exporto a SQLite y el .db ya existe?
El plugin preserva la estructura de tablas y reemplaza solo los datos (DELETE + INSERT). El archivo no se elimina ni recrea.
¿Uso Docker; por qué falla un backup o la copia de migración con pg_dump?
pg_dump, psql y pg_restore se ejecutan dentro del contenedor de Jellyfin. Instala un cliente
PostgreSQL compatible —se recomienda PostgreSQL 17— en tu imagen derivada de Jellyfin y configura su
directorio de binarios en PgBin path. Instalarlo solo en el host Docker no lo hace disponible para
el plugin dentro del contenedor.
¿La búsqueda rápida requiere cambios en el cliente Jellyfin?
No. Es un endpoint de servidor. La UI del plugin lo usa internamente cuando PostgreSQL está activo y los índices GIN existen.
¿Por qué los timestamps muestran UTC en lugar de mi zona horaria o una fecha mínima?
Las versiones anteriores usaban el switch global Npgsql.EnableLegacyTimestampBehavior, que forzaba UTC en todas las lecturas. El interceptor actual normaliza parámetros de escritura sin zona horaria sin alterar las lecturas y convierte DateTime.MinValue a un valor UTC seguro para clientes antes de que Npgsql lo represente como -infinity.
¿Dudas, sugerencias o encontraste un bug? Abre un issue o únete a la comunidad oficial de Jellyfin:
Hecho con ❤️ para la comunidad Jellyfin · ⭐ Star en GitHub






