Jellyfin Favorites Sync
Sync Jellyfin playlist or favorite movies and series to a remote host via rsync.
Overview
This tool queries a Jellyfin server for items in a playlist (or favorited items), expands series to individual episodes, discovers parent directories containing media files and metadata (subtitles, .nfo files, posters), and syncs them to a remote host using rsync in mirror mode.
Features
- Playlist or Favorites: Query items from a Jellyfin playlist or favorites
- Series Expansion: Expands TV series to include all episodes
- Complete Sync: Syncs parent directories to include all auxiliary files (.srt, .nfo, poster.jpg, etc.)
- Mirror Mode: Uses rsync
--deleteto remove files when items are removed from playlist/favorites - Efficient: Single rsync invocation using
--files-fromfor large sets - Resumable: Supports
--partialand--append-verifyfor interrupted transfers - Configurable: Target host, paths, and SSH arguments all configurable
Usage
CLI
Using a playlist:
jellyfin-favorites-sync \
--jellyfin-url https://jellyfin.sbr.pm \
--api-key-file /run/agenix/jellyfin-api-key \
--user-id vincent \
--playlist-name "Sync to NAS" \
--source-root /neo/videos \
--dest-host aix.sbr.pm \
--dest-user vincent \
--dest-root /data/favorites \
--dry-run \
--verbose
Using favorites:
jellyfin-favorites-sync \
--jellyfin-url https://jellyfin.sbr.pm \
--api-key-file /run/agenix/jellyfin-api-key \
--user-id vincent \
--source-root /neo/videos \
--dest-host aix.sbr.pm \
--dest-user vincent \
--dest-root /data/favorites \
--dry-run \
--verbose
Options
--jellyfin-url: Jellyfin server URL (required)--api-key: Jellyfin API key (use –api-key-file for secrets)--api-key-file: Path to file containing API key (recommended)--user-id: Jellyfin user ID or username (required)--playlist-id: Jellyfin playlist ID to sync (optional, instead of favorites)--playlist-name: Jellyfin playlist name to sync (optional, instead of favorites)--source-root: Root path of Jellyfin library (default: /neo/videos)--dest-host: Destination SSH host (required)--dest-user: SSH user (default: vincent)--dest-root: Destination path (default: /data/favorites)--ssh-arg: Additional SSH arguments (can be repeated)--dry-run: Show operations without executing--verbose: Enable verbose output
NixOS Service
Configure as a systemd service with scheduled execution:
Using a playlist:
services.jellyfin-favorites-sync = {
enable = true;
schedule = "daily";
jellyfinUrl = "http://localhost:8096";
apiKeyFile = config.age.secrets."jellyfin-favorites-sync-api-key".path;
userId = "vincent";
# Use a playlist instead of favorites
playlistName = "Sync to NAS";
sourceRoot = "/neo/videos";
destination = {
host = "aix.sbr.pm";
user = "vincent";
root = "/data/favorites";
};
sshArgs = [ "-o StrictHostKeyChecking=accept-new" ];
};
Using favorites (default):
services.jellyfin-favorites-sync = {
enable = true;
schedule = "daily";
jellyfinUrl = "http://localhost:8096";
apiKeyFile = config.age.secrets."jellyfin-favorites-sync-api-key".path;
userId = "vincent";
sourceRoot = "/neo/videos";
destination = {
host = "aix.sbr.pm";
user = "vincent";
root = "/data/favorites";
};
sshArgs = [ "-o StrictHostKeyChecking=accept-new" ];
};
How It Works
- Connect to Jellyfin: Authenticate using API key
- Query Items: Fetch items from playlist (if specified) or favorites
- Expand Series: For each series, fetch all episodes
- Discover Paths: Extract parent directories containing media + metadata
- Generate File List: Create rsync
--files-frominput - Execute Rsync: Sync to remote host with
--deletefor mirror mode
Examples
Dry-Run to See What Would Be Synced
jellyfin-favorites-sync \
--jellyfin-url https://jellyfin.sbr.pm \
--api-key-file ~/.secrets/jellyfin-api-key \
--user-id vincent \
--dest-host aix.sbr.pm \
--dry-run \
--verbose
Sync to Different Host
jellyfin-favorites-sync \
--jellyfin-url https://jellyfin.sbr.pm \
--api-key-file /run/agenix/jellyfin-api-key \
--user-id vincent \
--dest-host backup.example.com \
--dest-root /backups/jellyfin-favorites
With Custom SSH Port
jellyfin-favorites-sync \
--jellyfin-url https://jellyfin.sbr.pm \
--api-key-file ~/.secrets/jellyfin-api-key \
--user-id vincent \
--dest-host aix.sbr.pm \
--ssh-arg "-p" \
--ssh-arg "2222"
Requirements
- Python 3.11+
requestslibraryclicklibraryrsynccommandopenssh(for SSH transport)
Security
- API Key: Stored in encrypted file via agenix, never logged
- Path Validation: All paths validated within source root
- SSH: Dedicated service user with restricted SSH key recommended
Troubleshooting
No Favorites Found
- Verify user ID is correct (run
jellyfin-favorites-sync --verbose) - Check that items are actually marked as favorite in Jellyfin UI
- Ensure API key has correct permissions
Rsync Fails
- Verify SSH connectivity:
ssh dest-user@dest-host - Check destination path exists and has correct permissions
- Use
--verboseto see full rsync command
Series Not Expanding
- Check Jellyfin logs for API errors
- Verify series has episodes in Jellyfin library
- Use
--verboseto see API responses
License
MIT