3e5d29225a
- Removed unused classes and files related to SQLite database provider, including SqliteDesignTimeJellyfinDbFactory, ModelBuilderExtensions, PragmaConnectionInterceptor, AssemblyInfo, SqliteDatabaseProvider, DateTimeKindValueConverter. - Updated tests to remove dependencies on removed classes and adjusted mocking for configuration sections. - Added Microsoft.EntityFrameworkCore.Sqlite package reference to test project. - Improved string handling in tests for better consistency and clarity. - Refactored logging methods in JellyfinApplicationFactory for better readability and maintainability.
536 lines
15 KiB
Markdown
536 lines
15 KiB
Markdown
# Jellyfin with PostgreSQL Support
|
|
|
|
This is a fork of Jellyfin that adds PostgreSQL database support for .NET 11 preview.
|
|
|
|
## Features
|
|
|
|
- ✅ PostgreSQL database provider implementation
|
|
- ✅ Automatic database initialization from SQL scripts
|
|
- ✅ Remote database support with connection string configuration
|
|
- ✅ Database backup/restore via pg_dump/pg_restore
|
|
- ✅ Migration system disabled in favor of SQL scripts
|
|
- ✅ Support for both local and remote PostgreSQL servers
|
|
|
|
---
|
|
|
|
## Requirements
|
|
|
|
### FFmpeg Requirements
|
|
|
|
**jellyfin-ffmpeg is highly preferred and recommended** for use with Jellyfin Media Server. While standard FFmpeg can be used, the custom `jellyfin-ffmpeg` fork includes specifically targeted fixes, optimizations, and enhanced hardware acceleration support for media streaming that may not be available or prioritized in the upstream version.
|
|
|
|
#### Why jellyfin-ffmpeg is Preferred:
|
|
|
|
- **Improved Hardware Acceleration**: Better support for hardware acceleration (NVENC, QuickSync, VA-API) across a wider range of GPUs, reducing the risk of partial acceleration
|
|
- **Reduced Playback Issues**: Specifically built to handle HDR/Dolby Vision content, HLS/fMP4/MPEG-TS streaming, and complex transcoding scenarios better than standard FFmpeg
|
|
- **Optimized Performance**: Often includes more efficient software decoders (like dav1d for AV1)
|
|
- **Pre-configured**: Automatically included with official Docker images, deb packages, and Windows installers
|
|
|
|
**Link**: [jellyfin-ffmpeg repository](https://github.com/jellyfin/jellyfin-ffmpeg)
|
|
|
|
#### Installation:
|
|
|
|
**Debian/Ubuntu** (using Jellyfin repository):
|
|
```bash
|
|
# Add Jellyfin repository (if not already added)
|
|
sudo apt-get install -y software-properties-common
|
|
sudo add-apt-repository universe
|
|
|
|
# Install jellyfin-ffmpeg
|
|
sudo apt-get update
|
|
sudo apt-get install -y jellyfin-ffmpeg6
|
|
```
|
|
|
|
**Manual Download**:
|
|
Download from [jellyfin-ffmpeg releases](https://github.com/jellyfin/jellyfin-ffmpeg/releases) and configure the path in Jellyfin settings.
|
|
|
|
#### Using Standard FFmpeg (Not Recommended):
|
|
|
|
If using a custom or unofficial installation where jellyfin-ffmpeg is not available, standard FFmpeg might work but could lead to issues with specific transcoding tasks:
|
|
|
|
```bash
|
|
# Debian/Ubuntu
|
|
sudo apt-get install -y ffmpeg
|
|
|
|
# RHEL/Fedora
|
|
sudo dnf install -y ffmpeg
|
|
|
|
# Arch Linux
|
|
sudo pacman -S ffmpeg
|
|
```
|
|
|
|
**Note**: You may need to manually set the FFmpeg path in Jellyfin's dashboard under **Dashboard → Playback → FFmpeg path**.
|
|
|
|
### System Dependencies (Linux)
|
|
|
|
Jellyfin requires certain system libraries to be installed:
|
|
|
|
#### Debian/Ubuntu-based systems:
|
|
|
|
```bash
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
libfontconfig1 \
|
|
libfreetype6 \
|
|
libssl3 \
|
|
libicu-dev
|
|
```
|
|
|
|
**Note**: See the [FFmpeg Requirements](#ffmpeg-requirements) section above for installing `jellyfin-ffmpeg`.
|
|
|
|
#### RHEL/CentOS/Fedora-based systems:
|
|
|
|
```bash
|
|
sudo dnf install -y \
|
|
fontconfig \
|
|
freetype \
|
|
openssl \
|
|
libicu
|
|
```
|
|
|
|
**Note**: See the [FFmpeg Requirements](#ffmpeg-requirements) section above for installing FFmpeg.
|
|
|
|
#### Arch Linux:
|
|
|
|
```bash
|
|
sudo pacman -S fontconfig freetype2 openssl icu
|
|
```
|
|
|
|
**Note**: See the [FFmpeg Requirements](#ffmpeg-requirements) section above for installing FFmpeg.
|
|
|
|
**Note**: The `libfontconfig1` library is **required** for SkiaSharp (image processing). Without it, Jellyfin will fail to start with:
|
|
```
|
|
libfontconfig.so.1: cannot open shared object file: No such file or directory
|
|
```
|
|
|
|
### PostgreSQL Requirements
|
|
|
|
- PostgreSQL 12 or higher (tested with PostgreSQL 18.3)
|
|
- `psql` client tools (for automatic schema initialization)
|
|
- Network access to PostgreSQL server (if using remote database)
|
|
|
|
#### Install PostgreSQL client tools:
|
|
|
|
**Debian/Ubuntu**:
|
|
```bash
|
|
sudo apt-get install -y postgresql-client
|
|
```
|
|
|
|
**RHEL/CentOS/Fedora**:
|
|
```bash
|
|
sudo dnf install -y postgresql
|
|
```
|
|
|
|
**Verify psql is available**:
|
|
```bash
|
|
psql --version
|
|
```
|
|
|
|
---
|
|
|
|
## Database Configuration
|
|
|
|
### Option 1: Using ConnectionString (Recommended)
|
|
|
|
Create or edit `config/database.xml` in your Jellyfin data directory:
|
|
|
|
```xml
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<DatabaseConfigurationOptions>
|
|
<DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
|
|
<LockingBehavior>NoLock</LockingBehavior>
|
|
|
|
<CustomProviderOptions>
|
|
<PluginName>Jellyfin-PostgreSQL</PluginName>
|
|
<PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
|
|
|
|
<!-- Connection string with all parameters -->
|
|
<ConnectionString>Host=192.168.1.100;Port=5432;Database=jellyfin;Username=jellyfin;Password=your_password_here</ConnectionString>
|
|
</CustomProviderOptions>
|
|
|
|
<!-- Optional: Backup configuration (works for both local and remote databases) -->
|
|
<BackupOptions>
|
|
<PgDumpPath>pg_dump</PgDumpPath>
|
|
<PgRestorePath>pg_restore</PgRestorePath>
|
|
<BackupFormat>custom</BackupFormat>
|
|
<IncludeBlobs>true</IncludeBlobs>
|
|
<CompressionLevel>6</CompressionLevel>
|
|
<TimeoutSeconds>1800</TimeoutSeconds>
|
|
<VerboseOutput>true</VerboseOutput>
|
|
</BackupOptions>
|
|
</DatabaseConfigurationOptions>
|
|
```
|
|
|
|
### Option 2: Using Individual Options
|
|
|
|
```xml
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<DatabaseConfigurationOptions>
|
|
<DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
|
|
|
|
<CustomProviderOptions>
|
|
<PluginName>Jellyfin-PostgreSQL</PluginName>
|
|
<PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
|
|
|
|
<Options>
|
|
<CustomDatabaseOption>
|
|
<Key>Host</Key>
|
|
<Value>192.168.1.100</Value>
|
|
</CustomDatabaseOption>
|
|
|
|
<CustomDatabaseOption>
|
|
<Key>Port</Key>
|
|
<Value>5432</Value>
|
|
</CustomDatabaseOption>
|
|
|
|
<CustomDatabaseOption>
|
|
<Key>Database</Key>
|
|
<Value>jellyfin</Value>
|
|
</CustomDatabaseOption>
|
|
|
|
<CustomDatabaseOption>
|
|
<Key>Username</Key>
|
|
<Value>jellyfin</Value>
|
|
</CustomDatabaseOption>
|
|
|
|
<CustomDatabaseOption>
|
|
<Key>Password</Key>
|
|
<Value>your_password_here</Value>
|
|
</CustomDatabaseOption>
|
|
</Options>
|
|
</CustomProviderOptions>
|
|
</DatabaseConfigurationOptions>
|
|
```
|
|
|
|
### Option 3: Hybrid (ConnectionString + Overrides)
|
|
|
|
Individual options take precedence over ConnectionString:
|
|
|
|
```xml
|
|
<CustomProviderOptions>
|
|
<!-- Base connection -->
|
|
<ConnectionString>Host=192.168.1.100;Port=5432;Database=jellyfin;Username=jellyfin</ConnectionString>
|
|
|
|
<!-- Override just the password -->
|
|
<Options>
|
|
<CustomDatabaseOption>
|
|
<Key>Password</Key>
|
|
<Value>production_password</Value>
|
|
</CustomDatabaseOption>
|
|
</Options>
|
|
</CustomProviderOptions>
|
|
```
|
|
|
|
---
|
|
|
|
## Database Initialization
|
|
|
|
### Automatic Initialization
|
|
|
|
When Jellyfin starts with an empty database:
|
|
|
|
1. **Database Check**: Checks if the database exists (creates if missing)
|
|
2. **Table Check**: Checks if `users.Users` table exists
|
|
3. **Auto-Initialize**: If tables don't exist, automatically runs `sql/schema_init/create_database_schema.sql` via `psql`
|
|
4. **Schema Verification**: Verifies all required schemas and tables are present
|
|
|
|
**Requirements for automatic initialization**:
|
|
- ✅ `psql` command must be in system PATH
|
|
- ✅ Database must exist (created automatically or manually)
|
|
- ✅ SQL script must be deployed: `sql/schema_init/create_database_schema.sql`
|
|
|
|
### Manual Initialization
|
|
|
|
If `psql` is not available or automatic initialization fails:
|
|
|
|
```bash
|
|
# Create database first
|
|
createdb -U postgres jellyfin
|
|
|
|
# Run schema creation script
|
|
psql -U postgres -d jellyfin -f /path/to/jellyfin/sql/schema_init/create_database_schema.sql
|
|
```
|
|
|
|
---
|
|
|
|
## Startup Logs
|
|
|
|
### Successful Startup (Empty Database):
|
|
|
|
```
|
|
[INF] PostgreSQL connection: Host="192.168.1.100", Port=5432, Database="jellyfin", ...
|
|
[INF] Database tables not found (users.Users table missing). Initializing from SQL script...
|
|
[INF] Found schema script at: .../sql/schema_init/create_database_schema.sql
|
|
[INF] Executing create_database_schema.sql (this may take several minutes)...
|
|
[INF] Executing via psql: psql -h 192.168.1.100 -p 5432 -U jellyfin -d jellyfin -f "..."
|
|
[INF] ✅ Successfully initialized database from SQL script via psql
|
|
[INF] Database is ready. You can now start Jellyfin.
|
|
[DBG] Schema 'users' contains 4 tables
|
|
[DBG] Schema 'library' contains 45 tables
|
|
[DBG] Schema 'activitylog' contains 1 tables
|
|
[INF] ✅ Database schema verification complete
|
|
[INF] There are 0 migrations for stage CoreInitialisation
|
|
[INF] There are 24 migrations for stage AppInitialisation
|
|
```
|
|
|
|
### Successful Startup (Existing Database):
|
|
|
|
```
|
|
[INF] PostgreSQL connection: Host="192.168.1.100", Port=5432, Database="jellyfin", ...
|
|
[INF] Database tables exist (users.Users table found)
|
|
[DBG] Schema 'users' contains 4 tables
|
|
[DBG] Schema 'library' contains 45 tables
|
|
[INF] ✅ Database schema verification complete
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Error: `libfontconfig.so.1: cannot open shared object file`
|
|
|
|
**Cause**: Missing system dependency
|
|
|
|
**Solution**:
|
|
```bash
|
|
# Debian/Ubuntu
|
|
sudo apt-get install -y libfontconfig1
|
|
|
|
# RHEL/Fedora
|
|
sudo dnf install -y fontconfig
|
|
```
|
|
|
|
### Error: `psql command not found`
|
|
|
|
**Cause**: PostgreSQL client tools not installed
|
|
|
|
**Solution**:
|
|
```bash
|
|
# Debian/Ubuntu
|
|
sudo apt-get install -y postgresql-client
|
|
|
|
# RHEL/Fedora
|
|
sudo dnf install -y postgresql
|
|
```
|
|
|
|
### Error: `Failed to connect to 127.0.0.1:5432`
|
|
|
|
**Cause**: Configuration not loading correctly (using default localhost)
|
|
|
|
**Solution**:
|
|
- Verify `database.xml` is in the correct location (`/var/lib/jellyfin/config/database.xml` on Linux)
|
|
- Check that ConnectionString or individual Options are properly configured
|
|
- Ensure Host is set to your remote server IP/hostname
|
|
|
|
### Error: `database "jellyfin" does not exist`
|
|
|
|
**Cause**: Database wasn't created automatically (rare)
|
|
|
|
**Solution**:
|
|
```bash
|
|
# Create database manually
|
|
createdb -U postgres -h your-server jellyfin
|
|
|
|
# Grant privileges
|
|
psql -U postgres -h your-server -c "GRANT ALL PRIVILEGES ON DATABASE jellyfin TO jellyfin;"
|
|
|
|
# Restart Jellyfin (it will create tables automatically)
|
|
```
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
### Database Schema
|
|
|
|
- `activitylog` - Activity log entries
|
|
- `authentication` - API keys, devices, device options
|
|
- `displaypreferences` - User display preferences
|
|
- `library` - Media library data (BaseItems, metadata, etc.)
|
|
- `users` - User accounts, permissions, preferences
|
|
|
|
### Migration System
|
|
|
|
**Entity Framework migrations are DISABLED** for .NET 11 preview. Schema changes are managed via SQL scripts:
|
|
|
|
- **Core migrations**: Disabled (no database structure changes via EF)
|
|
- **Application migrations**: Enabled (configuration and data migrations only)
|
|
|
|
**Why**: EF migrations in preview builds can cause schema inconsistencies. SQL scripts provide reliable schema management.
|
|
|
|
---
|
|
|
|
## Backup and Restore
|
|
|
|
### Automatic Backups (via pg_dump)
|
|
|
|
Configured in `database.xml`:
|
|
|
|
```xml
|
|
<BackupOptions>
|
|
<PgDumpPath>pg_dump</PgDumpPath>
|
|
<BackupFormat>custom</BackupFormat>
|
|
<CompressionLevel>6</CompressionLevel>
|
|
</BackupOptions>
|
|
```
|
|
|
|
**Works for both local and remote databases!**
|
|
|
|
### Manual Backup
|
|
|
|
```bash
|
|
# Backup to custom format (compressed)
|
|
pg_dump -h your-server -U jellyfin -d jellyfin -Fc -f jellyfin_backup.dump
|
|
|
|
# Backup to SQL format
|
|
pg_dump -h your-server -U jellyfin -d jellyfin -f jellyfin_backup.sql
|
|
```
|
|
|
|
### Manual Restore
|
|
|
|
```bash
|
|
# Restore from custom format
|
|
pg_restore -h your-server -U jellyfin -d jellyfin jellyfin_backup.dump
|
|
|
|
# Restore from SQL format
|
|
psql -h your-server -U jellyfin -d jellyfin -f jellyfin_backup.sql
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting Connection Issues
|
|
|
|
### Error: `57P01: terminating connection due to administrator command`
|
|
|
|
**Cause**: PostgreSQL server forcibly terminated the connection during an operation
|
|
|
|
**Common reasons**:
|
|
- PostgreSQL server restart or reload
|
|
- Connection timeout (statement_timeout, idle_in_transaction_session_timeout)
|
|
- Manual connection termination via `pg_terminate_backend()`
|
|
- Network instability or firewall issues
|
|
- Resource limits exceeded (max_connections, memory pressure)
|
|
|
|
**Solutions**:
|
|
|
|
#### 1. Configure Automatic Retry (Already Enabled)
|
|
|
|
Jellyfin now includes automatic retry logic for transient failures:
|
|
- **Max retries**: 3 attempts
|
|
- **Max delay**: 5 seconds between retries
|
|
- **Retryable errors**: Includes `57P01` (connection termination)
|
|
|
|
#### 2. Increase PostgreSQL Timeouts
|
|
|
|
Edit PostgreSQL configuration (`/etc/postgresql/*/main/postgresql.conf`):
|
|
|
|
```
|
|
# Increase statement timeout
|
|
statement_timeout = 300000 # 5 minutes (in milliseconds)
|
|
|
|
# Increase idle transaction timeout
|
|
idle_in_transaction_session_timeout = 600000 # 10 minutes
|
|
|
|
# Enable TCP keepalives (prevent network timeouts)
|
|
tcp_keepalives_idle = 60 # seconds
|
|
tcp_keepalives_interval = 10 # seconds
|
|
tcp_keepalives_count = 6
|
|
```
|
|
|
|
Reload PostgreSQL:
|
|
```bash
|
|
sudo systemctl reload postgresql
|
|
# OR
|
|
psql -U postgres -c "SELECT pg_reload_conf();"
|
|
```
|
|
|
|
#### 3. Optimize Connection String
|
|
|
|
Add keepalive and timeout parameters to your connection string:
|
|
|
|
```xml
|
|
<ConnectionString>Host=192.168.129.253;Port=5432;Database=jellyfin;Username=jellyfin;Password=yourpass;Pooling=True;Minimum Pool Size=0;Maximum Pool Size=50;Connection Idle Lifetime=300;Connection Pruning Interval=10;Timeout=30;Command Timeout=300;Keepalive=60</ConnectionString>
|
|
```
|
|
|
|
**Key parameters**:
|
|
- `Timeout=30` - Connection establishment timeout (30 seconds)
|
|
- `Command Timeout=300` - Query execution timeout (5 minutes)
|
|
- `Keepalive=60` - TCP keepalive interval (60 seconds)
|
|
- `Connection Idle Lifetime=300` - Close idle connections after 5 minutes
|
|
- `Connection Pruning Interval=10` - Check for stale connections every 10 seconds
|
|
|
|
#### 4. Check PostgreSQL Logs
|
|
|
|
On your PostgreSQL server:
|
|
|
|
```bash
|
|
# View recent logs
|
|
sudo tail -f /var/log/postgresql/postgresql-*.log
|
|
|
|
# Or check systemd journal
|
|
sudo journalctl -u postgresql -n 100 --no-pager
|
|
```
|
|
|
|
Look for:
|
|
- `received fast shutdown request`
|
|
- `terminating connection`
|
|
- `too many connections`
|
|
- `out of memory`
|
|
|
|
#### 5. Monitor Active Connections
|
|
|
|
```sql
|
|
-- Check current connections
|
|
SELECT
|
|
datname,
|
|
usename,
|
|
application_name,
|
|
state,
|
|
state_change
|
|
FROM pg_stat_activity
|
|
WHERE datname = 'jellyfin'
|
|
ORDER BY state_change DESC;
|
|
|
|
-- Check connection limits
|
|
SELECT
|
|
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max_connections,
|
|
(SELECT COUNT(*) FROM pg_stat_activity) AS current_connections,
|
|
(SELECT COUNT(*) FROM pg_stat_activity WHERE datname = 'jellyfin') AS jellyfin_connections;
|
|
```
|
|
|
|
---
|
|
|
|
## Building from Source
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone https://github.com/yourusername/jellyfin.git
|
|
cd jellyfin
|
|
|
|
# Checkout the upgrade branch
|
|
git checkout upgrade-to-NET11
|
|
|
|
# Build
|
|
dotnet build
|
|
|
|
# Run
|
|
cd Jellyfin.Server
|
|
dotnet run
|
|
```
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
This is a development/preview branch. For production use, please use the official Jellyfin releases.
|
|
|
|
## License
|
|
|
|
GNU General Public License v2.0 (same as Jellyfin)
|
|
|
|
---
|
|
|
|
## Credits
|
|
|
|
Based on [Jellyfin](https://github.com/jellyfin/jellyfin) with PostgreSQL support and .NET 11 compatibility.
|