Skip to content
Reggio-DigitalPublic

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Repository files navigation

Clipmark

Docker Build GitHub release GHCR License: MIT

Create GIF clips from your Plex media library. Self-hosted, single-container. Optional integrations.

Features

  • Browse & Search - Navigate your Plex libraries or search by title
  • Subtitle Navigation - Click subtitle lines to jump to that moment
  • Clip Start & Duration - Choose where the clip begins and how long it runs, with frame preview
  • GIF Generation - Create GIFs with optional subtitle burn-in or custom text
  • Gallery - View, download, and manage your created GIFs
  • GIPHY Upload - Upload GIFs directly to GIPHY (optional)

Screenshots

Browse libraries

Gallery view

Create GIF with subtitle burn-in

Quick Start

docker run -d -p 8000:8000 -v ./data:/data --name clipmark ghcr.io/reggio-digital/clipmark:latest

Open http://localhost:8000 and connect your Plex account.

Note: Plex Media Server must be reachable from the container.

Library access

Each user signs in with their own Plex account. Browsing, search, media previews, and GIF creation use that account's access to the configured server, including Plex library and content restrictions. Manage access in Plex; a Clipmark admin role does not grant additional Plex library permissions.

After upgrading from a version without per-user library access, existing users must sign out and sign in again. Library access is denied until they do. Upgrading from a build that stored account tokens also clears those user tokens and requires sign-in again. Each user's server connection and library list are reused for up to 30 seconds; media and preview access are checked against Plex on every request. Plex Media Server must be reachable for these checks; plex.tv is needed at login. Changing the configured server requires users to sign in again for that server. The owner-wide background library scan has been removed. Legacy thumbnail and subtitle/detail cache files are deleted automatically at startup and during cache cleanup; namespaced files are preserved, and expired frames/previews use their existing cleanup schedule. Queued GIFs check the creator's access again before processing. Jobs queued before this upgrade or for a different Plex server must be created again.

Saved favorites and completed GIFs remain in their owner's account. Public GIF links explicitly created with public sharing enabled remain public.

Docker Compose

services:
  clipmark:
    image: ghcr.io/reggio-digital/clipmark:latest
    container_name: clipmark
    ports:
      - "8000:8000"
    volumes:
      - ./data:/data
    restart: unless-stopped

Docker Run

docker run -d \
  -p 8000:8000 \
  -v ./data:/data \
  --name clipmark \
  ghcr.io/reggio-digital/clipmark:latest

Requirements

  • Docker
  • Plex Media Server (accessible from the container)

Configuration

Environment variables (all optional):

Variable Default Description
DATA_DIR /data Persistent storage path
MAX_CONCURRENT_JOBS 1 Parallel FFmpeg jobs
MAX_QUEUED_JOBS 10 Max pending jobs
MAX_QUEUED_JOBS_PER_USER 3 Max pending jobs per user
MAX_GIF_DURATION_SECONDS 15 Max GIF length
MAX_PREVIEW_DURATION_SECONDS 10 Max preview length
MAX_WIDTH 480 Max output width (pixels)
MAX_FPS 10 Max frame rate
FRAME_CACHE_TTL_MINUTES 30 Frame cache lifetime
PREVIEW_CACHE_TTL_MINUTES 30 Preview cache lifetime
FAILED_WORKSPACE_TTL_HOURS 24 Failed job cleanup delay
FFMPEG_TIMEOUT_SECONDS 300 FFmpeg process timeout

Output defaults are 480px width and 10 FPS. Environment variables define upper limits, not per-GIF defaults.

App Settings (config.json)

These are managed via the admin UI and stored in data/config.json:

Setting Default Description
gifsicle_enabled true Enable gifsicle GIF compression
gifsicle_lossy 100 Lossy compression level (0-200)
public_sharing_enabled false Allow public GIF sharing via link
giphy_global_enabled true Allow users to upload to GIPHY
max_gif_duration_seconds 15 Default max GIF duration
max_width 480 Default max output width
max_fps 10 Default max frame rate
browse_page_size 48 Items per page when browsing

Data Storage

Mount /data as a volume. Contains:

/data/
├── config.json       # Plex token (treat as secret)
├── clipmark.db       # SQLite database
├── cache/
│   ├── frames/       # Extracted video frames
│   ├── previews/     # GIF previews
│   ├── thumbnails/   # Media thumbnails
│   └── subtitles/    # Parsed subtitle data
├── work/             # Job workspaces (auto-cleaned)
└── output/           # Generated GIFs

GIPHY Integration

Clipmark can upload your GIFs directly to GIPHY. To enable this:

  1. Create a free account at developers.giphy.com
  2. Create an app to get an API key
  3. Go to Settings in Clipmark and enter your API key

Once configured, a GIPHY upload button appears on completed GIFs in the gallery. Uploaded GIFs follow GIPHY's standard review and visibility rules.

GIF Optimization

Clipmark uses gifsicle to reduce GIF file sizes by 20-40%. This is enabled by default and can be configured in Settings:

  • Enable/disable - Toggle optimization on or off
  • Lossy compression - Adjust quality vs size (0-200, default 100)

Higher lossy values = more compression = smaller files but more artifacts.

Subtitles

Clipmark detects subtitles associated with Plex items (sidecar or embedded). If no subtitles appear for your media:

  1. Check Plex first - Open the media in Plex and verify subtitles are available there
  2. Search in Plex - Plex can search for and download subtitles directly from the media detail page
  3. Add external subtitles - Place .srt files alongside your media files with matching names (e.g., Movie.mp4 → Movie.srt or Movie.en.srt), then refresh the library in Plex
  4. Embedded subtitles - These are automatically detected if present in the media file

Supported formats for burn-in:

  • SRT, ASS/SSA, WebVTT - Full support (text-based)
  • PGS, DVD subtitles - Detected but cannot be burned into GIFs (image-based bitmap subtitles)

If your media only has PGS/DVD bitmap subtitles, convert to SRT (via OCR tools) or use custom text overlay instead.

Tip: Bazarr can automatically find and download subtitles across your entire library. It's a great companion if you want subtitles available without manually searching in Plex for each title.

Development

Prerequisites: Node 18+, Python 3.12, ffmpeg, and gifsicle on your PATH.

First-time setup (from the repo root):

cd frontend && npm install && cd ..
cd backend && python3 -m venv venv && ./venv/bin/pip install -r requirements.txt && cd ..

Start the app:

npm run dev

That runs the backend (Uvicorn, port 8000) and the frontend (Vite, port 5173) together with hot reload. Open http://localhost:5173. Vite proxies /api/* and /output/* to the backend.

The dev script also runs pip install -q -r requirements.txt against the backend venv on every start, so new Python dependencies are picked up automatically. Local data (config, SQLite DB, cache, generated GIFs) lives in ./data/ via DATA_DIR=../data.

Running npm run dev from frontend/ works too; the root script just delegates to it.

Build Docker Image

docker build -t clipmark .

Tech Stack

  • Frontend: React, TypeScript, Vite, Tailwind CSS
  • Backend: Python, FastAPI, SQLAlchemy, SQLite
  • Plex: python-plexapi
  • Media: FFmpeg, gifsicle

Security Notes

  • The owner's Plex account token remains server-side in config.json. At login, Clipmark obtains the selected server's resource.accessToken and stores it with the server ID in clipmark.db. Tokens are never included in browser responses. Treat both files and their backups as secrets; older backups may still contain account tokens.
  • If exposing to the internet, use a reverse proxy with HTTPS

License

MIT. See LICENSE for details.

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages