v0.3.5.1 · self-hosted · open source

Reclaim disk space
on autopilot.

Transcode Talker scans your media library, queues oversized files, re-encodes them to HEVC with hardware acceleration, and gives you back tens of gigabytes, without you ever opening HandBrake again.

  • ✓ Hardware accelerated: VAAPI · QSV · NVENC · CPU fallback
  • ✓ Postgres or SQLite, your call
  • ✓ Self-hosted web app, runs in your browser
transcode-talker.local/dashboard

Dashboard

live
Total Encoded
922
+18 this week
Space Saved
181 GB
34.2% avg
Queue
3
running
Now encoding · Baka and Test S00E09.mkv 62%
VAAPI · CRF 26 · 334 fps · ETA 2m 04s
up to 80%
Smaller files with HEVC compression
4
Encoders: VAAPI, QSV, NVENC, libx265 CPU
6
UI languages: EN, PT, ES, FR, ZH, JA
MIT
Open source, self-hosted, no cloud
Features

Built for entire media libraries.

Designed for a single goal: shrink your library without losing quality, and never run the same conversion twice.

⚡

Hardware acceleration

VAAPI (AMD/Intel), QSV (Intel), or NVENC (NVIDIA). Automatically falls back to libx265 CPU when no GPU is mounted.

⌕

Filesystem scan

Walk any number of folders, filter by minimum size, and queue only files that aren't already HEVC.

⌃

Full history with audit

Every encode is recorded with hash, FPS, encoder used, CRF, and space saved. Export/import as JSON.

⚙

Postgres or SQLite

Postgres is the production default; SQLite stays for single-user setups. Switch with one env var.

⌬

Live progress over WebSocket

Real-time fps, ETA, current frame, and a streaming ffmpeg log. Survives API restarts via exponential backoff.

⚐

Admin log stream

Ring-buffered HTTP and business events with SSE streaming. Parses IP, method, path, and status inline.

⌘

Multilingual help

English, Português, Español, Français, 中文, 日本語. The in-app manual ships in six languages.

How it works

Three steps. That's the whole loop.

01

Scan

Point at /mnt/media (or anywhere). Filter by size threshold. Files already in HEVC are skipped automatically.

→
02

Encode

Worker pulls jobs from Postgres, runs ffmpeg with your chosen encoder/preset/CRF, and streams live progress over WebSocket.

→
03

Reclaim

Original is replaced atomically; hash and metrics get persisted to history. You watch your free space go up.

The interface

Built to be lived in.

Six screens, each doing one thing well. No tabs-in-tabs, no buried settings, no five-second polling loops.

localhost:4246/dashboard

Dashboard

live
Total Encoded
922
+18 this week
Space Saved
181GB
34.2% avg
Active Queue
3
running
Success Rate
98.7%
stable

Now encoding

Baka and Test S00E09.mkv62%
VAAPI · CRF 26 · 334 fps · ETA 2m 04s

Recent activity

  • Movie.S01E02.mkv · saved 412 MB
  • Show.Episode.mkv · saved 287 MB
  • Anime.E04.mkv · saved 633 MB
  • Big.Buck.Bunny.mkv · retried 1×
localhost:4246/scan

Scan & Select

/mnt/animes /mnt/media 126 candidates · 47 GB total
FileSizeCodec
Movies/Inception.mkv4.2 GBx264
Animes/Baka and Test S00E09.mkv1.2 GBx264
Shows/Office S03E18.mkv2.8 GBx264
Movies/Interstellar.mkv8.1 GBx264
Animes/Bleach S01E20.mkv980 MBx264
localhost:4246/encode

Encode Queue

● live
running Baka and Test S00E09.mkv 62% · 334 fps · ETA 2m 04s
queued Inception.mkv 4.2 GB · waiting
queued Office S03E18.mkv 2.8 GB · waiting

Live log

[22:48:34] ffmpeg -hwaccel vaapi -i input.mkv ...
[22:48:35] vaapi: AMD Renoir initialized (renderD128)
[22:48:36] frame=  2508 fps=334 q=-0.0 size=  142336kB time=00:01:44.65
[22:48:37] frame=  2841 fps=334 q=-0.0 size=  158204kB time=00:01:58.51
[22:48:38] frame=  3175 fps=334 q=-0.0 size=  175020kB time=00:02:12.36
localhost:4246/history

