- Add setup auth fixes and scheduler time validation for reliable onboarding - Harden file watcher behavior under bursty filesystem events - Improve DB stability with WAL, timeouts, FK enforcement, runtime legacy watch_dir support, and new indexes - Add session cleanup task and include config dirs in initial scans - Switch reqwest to rustls for cross-compilation without OpenSSL - Add cross-platform build script (bun + zig + cargo-xwin) and design philosophy doc - Bump documentation changelog for v0.2.6-beta
38 KiB
Alchemist Documentation
Complete reference for the Alchemist video transcoding automation system
Table of Contents
- Overview
- Architecture
- Installation
- Configuration
- Web Interface
- API Reference
- Database Schema
- Database Migration Policy
- Hardware Acceleration
- Docker Deployment
- Development
- Troubleshooting
Overview
Alchemist is an intelligent video transcoding automation system written in Rust. It automatically analyzes your media library and transcodes files to efficient AV1/HEVC format using hardware acceleration (GPU) or software encoding (CPU fallback).
Why Alchemist?
Modern video codecs like AV1 and HEVC can reduce file sizes by 30-70% compared to older H.264 content while maintaining visual quality. However, manually transcoding a large media library is tedious and error-prone. Alchemist solves this by:
-
Intelligent Analysis: Not every file benefits from re-encoding. Alchemist analyzes bitrate, resolution, and codec efficiency to skip files that are already optimized.
-
Quality Preservation: Uses VMAF (Video Multi-Method Assessment Fusion) scoring to ensure transcoded files maintain perceptual quality.
-
Automatic Rollback: If a transcode doesn't meet size reduction thresholds, the original file is preserved.
-
Set-and-Forget: Configure once, let it run. Watch folders automatically pick up new content.
Use Cases
| Scenario | Benefit |
|---|---|
| Home Media Server | Reduce storage costs by shrinking your Plex/Jellyfin library |
| Archive Optimization | Convert old DVR recordings to modern efficient formats |
| Bandwidth Reduction | Smaller files = faster streaming over network |
| NAS Storage | Maximize limited NAS capacity |
| Content Creators | Batch convert raw footage to delivery formats |
Key Features
| Feature | Description |
|---|---|
| Hardware Acceleration | NVIDIA NVENC, Intel QSV, AMD VAAPI support |
| CPU Fallback | Automatic libsvtav1/x265 encoding when GPU unavailable |
| Intelligent Analysis | Only transcodes files that benefit from re-encoding |
| Web Dashboard | Real-time monitoring with React/Astro frontend |
| Single Binary | All assets embedded for easy deployment |
| Queue System | Concurrent job processing with priority support |
| Statistics | Detailed metrics, VMAF scores, space savings |
| Watch Folders | Auto-enqueue new files in monitored directories |
| 12+ Themes | Customizable UI with dark mode variants |
| Auth System | Secure login with Argon2 password hashing |
| Real-time Updates | Server-Sent Events for live progress |
How It Works
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SCAN │───▶│ ANALYZE │────▶│ DECIDE │────▶│ ENCODE │
│ │ │ │ │ │ │ │
│ Find video │ │ FFprobe │ │ Worth it? │ │ FFmpeg │
│ files │ │ metadata │ │ BPP check │ │ GPU/CPU │
│ │ │ │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ SKIP │ │ VERIFY │
│ │ │ │
│ Already │ │ VMAF score │
│ optimized │ │ Size check │
│ │ │ │
└─────────────┘ └─────────────┘
Technology Stack
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Rust + Tokio | Async, safe, fast |
| Web Framework | Axum | High-performance HTTP |
| Database | SQLite + SQLx | Embedded, zero-config |
| Frontend | Astro + React | Modern, reactive UI |
| Styling | Tailwind CSS | Utility-first CSS |
| Media | FFmpeg + FFprobe | Industry standard |
| Packaging | rust-embed | Single binary deployment |
Architecture
┌───────────────────────────────────────────────────────────────┐
│ Alchemist │
├───────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Scanner │ │ Analyzer │ │ Processor │ │
│ │ │ │ │ │ │ │
│ │ • Directory │ │ • FFprobe │ │ • FFmpeg │ │
│ │ walking │ │ • BPP calc │ │ • GPU/CPU │ │
│ │ • Filtering │ │ • Decision │ │ • VMAF │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Scheduler │ │
│ │ • Job queue management │ │
│ │ • Concurrency control │ │
│ │ • Priority ordering │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ SQLite Database │ │
│ │ • Jobs, Decisions, Encode Stats │ │
│ │ • Users, Sessions │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Axum Web Server │ │
│ │ • REST API endpoints │ │
│ │ • Server-Sent Events (SSE) │ │
│ │ • Static file serving │ │
│ └─────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
Module Overview
| Module | File | Purpose |
|---|---|---|
| Main | src/main.rs |
Entry point, CLI parsing, server startup |
| Config | src/config.rs |
Configuration loading and validation |
| Database | src/db.rs |
SQLite operations, job management |
| Server | src/server.rs |
Axum routes, API handlers |
| Scheduler | src/scheduler.rs |
Job queue, concurrency control |
| Processor | src/processor.rs |
Orchestrates analysis → encoding flow |
| Analyzer | src/media/analyzer.rs |
FFprobe wrapper, transcode decisions |
| FFmpeg | src/media/ffmpeg.rs |
FFmpeg wrapper, encoding commands |
| Watcher | src/system/watcher.rs |
File system monitoring |
Installation
Prerequisites
- Rust: 1.75+ (for building from source)
- FFmpeg: 5.0+ with hardware acceleration support
- FFprobe: Included with FFmpeg
- Bun: 1.3.4+ (for web development)
From Source
# Clone repository
git clone https://github.com/BrooklynLovesZelda/alchemist.git
cd alchemist
# Install dependencies
cd web && bun install
# Build release binary
cd .. && cargo build --release
# Binary located at ./target/release/alchemist
Docker (Recommended)
# Pull from GitHub Container Registry
docker pull ghcr.io/brooklynloveszelda/alchemist:latest
# Or build locally
docker build -t alchemist .
First-Run Setup
On first launch, Alchemist runs an interactive setup wizard to:
- Create admin user account
- Configure media directories
- Set transcoding preferences
- Detect available hardware encoders
Configuration
Configuration is stored in config.toml. On first run, the setup wizard creates this file.
Full Configuration Reference
#──────────────────────────────────────────────────────────────────
# TRANSCODING SETTINGS
#──────────────────────────────────────────────────────────────────
[transcode]
# Output codec: "av1" or "hevc"
output_codec = "av1"
# Quality profile: "quality", "balanced", or "speed"
quality_profile = "balanced"
# Minimum size reduction required (0.3 = 30%)
# If output isn't 30% smaller, original is kept
size_reduction_threshold = 0.3
# Minimum bits-per-pixel threshold for re-encoding
# Files already below this are skipped
min_bpp_threshold = 0.1
# Skip files smaller than this (in MB)
min_file_size_mb = 50
# Number of concurrent transcode jobs
concurrent_jobs = 2
#──────────────────────────────────────────────────────────────────
# HARDWARE ACCELERATION
#──────────────────────────────────────────────────────────────────
[hardware]
# Enable CPU fallback when GPU unavailable
allow_cpu_fallback = true
# Allow pure CPU encoding (no GPU required)
allow_cpu_encoding = true
# CPU encoding preset: "slow", "medium", "fast", "faster"
cpu_preset = "medium"
#──────────────────────────────────────────────────────────────────
# SCANNER SETTINGS
#──────────────────────────────────────────────────────────────────
[scanner]
# Directories to scan for media files
directories = [
"/media/movies",
"/media/tvshows"
]
# File extensions to include
extensions = ["mkv", "mp4", "avi", "mov", "wmv", "flv", "webm"]
# Skip files matching these patterns
exclude_patterns = ["sample", "trailer", "extras"]
#──────────────────────────────────────────────────────────────────
# SERVER SETTINGS
#──────────────────────────────────────────────────────────────────
[server]
# Web server port
port = 3000
# Bind address
host = "0.0.0.0"
Environment Variables
| Variable | Description | Default |
|---|---|---|
ALCHEMIST_CONFIG |
Path to config file | ./config.toml |
ALCHEMIST_DATA_DIR |
Data directory path | ./data |
ALCHEMIST_LOG_LEVEL |
Log verbosity | info |
Web Interface
The Alchemist web interface is a modern, responsive single-page application built with Astro and React. It provides real-time monitoring and control of the transcoding engine.
Navigation
The sidebar provides quick access to all sections:
| Icon | Page | Keyboard Shortcut |
|---|---|---|
| 📊 | Dashboard | - |
| 🎬 | Jobs | - |
| 📁 | Library | - |
| 📜 | Logs | - |
| 📈 | Statistics | - |
| 🎨 | Appearance | - |
| ⚙️ | Settings | - |
Dashboard (/)
The main command center for Alchemist. At a glance, see:
Summary Cards
- Active Jobs: Currently encoding files with live progress
- Completed: Total successful transcodes
- Failed: Jobs that encountered errors
- Total Processed: Lifetime job count
Recent Activity Feed
- Last 5 jobs with file name, status, and timestamp
- Color-coded status badges (green=complete, yellow=active, red=failed)
- Click to view job details
Quick Actions
- Scan Now: Trigger immediate directory scan
- Pause/Resume: Control the processing engine
Jobs (/jobs)
Comprehensive job management interface:
Job Table Features
- Sortable columns (name, status, progress, date)
- Status filtering (all, active, completed, failed)
- Search by filename
- Pagination for large queues
Per-Job Actions
| Action | Description |
|---|---|
| Cancel | Stop active encoding (preserves original) |
| Restart | Re-queue failed job for retry |
| View Details | See full analysis and encoding logs |
Bulk Actions
- Restart All Failed: Re-queue all failed jobs
- Clear Completed: Remove finished jobs from list
Statistics (/stats)
Deep dive into transcoding performance:
Overview Cards
- Space Saved (GB + percentage)
- Total Processed
- Encoding Time
- Average VMAF Score
Daily Activity Chart
- Bar chart showing jobs completed per day
- Last 30 days of activity
- Hover for detailed tooltips
Space Efficiency Visualization
- Visual comparison of input vs output size
- Animated progress bar
Performance Metrics Grid
- Average Compression Ratio
- Average Encoding Speed (fps)
- Average Bitrate (kbps)
Recent Jobs Table
- Last 10 completed jobs with full metrics
- Columns: File, Input Size, Output Size, Saved %, Ratio, VMAF, Time
Library (/library)
File browser for your configured media directories:
Features
- Navigate directory tree
- View file metadata (size, codec, resolution, bitrate)
- Enqueue individual files for transcoding
- See analysis results without encoding
- Filter by extension
Logs (/logs)
Real-time log viewer powered by Server-Sent Events:
Log Entry Types
| Type | Color | Description |
|---|---|---|
| INFO | Blue | General status updates |
| SUCCESS | Green | Job completions |
| WARNING | Yellow | Non-fatal issues |
| ERROR | Red | Failures and exceptions |
| DEBUG | Gray | Detailed diagnostics |
Features
- Auto-scroll with pause on hover
- Filter by log level
- Filter by job ID
- Search within logs
- Clear log history
Settings (/settings)
Configure the transcoding engine:
Transcoding Engine
- Output Codec: Toggle between AV1 and HEVC
- Quality Profile: Quality / Balanced / Speed
- Concurrent Jobs: 1-8 parallel encodes
- Min Reduction: Required size savings (%)
- Min File Size: Skip files below threshold
Changes are applied immediately - no restart required.
Appearance (/appearance)
Customize the UI with 12+ color profiles organized by category:
Vibrant & Energetic
- 🟠 Helios Orange: Default warm theme
- 🌅 Sunset: Warm gradients
- 💜 Neon: Electric cyber aesthetic
- 🔴 Crimson: Bold red accents
Cool & Calm
- 🔵 Deep Blue: Navy with cool highlights
- 🌊 Ocean: Teal and turquoise
- 🟢 Emerald: Rich green tones
Soft & Dreamy
- 💜 Lavender: Soft pastels
- 🟣 Purple: Velvet violets
Dark & Minimal
- ⚫ Midnight: Pure OLED black
- ⬛ Monochrome: Neutral grayscale
- 🧛 Dracula: Classic dev theme
API Reference
All API endpoints require authentication via Bearer token, except for:
/api/setup/*- Setup wizard endpoints/api/auth/login- Login endpoint/api/health- Health check (returns status, version, uptime)/api/ready- Readiness check (returns database status)
Authentication
# Login
POST /api/auth/login
Content-Type: application/json
{"username": "admin", "password": "secret"}
# Response: {"token": "abc123..."}
# Use token in subsequent requests
Authorization: Bearer abc123...
Jobs
# Get all jobs
GET /api/jobs/table
# Get job stats
GET /api/stats
# Cancel job
POST /api/jobs/:id/cancel
# Restart job
POST /api/jobs/:id/restart
# Restart all failed
POST /api/jobs/restart-failed
# Clear completed
POST /api/jobs/clear-completed
Statistics
# Aggregated stats (totals)
GET /api/stats/aggregated
# Response: {total_input_bytes, total_output_bytes, total_savings_bytes,
# total_time_seconds, total_jobs, avg_vmaf}
# Daily stats (last 30 days)
GET /api/stats/daily
# Response: [{date, jobs_completed, bytes_saved, total_input_bytes,
# total_output_bytes}, ...]
# Detailed per-job stats
GET /api/stats/detailed
# Response: [{job_id, input_path, input_size_bytes, output_size_bytes,
# compression_ratio, encode_time_seconds, encode_speed,
# avg_bitrate_kbps, vmaf_score, created_at}, ...]
Engine Control
# Pause processing
POST /api/engine/pause
# Resume processing
POST /api/engine/resume
# Get engine status
GET /api/engine/status
Settings
# Get transcode settings
GET /api/settings/transcode
# Update transcode settings
POST /api/settings/transcode
Content-Type: application/json
{
"concurrent_jobs": 2,
"size_reduction_threshold": 0.3,
"min_bpp_threshold": 0.1,
"min_file_size_mb": 50,
"output_codec": "av1",
"quality_profile": "balanced"
}
Server-Sent Events
# Real-time event stream
GET /api/events?token=<auth_token>
# Event types:
# - JobStateChanged: {job_id, status}
# - Progress: {job_id, percentage, time}
# - Decision: {job_id, action, reason}
# - Log: {job_id, message}
Database Schema
Alchemist uses SQLite for persistence. The database file is located at data/alchemist.db.
Tables
jobs
| Column | Type | Description |
|---|---|---|
id |
INTEGER | Primary key |
input_path |
TEXT | Source file path (unique) |
output_path |
TEXT | Destination file path |
status |
TEXT | Job state (queued/encoding/completed/failed/etc) |
mtime_hash |
TEXT | File modification time hash |
priority |
INTEGER | Job priority (higher = first) |
progress |
REAL | Encoding progress 0-100 |
attempt_count |
INTEGER | Retry count |
created_at |
DATETIME | Job creation time |
updated_at |
DATETIME | Last status update |
encode_stats
| Column | Type | Description |
|---|---|---|
id |
INTEGER | Primary key |
job_id |
INTEGER | Foreign key to jobs |
input_size_bytes |
INTEGER | Original file size |
output_size_bytes |
INTEGER | Encoded file size |
compression_ratio |
REAL | input/output ratio |
encode_time_seconds |
REAL | Total encoding time |
encode_speed |
REAL | Frames per second |
avg_bitrate_kbps |
REAL | Output bitrate |
vmaf_score |
REAL | Quality score (0-100) |
created_at |
DATETIME | Completion time |
decisions
| Column | Type | Description |
|---|---|---|
id |
INTEGER | Primary key |
job_id |
INTEGER | Foreign key to jobs |
action |
TEXT | Action taken (encode/skip/revert) |
reason |
TEXT | Human-readable explanation |
created_at |
DATETIME | Decision time |
users
| Column | Type | Description |
|---|---|---|
id |
INTEGER | Primary key |
username |
TEXT | Unique username |
password_hash |
TEXT | Argon2 password hash |
created_at |
DATETIME | Account creation time |
sessions
| Column | Type | Description |
|---|---|---|
id |
INTEGER | Primary key |
user_id |
INTEGER | Foreign key to users |
token |
TEXT | Session token (unique) |
created_at |
DATETIME | Session start |
expires_at |
DATETIME | Session expiration |
Database Migration Policy
Baseline Version: 0.2.5
All database migrations maintain backwards compatibility with the v0.2.5 schema. This means:
- ✅ Newer app versions work with older database files
- ✅ Database files can be safely upgraded
- ✅ No data loss during upgrades
Migration Rules
Allowed Operations
- Add new tables with
CREATE TABLE IF NOT EXISTS - Add new columns with
NULLorDEFAULTvalues - Add new indexes with
CREATE INDEX IF NOT EXISTS - Insert new configuration rows
Forbidden Operations
- Never remove columns
- Never rename columns
- Never change column types
- Never remove tables
- Never add
NOT NULLcolumns without defaults
Schema Version Tracking
The schema_info table tracks compatibility:
SELECT value FROM schema_info WHERE key = 'min_compatible_version';
-- Returns: "0.2.5"
Hardware Acceleration
Alchemist auto-detects available hardware encoders at startup.
Supported Encoders
| GPU | Encoder | Codec Support |
|---|---|---|
| NVIDIA | NVENC | AV1, HEVC |
| Intel | QSV | AV1, HEVC |
| AMD | VAAPI | HEVC (AV1 limited) |
| Apple | VideoToolbox | HEVC (experimental) |
| CPU | libsvtav1/x265 | AV1, HEVC |
Detection Order
- NVIDIA NVENC (if CUDA available)
- Intel QuickSync (if iGPU available)
- AMD VAAPI (on Linux)
- CPU fallback (always available)
Docker GPU Passthrough
See docs/GPU_PASSTHROUGH.md for detailed instructions on:
- NVIDIA Container Toolkit setup
- Intel QSV passthrough
- AMD ROCm configuration
Docker Deployment
Basic Run
docker run -d \
--name alchemist \
-p 3000:3000 \
-v /path/to/media:/media \
-v alchemist_data:/app/data \
ghcr.io/brooklynloveszelda/alchemist:latest
With NVIDIA GPU
docker run -d \
--name alchemist \
--gpus all \
-p 3000:3000 \
-v /path/to/media:/media \
-v alchemist_data:/app/data \
ghcr.io/brooklynloveszelda/alchemist:latest
Docker Compose
version: "3.8"
services:
alchemist:
image: ghcr.io/brooklynloveszelda/alchemist:latest
container_name: alchemist
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- /path/to/media:/media
- alchemist_data:/app/data
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
volumes:
alchemist_data:
Image Tags
| Tag | Description |
|---|---|
latest |
Latest stable release |
0.2.5 |
Specific version |
0.2 |
Latest patch of minor version |
Development
This section covers setting up a development environment and contributing to Alchemist.
Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Rust | 1.75+ | Backend compilation |
| Bun | 1.3.4+ | Frontend package management |
| FFmpeg | 5.0+ | Media processing (runtime) |
| Docker | 20.10+ | Container builds (optional) |
Project Structure
alchemist/
├── src/ # Rust backend
│ ├── main.rs # Entry point & CLI
│ ├── config.rs # Configuration loading
│ ├── db.rs # Database operations (600+ lines)
│ ├── server.rs # Axum routes & handlers
│ ├── scheduler.rs # Job queue management
│ ├── processor.rs # Transcode orchestration
│ ├── error.rs # Error types & handling
│ ├── media/
│ │ ├── mod.rs # Module exports
│ │ ├── analyzer.rs # FFprobe wrapper & decisions
│ │ └── ffmpeg.rs # FFmpeg command builder
│ └── system/
│ ├── mod.rs # Module exports
│ └── watcher.rs # File system monitoring
│
├── web/ # Frontend (Astro + React)
│ ├── src/
│ │ ├── pages/ # Astro page routes
│ │ │ ├── index.astro # Dashboard
│ │ │ ├── jobs.astro # Job management
│ │ │ ├── stats.astro # Statistics dashboard
│ │ │ └── ...
│ │ ├── components/ # React components
│ │ │ ├── Dashboard.tsx
│ │ │ ├── StatsCharts.tsx
│ │ │ ├── SystemStatus.tsx
│ │ │ └── ...
│ │ ├── layouts/ # Page layouts
│ │ ├── lib/ # Utilities
│ │ │ └── api.ts # Authenticated fetch
│ │ └── styles/ # Global CSS
│ ├── astro.config.mjs
│ ├── tailwind.config.mjs
│ └── package.json
│
├── migrations/ # SQL migrations
│ ├── 20231026000000_initial_schema.sql
│ ├── 20240109120000_add_auth_tables.sql
│ └── MIGRATIONS.md # Migration policy
│
├── docs/ # Documentation
│ ├── Documentation.md # This file
│ └── GPU_PASSTHROUGH.md # GPU setup guide
│
├── .github/
│ └── workflows/
│ └── docker.yml # CI/CD pipeline
│
├── Cargo.toml # Rust dependencies
├── Cargo.lock
├── Dockerfile # Container build
├── VERSION # Version tracking
├── README.md
└── config.toml # Runtime config
Building
Backend (Rust)
# Development build (fast compile, debug symbols)
cargo build
# Release build (optimized, slower compile)
cargo build --release
# Check for errors without building
cargo check
# Run tests
cargo test
# Run with debug logging
RUST_LOG=debug cargo run -- --server
# Run in production mode
./target/release/alchemist --server
Frontend (Astro + React)
cd web
# Install dependencies with Bun
bun install
# Development server with hot reload (port 4321)
bun run dev
# Production build (outputs to dist/)
bun run build
# Preview production build
bun run preview
# Type check
bun run astro check
Docker Build
# Full Docker build
docker build -t alchemist .
# Build with no cache (clean build)
docker build --no-cache -t alchemist .
# Build for specific platform
docker build --platform linux/amd64 -t alchemist .
Code Style
Rust
- Follow standard Rust formatting:
cargo fmt - Run clippy for lints:
cargo clippy - Use
Result<T>for fallible operations - Prefer
anyhowfor error handling
TypeScript/React
- Use functional components with hooks
- Type all props with interfaces
- Use the
apiFetchutility for API calls - Follow Tailwind class ordering conventions
Adding a New API Endpoint
- Add route in
src/server.rs:
.route("/api/my/endpoint", get(my_handler))
- Implement handler:
async fn my_handler(State(state): State<Arc<AppState>>) -> impl IntoResponse {
// Your logic here
axum::Json(serde_json::json!({"ok": true}))
}
- Update documentation in
docs/Documentation.md
Adding a New Database Table
- Create migration in
migrations/:
-- migrations/20260110000000_add_my_table.sql
CREATE TABLE IF NOT EXISTS my_table (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
- Add struct in
src/db.rs:
#[derive(Debug, Serialize, Deserialize)]
pub struct MyRecord {
pub id: i64,
pub name: String,
pub created_at: DateTime<Utc>,
}
- Follow migration policy (see
migrations/MIGRATIONS.md)
Versioning
Version is tracked in two places that must stay in sync:
VERSIONfile (read by Docker workflow)Cargo.tomlversionfield
To release:
- Update both files to new version
- Commit:
git commit -m "v0.2.5: Description" - Push to master (triggers Docker build)
Troubleshooting
Common Issues
"Failed to load settings" / 401 Unauthorized
Cause: Auth token not being sent with API requests.
Solution: Clear browser localStorage and re-login:
localStorage.removeItem('alchemist_token');
window.location.href = '/login';
"No hardware encoder detected"
Cause: GPU drivers or container configuration issue.
Solution:
- Verify FFmpeg has hardware support:
ffmpeg -encoders | grep -E "nvenc|qsv|vaapi" - For Docker, ensure GPU passthrough is configured (see GPU_PASSTHROUGH.md)
- Check driver installation on host
Jobs stuck in "queued" state
Cause: Engine paused or scheduler not running.
Solution:
- Check engine status:
GET /api/engine/status - Resume if paused:
POST /api/engine/resume - Check logs for errors
High CPU usage during encoding
Cause: CPU fallback active instead of GPU.
Solution:
- Verify GPU encoder available
- Check
concurrent_jobssetting (reduce if needed) - Consider using "speed" quality profile
Database locked errors
Cause: Multiple processes accessing SQLite simultaneously.
Solution:
- Ensure only one Alchemist instance is running
- Check for zombie processes:
ps aux | grep alchemist - Delete lock file if stuck:
rm data/*.lock
Files being skipped unexpectedly
Cause: Analysis determined transcode wouldn't be beneficial.
Solution:
- Check the decision log in
/logsfor the reason - Common reasons:
- File already has low BPP (already optimized)
- File smaller than
min_file_size_mb - Estimated savings below threshold
- Adjust thresholds in Settings if needed
Output files larger than original
Cause: This shouldn't happen - Alchemist should auto-revert.
Solution:
- Check
size_reduction_thresholdsetting (default 30%) - If revert failed, check disk space
- Report as bug if persists
VMAF scores not appearing
Cause: VMAF calculation requires libvmaf in FFmpeg.
Solution:
- Check FFmpeg has VMAF:
ffmpeg -filters | grep vmaf - Install FFmpeg with VMAF support
- VMAF is optional - encoding works without it
"Connection refused" on port 3000
Cause: Server not running or bound to different address.
Solution:
- Check if process is running:
ps aux | grep alchemist - Check bound address in config (default
0.0.0.0:3000) - Check firewall rules
- For Docker: ensure port is mapped (
-p 3000:3000)
Log Locations
| Environment | Path | Command |
|---|---|---|
| Binary | stdout/stderr | Redirect with 2>&1 |
| Docker | Container logs | docker logs alchemist |
| Docker (follow) | Live logs | docker logs -f alchemist |
| Systemd | Journal | journalctl -u alchemist |
| Systemd (follow) | Live journal | journalctl -fu alchemist |
Debug Mode
Run with verbose logging to diagnose issues:
# Binary
RUST_LOG=debug ./alchemist --server
# Docker
docker run -e RUST_LOG=debug ...
Log levels: error, warn, info, debug, trace
FAQ
General
Q: What video formats does Alchemist support?
A: Input: Any format FFmpeg can read (MKV, MP4, AVI, MOV, WMV, FLV, WebM, etc.) Output: Same container as input, with AV1 or HEVC video codec.
Q: Will transcoding affect audio or subtitles?
A: No. Audio and subtitle streams are copied unchanged (-c:a copy -c:s copy).
Q: How long does transcoding take?
A: Depends on file size, resolution, and encoder:
- GPU (NVENC): ~50-300 fps for 1080p
- CPU (SVT-AV1): ~5-30 fps for 1080p
A 2-hour 1080p movie takes roughly 30min (GPU) or 3-4 hours (CPU).
Q: Does Alchemist delete original files?
A: Only after successful transcode AND if the output meets quality/size thresholds. Originals are preserved until fully validated.
Quality
Q: What VMAF score is acceptable?
A:
- 95+: Virtually identical to original
- 90-95: Imperceptible quality loss
- 85-90: Minor loss, acceptable for archival
- <85: Noticeable degradation
Alchemist targets 93+ by default.
Q: What's the difference between quality profiles?
| Profile | Speed | Size | Quality |
|---|---|---|---|
| Quality | Slowest | Smallest | Best |
| Balanced | Medium | Medium | Good |
| Speed | Fastest | Largest | Acceptable |
Q: AV1 vs HEVC - which should I use?
| Factor | AV1 | HEVC |
|---|---|---|
| Compression | 20-30% better | Good |
| Encode Speed | Slower | Faster |
| Hardware Support | Newer GPUs only | Wide support |
| Playback | Modern devices | Almost everything |
Use AV1 if you have compatible hardware. Use HEVC for maximum compatibility.
Storage & Performance
Q: How much space will I save?
A: Typical savings:
- Old H.264 content: 40-60% smaller
- Already optimized content: 10-20% or skipped
- 4K HDR: 30-50% smaller
Q: Will transcoding impact my system performance?
A:
- GPU encoding: Minimal CPU impact, GPU at 50-100%
- CPU encoding: High CPU usage (configurable via
concurrent_jobs) - RAM: ~500MB per concurrent job
- Disk I/O: Read/write proportional to file size
Q: How do I limit resource usage?
Set concurrent_jobs = 1 in settings for minimal system impact.
Docker
Q: How do I persist data across container restarts?
A: Mount a volume for /app/data:
docker run -v alchemist_data:/app/data ...
Q: Container can't see my media files?
A: Mount your media directory:
docker run -v /path/on/host:/media ...
Q: How do I update to a new version?
docker pull ghcr.io/brooklynloveszelda/alchemist:latest
docker stop alchemist
docker rm alchemist
docker run ... # same options as before
Technical
Q: Does Alchemist support HDR?
A: Yes, HDR metadata is preserved during transcoding.
Q: Can I run multiple instances?
A: Not recommended. Use a single instance with multiple scan directories.
Q: Is there an API rate limit?
A: No rate limiting on the local API. All endpoints respond instantly.
Q: How does authentication work?
A:
- Login with username/password → receive JWT token
- Token stored in localStorage
- Token sent as
Authorization: Bearer <token>header - Tokens expire after 7 days
Changelog
v0.2.6-beta
- ✅ Setup wizard now authenticates scan and hardware calls to prevent endless loading
- ✅ Scheduler window validation and normalized time handling
- ✅ File watcher no longer blocks on bursty filesystem events
- ✅ DB stability pass: WAL + busy timeout + foreign keys enabled
- ✅ Legacy watch directory schemas now supported at runtime
- ✅ Session cleanup task to prevent DB growth
- ✅ New DB indexes for faster jobs/logs/schedule/notifications queries
- ✅ Reqwest switched to rustls for cross-compiles without OpenSSL
- ✅ Cross-platform build script (bun + zig + cargo-xwin)
- ✅ Design philosophy added for consistent development standards
v0.2.5 (Current)
- ✅ Async runtime reliability improvements (spawn_blocking for ffprobe/VMAF/hardware detection)
- ✅ Accurate encode_speed and avg_bitrate_kbps metrics computed from actual media duration
- ✅ GPU utilization monitoring in dashboard
- ✅ Public /api/health and /api/ready endpoints for container orchestration
- ✅ CPU encoding toggle in hardware settings
- ✅ Output path refresh on config changes
v0.2.3
- ✅ Database migration policy (backwards compatible from this version)
- ✅ Schema version tracking
- ✅ Auth token injection for API calls
- ✅ Statistics dashboard with charts
- ✅ Docker workflow improvements
v0.2.2
- Initial public release
- Core transcoding engine
- Web dashboard
- Multi-theme support
License
Alchemist is licensed under the MIT License.
MIT License
Copyright (c) 2024 BrooklynLovesZelda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Getting Help
- GitHub Issues: github.com/BrooklynLovesZelda/alchemist/issues
- Logs: Use
/logsin web UI for real-time diagnostics - Documentation: You're here! 📖
Documentation for Alchemist v0.2.6-beta • Last updated: January 2026