-
Notifications
You must be signed in to change notification settings - Fork 0
Fork Changes
What started as a targeted PostgreSQL swap has grown into a substantial independent rewrite. This page documents everything that differs from the upstream Pinchflat project.
The upstream project uses SQLite. This fork uses PostgreSQL.
- SQLite + Oban is a structural mismatch. Oban was built for Postgres and the SQLite adapter causes write contention under load, query timeouts, and crash loops as library size grows.
- Postgres handles concurrent job queues (indexing, downloading, metadata, file sync) correctly and without file locking issues.
- Deployment requires a Postgres sidecar container. See Installation.
Jobs that get stuck in executing state after a crash or container restart are automatically rescued and re-queued after 30 minutes. The upstream does not include this plugin.
- Scoped yt-dlp output template prevents multi-MB JSON truncation on resource-constrained hosts
- Graceful error handling in the metadata worker prevents fetch failures from causing noisy Oban retries and discards
The entire UI has been redesigned with a Sonarr-style layout.
- Source library — poster card grid with download progress bars and one-click monitored toggles
- Source detail page — fanart banner header, poster overlay, granular stats bar (Downloaded / Pending / Failed / Prevented / Skipped), horizontal action bar
- Episode list — grouped by year (season analog) with collapsible sections, per-item status badges, and monitored toggles
- Activity page — dedicated page replaces the cluttered home dashboard
- System Status page — Pinchfork version, yt-dlp version, PostgreSQL version and database size, Oban queue health, and live bgutil PO token server status with one-click test
Channel vs Playlist is now user-selectable on the new source form before entering the URL. This overrides yt-dlp's auto-detection, which can misidentify channel handles as playlists on some architectures. The URL field label changes dynamically (Channel URL / Playlist URL) and the URL field is locked until a type is selected.
A dedicated Edit Metadata page (accessible from the source action bar) provides:
- Editable Name and Description fields with per-field lock toggles — locked fields are not overwritten by metadata refreshes
- Custom poster upload (file or URL) — once set, the custom poster takes priority over auto-fetched images and is locked until removed
Per-source checkboxes to control whether public videos, members-only videos, or both are downloaded. The availability field is captured from yt-dlp at index time and re-evaluated on rescan.
Per-source control over when cookies are used: Disabled / When Needed / All Operations.
Select the yt-dlp player client per source. Used to bypass SABR-corrupted downloads or work around authentication issues on specific content. See SABR Bypass and PO Tokens.
Integration with the bgutil sidecar for YouTube PO token generation. Required for reliable downloads on some content. See SABR Bypass and PO Tokens.
YT_DLP_VERSION environment variable controls update behavior: stable (default), nightly, master, pinned/none to disable, or a specific version string like 2025.12.08.
error_type field on media items distinguishes permanent failures (members-only, unavailable, geo-blocked, age-restricted, premium-only) from transient ones (network errors, rate limits). Permanent failures automatically set prevent_download: true to stop retry cycles.
download_prevented_reason field distinguishes between manual prevention (user turned off download), policy blocks (system rules), and error-stops. This prevents re-indexing from accidentally re-enabling intentionally blocked items.
One-click API key validation from the Settings page.
Downloads can stage to a local disk path before moving to the final destination. Eliminates partial-file issues when /downloads is a network share. See Local Temp Staging.
The following upstream features are unchanged in this fork and are documented in the upstream wiki:
- Media profiles
- SponsorBlock integration
- RSS/podcast feeds
- Apprise notifications
- Custom yt-dlp options
- Lifecycle scripts
- Jellyfin/Plex/Kodi setup and file naming
- Retention periods
- Title filter regex
- Output path templates