History

status: all encoder: vaapi 922 records · 181 GB saved
FilenameOriginalFinalSavedEncoderStatus
Baka and Test S00E09.mkv1.18 GB....vaapiinterrupted
Movie Inception.mkv8.13 GB5.21 GB2.92 GBvaapicompleted
Office S03E18.mkv2.81 GB1.87 GB0.94 GBvaapicompleted
Anime E04.mkv1.49 GB0.86 GB0.63 GBvaapicompleted
Bleach S01E20.mkv0.98 GB0.57 GB0.41 GBvaapicompleted
localhost:4246/roadmap

Roadmap

YAML-driven · live reload
severity: all priority: all version: 0.3.5.2

🐞 Bugs · 3 open

B-103 WebSocket reconnect doesn't surface a disconnected state Low
B-104 Storage page silently fails on hosts without /mnt/hdd Med
B-105 Folder picker doesn't refresh on parent change Low

✦ Improvements · 0 open

I-201 Full UI rewrite (React + Vite + Tailwind) done
I-202 Roadmap surface in the UI done

★ Features · 5 planned

F-301 Encode preset profiles (saveable) High
F-302 Scheduled scans (cron-style) Med
F-303 Webhook on completion Low
localhost:4246/settings/admin-logs

Admin Logs

● live
INFO22:48:34uvicorn.access
IP 192.0.2.41
HTTP Method GET
Path /api/health
HTTP Response 200
INFO22:48:36reencoder.api
Event encode.start
Job ID 7384
File Baka and Test S00E09.mkv
Encoder vaapi
WARN22:48:41reencoder.worker
Event encode.interrupted
Job ID 7384
Reason Interrupted by user
Architecture

Four containers, sharp boundaries. Same stack, one docker-compose.

Each service does one job. Talk over the docker network; the host only sees port 4246.

▣

reencoder-web

nginx:1.27-alpine

Serves the Vite SPA bundle and reverse-proxies /api/* and /ws to the API.

4246 → 80
▤

reencoder-api

FastAPI · Python 3.12

REST + WebSocket + SSE. Owns scans, queue mutations, history, config, and the live event bus.

4246/tcp internal
▶

reencoder-worker

FFmpeg · Python 3.12

Pulls jobs from Postgres, spawns ffmpeg with hardware accel, streams progress. 8 CPU / 8 GB cap.

no public port
▦

postgres

postgres:16-alpine

Metastore for sessions, jobs, history, scan results. Switch to SQLite with DB_BACKEND=sqlite.

5432 internal
Install

One command. Four containers up.

Compose ships sane defaults, no .env required for a local boot. Postgres is the production default; SQLite stays one env var away.

  • ✓ Linux host with Docker & Docker Compose
  • ✓ Optional: /dev/dri mapped for VAAPI/QSV acceleration
  • ✓ ~6 GB free for the Postgres volume + first build cache
# 1. Clone & enter
git clone https://github.com/<you>/reencoder-v3.git
cd reencoder-v3

# 2. Build & up (4 containers)
docker compose build
docker compose up -d

# 3. Verify
docker compose ps
NAME                STATUS              PORTS
reencoder-postgres  Up (healthy)        5432/tcp
reencoder-api       Up (healthy)        4246/tcp
reencoder-worker    Up (healthy)
reencoder-web       Up (healthy)        0.0.0.0:4246->80/tcp

# 4. Open the UI
open http://localhost:4246
Why this exists

HandBrake is great, until you have 5,000 files.

vs. manual HandBrake

  • ✓ Walks your library automatically
  • ✓ Skips files already in HEVC
  • ✓ Persists history; never re-encodes the same file twice
  • ✓ Resumes after crashes via heartbeat

vs. cloud services

  • ✓ Your media never leaves your home network
  • ✓ Uses the GPU you already own
  • ✓ Zero per-minute fees
  • ✓ Works offline

vs. bash scripts

  • ✓ Real UI with queue, history, search, filters
  • ✓ Audit trail with hashes per file
  • ✓ WebSocket live progress, not tail -f
  • ✓ Multi-encoder fallback when hardware breaks