Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ ARG GIT_SHA=unknown
# because it carries the DV RPU-aware tonemap_opencl patches upstream lacks).
RUN apt-get update && \
apt-get install -y --no-install-recommends \
mediainfo python3 python3-pip gosu pciutils git curl gnupg ca-certificates \
mesa-va-drivers mesa-vulkan-drivers libva2 libva-drm2 vainfo && \
mediainfo python3 python3-pip gosu pciutils git curl gnupg ca-certificates \
libchromaprint-tools \
mesa-va-drivers mesa-vulkan-drivers libva2 libva-drm2 vainfo && \
if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
# Jellyfin apt repo (Ubuntu Noble) for jellyfin-ffmpeg7
curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key \
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Generates video preview thumbnails (BIF files) for Plex Media Server. These are
| **Web Dashboard** | Manage jobs, schedules, and status |
| **Scheduling** | Cron and interval-based automation |
| **Smart Skipping** | Automatically skips files that already have thumbnails |
| **Credits Detection** | Automatic "Skip Credits" markers for movies and episodes |
| **Intro Detection** | Cross-episode audio fingerprinting finds recurring intros |
| **Radarr/Sonarr** | Webhook integration for auto-processing on import |
| **Plex direct webhook** | Auto-trigger on `library.new` (Plex Pass) for media added without Sonarr/Radarr |
| **Recently Added scanner** | Polling fallback that catches manually-added items without Plex Pass |
Expand Down
61 changes: 61 additions & 0 deletions docs/guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,67 @@ You can enable **both** if you want belt-and-suspenders behavior — the recentl

---

## Load Testing

A Locust load test is available for stress testing the web API.

### Running Load Tests

```bash
# Interactive mode (opens browser UI)
locust -f tests/load/locustfile.py

# Open http://localhost:8089 to configure and start
```

```bash
# Headless mode
locust -f tests/load/locustfile.py --headless -u 50 -r 10 -t 60s
```

> [!NOTE]
> Locust is a dev dependency. Install with `pip install -e ".[dev]"`.

---

## Marker Detection (Intro & Credits)

### Enabling Detection

1. Go to **Settings** in the web UI
2. Scroll to the **Credits Detection** and/or **Intro Detection** cards
3. Toggle the enable switch
4. Adjust parameters if needed (defaults work well for most content)
5. Click **Save Changes**
6. Run a job — detection runs automatically alongside BIF generation

### How It Works

**Credits detection** scans the last portion of each video with FFmpeg's `blackdetect` and `silencedetect` filters. When it finds a black frame + silence region near the end, it writes a "Skip Credits" marker to the Plex database.

**Intro detection** uses a two-pass approach:
1. **Pass 1** (parallel): Each episode gets its first ~10 minutes fingerprinted using `fpcalc` (chromaprint audio fingerprinting)
2. **Pass 2** (after all episodes): Fingerprints are compared across episodes in each season to find the recurring intro theme

### Troubleshooting

**Markers not appearing in Plex clients:**
- Restart your Plex client (or exit and re-enter the media). Plex clients cache marker data.
- Verify markers were written: check the job logs for "Credits marker:" or "Intro found for" messages.

**"Database locked" warnings:**
- Normal when Plex is busy (scanning, analyzing). The tool retries automatically (5-second timeout).
- If persistent, avoid running detection during Plex library scans.

**Docker on Windows:**
- Windows Docker volume mounts do not support SQLite file locking. Stop Plex Media Server before running detection, or use a Linux/macOS host.
- The Settings page shows a warning when this environment is detected.

**"fpcalc not found" for intro detection:**
- The Docker image includes `fpcalc`. If running from source, install `libchromaprint-tools`.

---

## HDR & Dolby Vision

The tool auto-detects HDR metadata and tone-maps to SDR before generating thumbnails. Behavior depends on the HDR format:
Expand Down
38 changes: 38 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,44 @@ GPU settings are configured per-GPU in **Settings** → **Processing Options**.
> No separate fallback pool is needed — increase `cpu_threads` if you
> want more dedicated CPU concurrency for files that never hit the GPU.

### Marker Detection (Experimental)

Detects intro and credits segments in media files and writes "Skip Intro" / "Skip Credits" markers directly to the Plex SQLite database. Markers appear as skip buttons in Plex clients.

#### Credits Detection

Analyzes the end of each video using FFmpeg's `blackdetect` and `silencedetect` filters to find where credits begin. Works on both movies and TV episodes.

| Setting | Web UI | Default | Description |
|---------|--------|---------|-------------|
| `credits_detection_enabled` | Yes | `false` | Enable credits detection |
| `credits_detection_overwrite` | Yes | `false` | Re-detect even if markers exist |
| `credits_scan_last_pct` | Yes | `25` | Scan last N% of video (5–50) |
| `credits_min_duration` | Yes | `15` | Minimum credits length in seconds (5–120) |

#### Intro Detection

Compares audio fingerprints across all episodes in a TV season to find the recurring intro theme. Uses `fpcalc` (chromaprint) for fingerprinting. Requires at least 2 episodes per season.

| Setting | Web UI | Default | Description |
|---------|--------|---------|-------------|
| `intro_detection_enabled` | Yes | `false` | Enable intro detection |
| `intro_detection_overwrite` | Yes | `false` | Re-detect even if markers exist |
| `intro_scan_duration_sec` | Yes | `600` | Seconds of audio to fingerprint (first N seconds of each episode) |
| `intro_min_duration_sec` | Yes | `15` | Minimum intro length in seconds |
| `intro_max_duration_sec` | Yes | `120` | Maximum intro length in seconds |

> [!WARNING]
> Marker detection writes directly to the Plex SQLite database (`com.plexapp.plugins.library.db`).
> Back up your database before enabling. Detection is safe while Plex is running (Plex uses WAL mode),
> but **Docker on Windows** volume mounts do not support SQLite file locking — stop Plex before
> running detection on Windows, or use a Linux/macOS host.

> [!NOTE]
> The Plex REST API only supports bookmark-type markers. Intro and credits markers must be written
> directly to the database. This is the same approach used by [MarkerEditorForPlex](https://github.com/danrahn/MarkerEditorForPlex)
> and other community tools.

---

## Environment Variables
Expand Down
13 changes: 13 additions & 0 deletions plex_generate_previews/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,19 @@ class Config:
# Exclude paths: list of {"value": str, "type": "path"|"regex"}; path = prefix match, regex = full match
exclude_paths: list[dict[str, str]] | None = None

# Credits detection
credits_detection_enabled: bool = False
credits_detection_overwrite: bool = False
credits_scan_last_pct: float = 25.0
credits_min_duration: float = 15.0

# Intro detection
intro_detection_enabled: bool = False
intro_detection_overwrite: bool = False
intro_scan_duration_sec: float = 600.0 # first 10 minutes
intro_min_duration_sec: float = 15.0
intro_max_duration_sec: float = 120.0

def __repr__(self) -> str:
"""Return a string representation with plex_token redacted."""
fields = []
Expand Down
Loading
Loading