Compressatorium

Compressatorium

Docker app from pacnpal's Repository

Overview

Compressatorium is a multi-tool game disc image converter with a web UI. Supports CHDMAN (CD/DVD/LaserDisc to CHD), Dolphin-tool (GameCube/Wii ISO/GCZ/WIA/RVZ/WBFS), and z3ds_compressor (3DS ROM compression). Features batch conversion with progress tracking, nested directory scanning, compressed archive support (ZIP, 7z, RAR), smart duplicate handling, verification, and a REST API. Mount multiple volumes under /data/ to organize different game libraries (e.g. /data/library1, /data/library2).

Compressatorium

Fork notice: This is a fork of MarcTV's Docker CHD Converter. It adds a Web UI and more conversion tools on top of the original CLI converter. Thanks to MarcTV for the original.

A game image converter that wraps seven tools: CHDMAN (MAME), dolphin-tool (Dolphin Emulator), z3ds_compressor (Nintendo 3DS), nsz (Nintendo Switch), maxcso (PSP/PS2 CSO/ZSO), 7z (handheld ROM archives), and makeps3iso (PS3 decrypted folder → ISO). Pick the tool that matches your files and convert from a browser, or run it headless from the command line.

Features

  • Seven tools in one. CHDMAN, Dolphin, 3DS, Switch, CSO/ZSO, handheld ROM (GB/GBC/GBA/DS), or PS3 ISO (a decrypted PS3 folder packed to .iso), chosen per job.
  • Web UI for browsing files and converting them. The tool picker filters the whole interface down to the tool you chose.
  • Nested directories and archives. Browse subfolders and look inside ZIP, 7z, and RAR archives.
  • Multiple volume mounts so you can keep separate game libraries separate.
  • File detection that works out which files each tool can convert.
  • Existing-output detection with skip, rename, or overwrite.
  • Delete-on-verify. Optionally remove the source after a conversion verifies. Off by default.
  • Progress tracking through a live job queue.
  • File info for CHD, Dolphin, 3DS, Switch, CSO, and handheld ROM files.

Supported Conversions

Tool Platform / Use Input Formats Output Formats Compression Control External Keys Binary
CHDMAN CD / DVD / HD / LaserDisc discs .gdi, .cue, .bin, .iso, .chd .chd, .cue, .bin, .iso, .raw, .avi Codec list (zstd, zlib, …) None mame-tools
Dolphin GameCube / Wii discs .iso, .wbfs, .rvz, .wia, .gcz .rvz, .wia, .gcz, .iso Codec + numeric level None dolphin-emu
3DS Nintendo 3DS ROMs .cci, .cia, .3ds, .cxi, .3dsx, .zcci, .zcia, .z3ds, .zcxi, .z3dsx .zcci, .zcia, .z3ds, .zcxi, .z3dsx, .cci, .cia, .3ds, .cxi, .3dsx None (fixed) None z3ds_compressor
Switch Nintendo Switch dumps .nsp, .xci, .nsz, .xcz .nsz, .xcz, .nsp, .xci Layout + level Yes (prod.keys) nsz
CSO PSP / PS2 game images .iso, .cso, .zso, .dax .cso, .zso, .dax, .iso, .chd Effort preset (Fast/Default/Max); the cso_to_chd chain ignores it and uses chdman defaults None maxcso (+ chdman for cso_to_chd)
Handheld ROM Game Boy / GBC / GBA / DS ROMs .gb, .gbc, .gba, .nds, .7z, .zip .7z, .zip, .gb, .gbc, .gba, .nds Effort preset (Fast/Default/Max) None 7z (p7zip-full)
PS3 ISO Decrypted PS3 disc / JB folders a folder containing PS3_GAME/ (plus PS3_DISC.SFB for disc rips) .iso (optional 4 GB FAT32 split) None (fixed) None makeps3iso

Most conversions above are lossless and fully reversible, including 3DS, which now decompresses back to the original ROM as well. This uses z3ds_compress (a fork that adds a decompression mode and .cxi/.3dsx support to the original energeticokay/z3ds_compress). The compressed .z3ds can be read directly by Azahar, or restored to .cci/.cia/.3ds with z3ds_decompress; see Nintendo 3DS Support.

PS3 ISO is the clearest exception to the round trip. It packs a decrypted PS3 folder into a .iso that RPCS3 mounts directly; there is no reverse mode back to a folder, and it never deletes the source. See PlayStation 3 Support.

The CSO tool also has a one-step chain, cso_to_chd, that runs a .cso/.zso/.dax through maxcso to a temporary .iso and then chdman to a .chd in a single job. The disc image survives losslessly, but this one changes container: extracting the resulting .chd gives you an .iso, not the original .cso/.zso/.dax, so delete-on-verify here trades the compressed source for a CHD. See PSP / PS2 Support.

Each tool's full mode list (e.g. CHDMAN's createcd/extractcd, CSO's cso2_compress, the ROM packer's romz_7z/romz_zip/romz_extract, and the PS3 packer's folder_to_iso) is in Supported Operations.

Archive inputs: most input formats above can be converted straight from inside a ZIP, 7z, or RAR archive, including 3DS ROMs, Dolphin game images, and Switch dumps. Browse into the archive, pick a member, and convert. This even covers CHDMAN's extract modes pulling a .chd out of an archive and decompressing it back to a game image. A few exceptions: CHDMAN's copy/recompress mode is not offered from an archive (recompressing an already-finished .chd would be a pointless round trip); Handheld ROM does not accept loose ROMs from inside an archive — its .7z/.zip are the packed product, so to unpack one select the archive file itself and run romz_extract, rather than browsing into it for a member; and PS3 ISO takes a folder, not a file, so it is never an archive input (a zipped PS3_GAME tree can't be converted from inside an archive).

MAME Redump DAT Integration

Compressatorium can sync MAME Redump DAT files (Logiqx XML) in one click and check your compressed files against known-good Redump hashes. The same hashes let tools like Hasheous and RomM match your library.

  • One-click sync: Click "Sync from MAME Redump" in the DAT panel to download all ~69 DATs automatically from GitHub
  • Auto-sync: Set MAMEREDUMP_AUTO_SYNC=true to sync DATs on container startup when none are loaded
  • CHD files: Matched via the embedded header / data SHA1 (codec-independent, works with any compression setting on chdman 0.285)
  • Dolphin RVZ/WIA/GCZ: Matched via the game image's content SHA1 reconstructed by dolphin-tool verify — the same hash MAME Redump records for GameCube/Wii discs — so compressed Dolphin outputs match without the container bytes having to be identical
  • Everything else (3DS/Switch/CSO·ZSO·DAX/.iso/.bin): Matched via file-level SHA1
  • Library scan: The background scan discovers and DAT-matches tool outputs by extension (CHD, Dolphin RVZ/WIA/GCZ, 3DS, Switch, CSO/ZSO, .iso, and the .bin data track from CHDMAN extract), not just CHDs, so non-CHD libraries get cached match results too. A single PS3-packed .iso is matched like any other .iso; a 4 GB split set is not, since its .iso.0/.iso.1 parts aren't scanned extensions. Heavy Dolphin disc-hashing during the scan honors MATCH_MAX_FILE_SIZE and stops promptly if you cancel the scan.
  • DAT management: Import, list, and delete DATs via the web UI "DAT Files" button
  • Match badges: Files matching a DAT entry show a blue "DAT" badge in the file list

Installation

The Docker image is available from two registries:

Docker Hub

docker pull pacnpal/compressatorium

GitHub Container Registry

docker pull ghcr.io/pacnpal/compressatorium

Both registries provide identical images with multi-architecture support (linux/amd64 and linux/arm64).

Note: Use either registry: replace pacnpal/compressatorium with ghcr.io/pacnpal/compressatorium for the same image.

Available Tags

Tag Description
latest Latest stable release
beta Latest pre-release build (see warning below)
X.Y.Z Specific stable version (e.g., 3.7.0)
X.Y.Z-beta-N Specific pre-release build (e.g., 3.7.0-beta-3)
sha-xxxxxxx Specific commit build

Opting in to beta updates

To track pre-release builds, pull the :beta tag instead of :latest:

docker pull pacnpal/compressatorium:beta

Or pin to a specific pre-release (recommended if you want to control when you upgrade):

docker pull pacnpal/compressatorium:3.7.0-beta-3

Warning: beta builds can cause data loss. Pre-releases may carry unfinished migrations, experimental conversion logic, or breaking changes to the job database. Running a beta against a database that a stable release created can corrupt it or migrate it past the point of return, and downgrading back to :latest afterwards is not supported. Before you pull :beta:

  • Back up your SQLite database (compressatorium.db in your data volume) and any in-flight output files.
  • Prefer a separate data volume for beta testing rather than pointing a beta container at your production volume.
  • Do not use beta builds for batches you cannot afford to redo.

Quick Start Guide

1. Select Your Primary Tool

When you open the Web UI, you'll see the tool options at the top:

  • CHDMAN - For converting CD/DVD/LaserDisc images to CHD format
  • Dolphin - For GameCube/Wii game image conversions
  • 3DS - For compressing Nintendo 3DS ROMs
  • Switch - For compressing/decompressing Nintendo Switch dumps (needs your own prod.keys)
  • CSO - For compressing/decompressing PSP/PS2 ISO images to CSO/ZSO (and a one-step CSO → CHD chain)
  • Handheld ROM - For compressing/extracting GB/GBC/GBA/DS ROM dumps to .7z/.zip archives
  • PS3 ISO - For packing a decrypted PS3 folder into a .iso RPCS3 can mount

Choose the tool that matches your files. The interface then shows only the modes and file types that tool can use.

2. Browse and Select Files

  • Navigate through your mounted volumes using the left panel
  • Click on folders to browse subdirectories
  • Check the boxes next to files you want to convert
  • Archives (.zip, .7z, .rar) can be browsed by clicking them
  • With the PS3 ISO tool selected, a decrypted PS3 folder is itself selectable as a source (clicking its name still browses into it); the rest of the tools take files

3. Configure and Convert

  • Select the appropriate conversion mode from the dropdown
  • Adjust compression settings if available (see Compression Settings)
  • Click the action button (Create/Convert/Compress depending on mode)
  • Monitor progress in the job queue panel

Usage Guide

This is the global guide to the workflow and the features shared by every tool — browsing, modes, compression, verifying/deleting, archives, DAT matching, and troubleshooting. The per-tool sections further down only document what's specific to each tool (its formats, modes, env vars, and quirks). The same material is available in-app under Help.

Browsing and finding files

Your mounted volumes appear in the left panel — click a folder to enter, a breadcrumb to go back. Search All walks the whole volume and lists every convertible file at once; the filter dropdown narrows by extension. Both update automatically as tools are added. System clutter (.DS_Store, AppleDouble ._* files, Thumbs.db, desktop.ini, @eaDir, #recycle, lost+found, …) is hidden so listings stay clean.

Modes

Create makes a compressed file, extract/decompress gives the original back, copy recompresses in place. Pick the create mode that matches the media — compressing a PSP/PS2 image with createcd instead of createdvd won't come out right. The full mode list per tool is in Supported Operations.

Compression settings

Every tool that compresses (CHD, Dolphin, Switch, CSO) shares one compression picker in the convert panel:

  • Controls differ per tool. chdman takes a codec list, Dolphin and Switch take a single codec/layout plus a numeric level, and CSO takes a Fast/Default/Max effort preset (no numeric level). Decompress/extract modes and 3DS have no compression settings, so the picker is hidden for them.
  • Your choice is remembered server-side per tool, so it follows you across sessions and browsers.
  • Reset to default. A button under the picker restores that tool's codec/layout/level/effort to its default and confirms with a toast. It's disabled when you're already on the defaults.
  • Strong defaults where it helps. CSO defaults to the Max preset (smallest output); the other tools default to broadly-compatible settings (chdman zlib, Dolphin zstd:19, Switch solid:18). See also Compression Compatibility Tips.

Output location and duplicates

By default the output lands next to its source; set a custom output directory instead and it's created for you as long as it's inside a mounted volume. If a matching output already exists the app stops and asks rather than clobbering it: skip keeps the existing file, rename writes under a new name, overwrite replaces it.

The job queue

Every conversion and verify runs through one FIFO queue — one job at a time by default, which keeps the host responsive during big batches. Progress streams live, and jobs run on the server, so closing the browser (or rebooting your laptop) doesn't stop them; reopen the page and it reconnects. The queue has active / completed / failed tabs, plus Cancel All and Clear Done (both confirm first).

Verifying and deleting safely

Converting never deletes anything on its own — the safe order is convert, verify, then delete the source. Verify reads the whole output back and checks it against the file's own hashes/CRC; with delete-on-verify the source is removed only after the output passes, and never if it fails. You get a confirmation list of everything to be deleted first, including the .cue/.gdi track files that ride with a .bin, and the whole archive if the source came from one. Bulk Verify checks a whole selection at once across CHD, Dolphin, 3DS, Switch, and CSO; verification status persists between sessions, and a long verify can be given a timeout so a stalled one doesn't block the queue.

File info

Click a file to open the inspector — it shows the format/version, compression, size, and hashes, plus the raw tool output. For PS1/PS2/PSP/Dreamcast discs it also digs the game serial out of the sector data and shows a human title when it recognizes one. A background scan caches this so the list badges don't recompute on every folder open.

DAT matching

Sync the MAMERedump DATs from the DAT Library (or import your own .dat/.xml from No-Intro/Redump) and converted files are checked against known-good hashes — a blue DAT badge means the file matches. CHDs match on the codec-independent header SHA1, and Dolphin RVZ/WIA/GCZ match on the game image's content SHA1 reconstructed by dolphin-tool verify --algorithm sha1 (the same hash Redump records), so any compression setting still matches for both. A missing badge usually means the DATs aren't synced, the title isn't in the DAT, or the file is larger than MATCH_MAX_FILE_SIZE (which skips the expensive full-disc reconstruction) — not that the file is bad.

Archives

Browse straight into a ZIP, 7z, or RAR and convert a file from inside it — no need to extract first. The member is unpacked to a temp dir for the conversion and cleaned up afterwards. Any convertible source works this way (CHD create, Dolphin, 3DS, Switch, and CSO — Switch still needs your own prod.keys), and CHDMAN's extract modes can even pull a .chd out of an archive and decompress it back to a game image. CHDMAN's copy/recompress mode is the exception: it acts on a finished .chd, and recompressing one straight out of an archive is a pointless round trip, so it's not offered there. Handheld ROM and PS3 ISO also don't take archive inputs: the ROM packer's .7z/.zip are its product, and PS3 ISO's input is a folder, not a file.

Why only certain files show inside an archive

Browsing into an archive does not list everything it contains. It lists the file types the app knows — every extension that some tool recognizes as a convertible source (.iso, .cue/.bin, .gdi, .gcz/.wia/.rvz/.wbfs, .cci/.cia/.3ds/.cxi/.3dsx, .nsp/.xci, .cso/.zso/.dax, the handheld ROMs .gb/.gbc/.gba/.nds, …) plus a .chd you can decompress in place. Anything else is hidden, on purpose:

  • Unknown files are filtered out. Read-me text, .nfo/.sfv files, box art, manuals, save states — none of it is something the app can convert or verify, so it would only be clutter in the browser. The listing is global, scoped to known extensions: a member shows up if and only if its extension is one the app understands, regardless of which tool you currently have selected.
  • Nested archives are hidden. A .zip inside a .zip (or .7z/.rar) is not listed — there's no point browsing an archive within an archive.
  • OS/NAS clutter is ignored. macOS __MACOSX/… resource forks, .DS_Store, Thumbs.db and the like never appear, so a ROM zipped on a Mac or Windows box still reads as a clean single-file archive.

Some members that are shown still can't be converted from inside the archive, and the UI badges them non-convertible:

  • A handheld ROM packed by this app (Game.gba inside Game.gba.7z) is shown so you can see and verify it, but it isn't offered for re-conversion — recompressing an already-archived ROM would just be packing a .7z into another .7z. To unpack it, select the archive file itself and run romz_extract.
  • A .chd inside an archive can be decompressed in place (chdman's extract modes), but it can't be recompressed — it's already a finished CHD, so chdman's copy/recompress mode is deliberately not offered from an archive.

In short: if a file you expect isn't in the list, it's almost always because its extension isn't one of the convertible/verifiable types the app handles. Loose files on disk follow the same rule — the file list filters to the types the selected tool understands.

Troubleshooting

  • An emulator won't read the CHD — almost always the codec; recompress with zlib only using copy mode (see Compression Compatibility Tips).
  • "Output already exists" — pick skip / rename / overwrite; nothing is replaced unless you choose overwrite.
  • A conversion stalls — big files are slow; an adaptive stall timeout scales with input size, and the queue has a recovery action. Check temp-dir space/speed.
  • A file didn't show up — make sure the right tool is selected (the list filters to it); try Search All or clear the extension filter.
  • An ISO went to the wrong tool — ISOs can belong to CHDMAN or Dolphin; set the ISO Handling toggle to match the disc.
  • The Switch tool is missing or jobs ask for prod.keys — it needs your own keys; see Nintendo Switch Support. Without keys the tool is hidden.

Web UI Mode (Default)

The web interface is the easiest way to run Compressatorium:

docker run -d \
  -p 8080:8080 \
  -e PUID=$(id -u) \
  -e PGID=$(id -g) \
  -v /path/to/config:/config \
  -v /path/to/games:/data/games \
  pacnpal/compressatorium

Then open http://localhost:8080 in your browser.

Required: The /config volume must be mounted for persistent data storage.
Volume discovery: If COMPRESSATORIUM_VOLUMES is unset, the app scans /data/* at startup and auto-registers mounted game volumes (restart after mount changes).
Ownership (optional): Set PUID/PGID to match your host user/group (for example Unraid 99:100). If unset, defaults remain 999:999.
Default temp location: /config/temp. To use a different location, set CHD_TEMP_DIR and mount it.

Multiple Volumes

Mount multiple game directories for better organization:

docker run -d \
  -p 8080:8080 \
  -v /path/to/config:/config \
  -v /home/user/dreamcast:/data/dreamcast \
  -v /home/user/psp:/data/psp \
  -v /home/user/ps1:/data/ps1 \
  pacnpal/compressatorium

Custom Output Directory

In the Web UI, you can specify a custom output directory for converted CHD, Dolphin, or 3DS outputs instead of placing them alongside the source files. The directory will be created automatically as long as it is within your configured volumes.

Screenshots

The Web UI ships with light and dark themes and is fully responsive from desktop down to phones. Each surface below is shown as a light / dark pair.

These screenshots are generated automatically. The Take screenshots GitHub Actions workflow builds the UI, runs it against a throwaway fixture library, captures each surface with shot-scraper (definitions in shots.yml), optimises the PNGs with Oxipng, and commits the results back to docs/screenshots/. To refresh them, trigger that workflow (or run it locally — see docs/SCREENSHOTS.md).

Workspace

A three-pane layout: navigation and tool picker on the left, the volume and file browser in the middle, and a live convert panel with the job queue on the right. Selecting a tool refilters the file list and the convert options to match.

Light Dark
Workspace · CHDMAN, light Workspace · CHDMAN, dark

Batch selection. Tick multiple files and the convert panel arms itself, showing how many sources are queued and a one-click Start conversion.

Light Dark
Batch selection, light Batch selection, dark

Dolphin (GameCube / Wii). Compress discs to RVZ, WIA, or GCZ, with a codec and compression-level picker.

Light Dark
Dolphin tool, light Dolphin tool, dark

3DS. Compress .cci, .cia, and .3ds ROMs with z3ds_compressor.

Light Dark
3DS tool, light 3DS tool, dark

Dashboard

An at-a-glance view of the job queue, verification cache, mounted volumes, recent conversions, and quick tool shortcuts.

Light Dark
Dashboard, light Dashboard, dark

DAT Library

Import or sync No-Intro / Redump / MAMERedump datasets and match converted files against known-good hashes.

Light Dark
DAT Library, light DAT Library, dark

Help

In-app reference for tools, formats, compression, and verification.

Light Dark
Help, light Help, dark

Responsive layouts

The interface reflows cleanly across breakpoints:

Desktop (1280px)

Desktop View

Tablet (768px)

Tablet View

Mobile (375px)

Mobile View

On small screens the file list switches to a card layout. Controls use 44 to 48px touch targets, inputs go full width, and the spacing opens up so it stays usable on a phone.

Features

File Browser

  • Navigate through mounted volumes and subdirectories
  • View file sizes, types, ISO handling, and CHD status indicators
  • Recursive search to find all convertible files across the entire volume

Archive Support

  • Browse inside ZIP, 7z, and RAR archives without extraction
  • Convert files directly from within archives
  • Archives extract temporarily during conversion, then clean up automatically
  • When a .cue/.gdi is present in the same archive folder, .bin entries are suppressed and batch jobs are deduplicated by output path to avoid stalled conversions.
  • Archive listings include safety limits (max entries/size) and expose truncation metadata when limits are hit.
  • Browsing is global, scoped to known extensions. When you look inside an archive, the listing shows every member whose extension is one the app understands — every tool's convertible source plus a .chd you can decompress — regardless of which tool is currently selected. That covers CHDMAN (.gdi/.iso/.cue/.bin), Dolphin (.iso/.gcz/.wia/.rvz/.wbfs), 3DS (.cci/.cia/.3ds/.cxi/.3dsx), Switch (.nsp/.xci), CSO (.iso/.cso/.zso/.dax), and Handheld ROM (.gb/.gbc/.gba/.nds). Archive members appear for whichever tool accepts them, exactly like on-disk files.
  • Why everything else is hidden. Unknown files (text, .nfo/.sfv, cover art, manuals), nested archives (a .zip inside a .zip), and OS/NAS clutter (__MACOSX/…, .DS_Store, Thumbs.db) are filtered out — they aren't convertible or verifiable, so listing them would only be noise. See Archives → Why only certain files show inside an archive.
  • Some shown members are view-only. A handheld ROM this app packed (Game.gba inside Game.gba.7z) is listed for visibility/verification but not offered for re-conversion (recompressing an archived ROM would be recursive); unpack it by selecting the archive and running romz_extract. A .chd inside an archive can be decompressed in place but not recompressed (copy/recompress acts on a finished output). Such members are badged non-convertible.
  • The inputs that can't come from an archive are CHDMAN's copy/recompress mode (recompressing an already-finished .chd would be a pointless round trip, though the extract modes can decompress a .chd straight out of an archive), Handheld ROM compression, whose .7z/.zip are the packed product, and PS3 ISO, whose input is a folder rather than a file (a zipped PS3_GAME tree can't be selected from inside an archive).

ISO Handling & Dolphin Tools (GameCube/Wii)

  • Toggle ISO handling between CHDMAN and Dolphin (controls ISO info/verify and conversions)
  • Convert .iso, .gcz, .wia, .rvz, .wbfs with dolphin-tool (RVZ/WIA/GCZ/ISO output)
  • Disc info and verification for Dolphin formats (including batch verification)
  • Dolphin sources may be converted directly from inside ZIP/7z/RAR archives (extracted to a temp dir for the conversion, then cleaned up)

Batch Conversion

  • Select multiple files and convert them all at once
  • Queue-based processing (FIFO), defaulting to serial execution (MAX_CONCURRENT_JOBS=1)
  • Real-time progress tracking via Server-Sent Events
  • Duplicate detection with options to skip, rename, or overwrite
  • Optional delete-on-verify with a preflight confirmation list (includes .cue/.gdi track files)
  • Archive conversions can delete the entire archive after verify (explicit warning in the delete plan)
  • Job manager controls include Cancel All and Clear Done, both guarded by confirmation dialogs

Bulk Operations

  • Bulk Delete: Delete multiple selected files at once
  • Bulk Verify: Verify integrity of multiple CHD + Dolphin images simultaneously
  • Sorts sources by whether they already have a CHD backup
  • Warnings for files without verified CHD backups before deletion

Verification

  • Verify CHD files using chdman's built-in verification
  • Verify GameCube/Wii game images using dolphin-tool (ISO uses Dolphin when ISO handling is set to Dolphin)
  • Verification status persisted across sessions (stored in /config/verified_chds.json)
  • Integrated verification workflow when deleting source files
  • Visual indicators showing verified vs unverified items
  • Optional timeouts for long-running verifications and stalled progress

CHD Inspector

  • View detailed CHD file information (version, compression, size, hashes)
  • SHA1 and Data SHA1 checksums displayed
  • Raw chdman output available for advanced inspection
  • Dolphin disc info shows game ID, region, format, compression, and raw output
  • Game ID and title. PS1, PS2, PSP, and Dreamcast serials are read from CHD sector data (SYSTEM.CNF, PARAM.SFO, IP.BIN) and shown in the info modal, with human-readable titles when available (for example "Patapon", "DEAD OR ALIVE 2")

CHD Metadata Cache

  • Background metadata scan with CD/DVD badges
  • Retroactive game ID tagging. The scan writes GAME and NAME tags into existing CHDs that lack them. Later scans skip files that are already tagged
  • "Scan Metadata" and "Force Rescan" actions to refresh cached metadata
  • Cache stored in /config/chd_metadata.json

File Management

  • Rename files and directories
  • Delete files with safety checks (warns about missing CHD backups)
  • Empty directory cleanup

Conversion Modes

  • Create CHD: createcd (CD), createdvd (DVD/PSP/PS2), createraw, createhd, createld
  • Extract from CHD: extractcd, extractdvd, extractraw, extracthd, extractld
  • Copy/Recompress: Recompress existing CHD files with different codecs
  • Dolphin (GameCube/Wii): dolphin_rvz, dolphin_wia, dolphin_gcz, dolphin_iso

Compression Options

  • Choose from multiple compression codecs: zlib, zstd, lzma, huff, flac, avhu (A/V Huffman)
  • CD-specific codecs: cdzl, cdzs, cdlz, cdfl (CD images only)
  • No compression option for maximum compatibility (-c none)
  • Select up to 4 codecs per conversion (CHD only)
  • Dolphin modes accept one codec + optional level (RVZ/WIA), while GCZ/ISO ignore compression

Dolphin Emulator Support (GameCube/Wii)

Dolphin support is available in the Web UI and REST API (CLI mode remains CHDMAN-only).

Supported inputs: .iso, .gcz, .wia, .rvz, .wbfs
Output modes: dolphin_rvz (recommended), dolphin_wia, dolphin_gcz, dolphin_iso

Notes (shared workflow — compression, verify, archives — is in the Usage Guide)

  • Requires the Docker image with Dolphin installed (default image includes dolphin-emu + wrapper).
  • Dolphin conversions use dolphin-tool (configurable via DOLPHIN_TOOL_PATH).
  • Compression is a single codec plus an optional level (zstd:5, bzip2:5, lzma:5, lzma2:5); zstd:19 is the default. dolphin_gcz uses fixed compression (ignores the codec), and dolphin_iso outputs an uncompressed ISO.
  • ISO info/verify and conversions follow the ISO Handling toggle in the UI (no default — you must choose, since an ISO can belong to CHDMAN or Dolphin).

Nintendo 3DS Support

3DS ROM compression and decompression are available in the Web UI and REST API using z3ds_compress — a fork of the original energeticokay/z3ds_compress that adds a decompression mode and support for .cxi/.3dsx files.

Select 3DS as the primary tool, pick your files, and choose a mode: Compress 3DS (z3ds_compress) packs a raw ROM, and Decompress 3DS (z3ds_decompress) restores the original ROM from a Z3DS file. The general workflow (queue, verify, delete-on-verify, archives) is in the Usage Guide; the 3DS-specific bits are below.

Round-trip is lossless. The compressed .z3ds/.zcci/.zcia is a seekable-Zstandard container that Azahar reads directly, and it can be decompressed back to a byte-identical original. Direction is chosen by the mode (we pass the tool's explicit -c/-d flag), so it never depends on guessing from the file contents.

Supported File Formats

Compress inputs (raw ROMs):

  • .cci - CCI (CTR Card Image) format - Nintendo 3DS cartridge dumps
  • .cia - CIA (CTR Importable Archive) format - Installable packages, updates, DLC
  • .3ds - Alternative extension for cartridge dumps (identical to .cci, can be renamed)
  • .cxi - CXI (CTR Executable Image) - experimental
  • .3dsx - 3DSX homebrew executable - experimental

Compressed outputs / decompress inputs (Z3DS containers):

  • .zcci.cci
  • .zcia.cia
  • .z3ds.3ds
  • .zcxi.cxi
  • .z3dsx.3dsx

Important Note: The .3ds and .cci formats are functionally identical - they're both cartridge dump formats with different file extensions. You can freely rename between them. The z3ds_compress tool supports both extensions and maintains the naming convention (.3ds → .z3ds, .cci → .zcci, and the reverse on decompress).

Technical Details

Compression method: Seekable ZStandard (256KB frame size)
Size reduction: Typically ~50% without compatibility issues
Compression speed: Fast, single-threaded processing

Compatibility:

  • Compressed ROMs are natively supported by Azahar emulator (release 2123+)
  • .cci files: Thoroughly tested and production-ready
  • .cia files: Supported but considered experimental
  • .3ds files: Same as .cci - fully supported (they're the same format)

3DS-specific notes:

  • z3ds_compressor binary ships in the Docker image (Z3DS_COMPRESSOR_PATH=/usr/local/bin/z3ds_compressor), built from the pacnpal/z3ds_compress fork via CMake.
  • Compression settings are fixed — 3DS is the one tool with no compression picker.
  • ROMs must be decrypted before compression (encrypted ROMs will not work).
  • Decompression (z3ds_decompress) does not offer delete-on-verify: the restored ROM is not itself a verify-class file, so the compressed source can't be confirmed before deletion.

Environment Variables

Variable Default Description
Z3DS_COMPRESSOR_PATH /usr/local/bin/z3ds_compressor Path to z3ds_compressor binary

(Global vars — DAT sync, tool paths, priority — are in Environment Variables.)

REST API Endpoints

  • POST /api/jobs or POST /api/jobs/batch - Queue 3DS jobs (use mode: "z3ds_compress" or mode: "z3ds_decompress")
  • GET /api/z3ds-info?path=/path/to/rom.cci - Get file information (size, format, compression status)
  • GET /api/z3ds-verify?path=/path/to/rom.zcci - Verify compressed 3DS output integrity
  • GET /api/z3ds-verify/events?path=/path/to/rom.zcci - SSE stream for 3DS verify progress
  • POST /api/z3ds-verify-batch/events - SSE stream for batch 3DS verification

(DAT sync/import/match endpoints are shared — see API Endpoints.)


Nintendo Switch Support

Switch compression and decompression use nsz, the homebrew-standard tool. It shrinks .nsp/.xci dumps into .nsz/.xcz (40-80% smaller) and reverses the process. Compressed output stays installable in Tinfoil and DBI.

You must provide your own prod.keys. Switch game content (the NCA files inside an NSP/XCI) is encrypted, and encrypted data does not compress. nsz decrypts the content, compresses it, and stores how to re-encrypt it so decompression rebuilds a byte-identical original. That decrypt step needs your console's keys. This app ships no keys and nsz ships no keys. You supply your own, dumped from a console you own, for games you own. Without keys, the Switch tool is hidden from the UI entirely. See the legal note at the bottom of this section.

How to Use

Provide keys first (see Keys: setup and security) — the Switch tool only appears once prod.keys are found. Then select Switch, choose Compress (.nsp/.xci.nsz/.xcz) or Decompress, and convert. The general workflow is in the Usage Guide.

Supported File Formats

  • .nsp - Nintendo Submission Package (eShop-style dump)
  • .xci - Cartridge image (game card dump)
  • .nsz - Compressed NSP (zstandard over decrypted NCA content)
  • .xcz - Compressed XCI

Compress maps .nsp.nsz and .xci.xcz; decompress reverses it.

Compression (layout and level)

The Compress mode exposes two controls in the convert panel, per job:

  • Layout - Solid (best ratio; must be decompressed to run) or Block (slightly larger, but installable/playable without full decompression).
  • Level - the zstandard level, 1-22.

Your choice is remembered server-side (per tool), so it persists across sessions and browsers. NSZ_COMPRESSION_LEVEL is the fallback default when no per-job level is set. (See Compression Settings for the shared picker behavior, including the Reset-to-default button.)

Technical Details

  • nsz is installed from pip and runs as a subprocess (no shell). Verify uses nsz's own -V integrity check on the compressed container.
  • The compress/decompress round trip is lossless. nsz keeps all protection measures in place (the first 0x4000 bytes of each NCZ stay encrypted, and the NCZ header records how to re-encrypt), so decompression reproduces the original byte-for-byte.
  • Archive inputs work, but your own prod.keys are still required exactly as for on-disk files.

Keys: setup and security

  • Recommended: mount the directory holding your keys read-only and set SWITCH_KEYS to it:

    # docker-compose.yml
    services:
      compressatorium:
        environment:
          - SWITCH_KEYS=/keys           # directory containing prod.keys
        volumes:
          - /host/path/to/switch-keys:/keys:ro
    
  • SWITCH_KEYS is the source of truth when set (its directory is checked directly, then searched recursively). When unset, the app best-effort searches the standard locations (~/.switch, the nsz config dirs) and then recursively walks your mounted game volumes for a prod.keys/keys.txt, skipping junk dirs and bounded by a directory cap so a huge library can't stall startup. Set SWITCH_KEYS if your keys live very deep.

  • Keys are never baked into the image and are git-ignored, so a stray copy can't be committed. The file only needs to be readable by uid 999 (converter).

  • Keys are never logged.

Environment Variables

Variable Default Description
NSZ_PATH nsz Path to the nsz binary (resolved on PATH by default)
SWITCH_KEYS (unset) Directory holding your prod.keys. Source of truth when set; otherwise a best-effort search of ~/.switch and your volumes runs at startup.
NSZ_COMPRESSION_LEVEL 18 Fallback zstandard level (1-22) when no per-job level is set in the UI

REST API Endpoints

  • POST /api/jobs or POST /api/jobs/batch - Queue Switch jobs (use mode: "nsz_compress" or "nsz_decompress"; optional compression: "solid:18" / "block:20")
  • GET /api/nsz-info?path=/path/to/game.nsp - Get file information (size, format, compression status)
  • GET /api/nsz-verify?path=/path/to/game.nsz - Verify a compressed Switch output
  • GET /api/nsz-verify/events?path=/path/to/game.nsz - SSE stream for Switch verify progress
  • POST /api/nsz-verify-batch/events - SSE stream for batch Switch verification

Legal note

Compress only games you own, using keys you dumped from your own console. You are responsible for how you use this tool. The project distributes no Nintendo keys, firmware, or copyrighted game data.


PSP / PS2 Support (CSO / ZSO / DAX)

CSO/ZSO/DAX compression and decompression use maxcso, the standard PSP/PS2 ISO compressor. It shrinks .iso game images into .cso, .zso, or .dax (and reverses the process). PPSSPP (PSP) and PCSX2 (PS2) read these compressed formats directly, so the compressed file plays without a separate decompress step. No keys are required.

How to Use

Select CSO as the primary tool and pick a mode (the general workflow is in the Usage Guide):

  • Compress ISO → CSO (.iso.cso, CSO v1, the universally-supported default, deflate-based)
  • Compress ISO → CSO v2 (.iso.cso, CSO v2, better block alignment; needs a recent PPSSPP/PCSX2)
  • Compress ISO → ZSO (.iso.zso, lz4-based, faster to decode)
  • Compress ISO → DAX (.iso.dax, legacy PSP format)
  • Decompress CSO/ZSO/DAX → ISO (.cso/.zso/.dax.iso)
  • Convert to CHD (cso_to_chd: .cso/.zso/.dax.chd in one step)

CSO → CHD in one step. The cso_to_chd mode runs the whole chain as a single job: maxcso decompresses the compressed image to a temporary .iso, then chdman packages that to a .chd (PPSSPP, PCSX2, and RetroArch read the result). The intermediate .iso lives in a private temp dir and is cleaned up after, so only the source and the final .chd remain. Delete-on-verify works end to end: the original .cso is removed only after the final .chd passes chdman verification. If the .cso came from inside an archive, delete-on-verify removes the whole archive, not just that member, with a warning in the delete plan, the same as any archive-sourced conversion. Note this changes container, so it's a one-way trip: extracting the .chd later (chdman extractdvd) gives back the .iso, not the original .cso/.zso/.dax. The disc image is preserved, but the compressed source is not reproducible once deleted. Disc-ID GAME/NAME tags are embedded into the CHD just like a direct Create DVD. The chain uses chdman's default compression (there is no codec picker for it yet).

Supported File Formats

  • .iso - Raw PSP/PS2 game image (compress source)
  • .cso - Compressed ISO (CISO, deflate); CSO v1 and v2 share this extension
  • .zso - Compressed ISO (lz4, faster decompression)
  • .dax - Legacy compressed ISO (compress target and decompress source)

Technical Details

  • maxcso is built from source into the image and runs as a subprocess (no shell). Compression is lossless and fully reversible; the round trip reproduces the original .iso byte-for-byte. Verify runs maxcso's --crc over the compressed container (it decompresses the whole file and checks its CRC32).
  • The output format is chosen by the mode (CSO v1 --format default, CSO v2 --format=cso2, ZSO --format=zso, DAX --format=dax). Compress modes also take an effort preset — there is no numeric level (maxcso has none):
    • Fast - --fast (basic zlib/lz4): fastest, largest output.
    • Default - maxcso's default trials (zlib + 7zdeflate for the deflate-based CSO/CSO2/DAX formats, lz4hc for ZSO).
    • Max - smallest output, slowest: --use-zopfli --use-libdeflate for CSO/CSO2/DAX, --use-lz4brute for ZSO. CSO defaults to Max.
  • Which format? Use plain CSO (v1) when in doubt — every PPSSPP/PCSX2 reads it. Pick ZSO for fastest decode (lz4), CSO v2 for the best size on recent emulators, and DAX only for legacy tools that require it.
  • An .iso row can be handled by CHDMAN, Dolphin, or CSO; the primary-tool picker decides which one acts on it.

Environment Variables

Variable Default Description
MAXCSO_PATH /usr/local/bin/maxcso Path to the maxcso binary

REST API Endpoints

  • POST /api/jobs or POST /api/jobs/batch - Queue CSO jobs (use mode: "cso_compress", "cso2_compress", "zso_compress", "dax_compress", "cso_decompress", or "cso_to_chd")
  • GET /api/cso-info?path=/path/to/game.cso - Get file information (size, format, compression status)
  • GET /api/cso-verify?path=/path/to/game.cso - Verify a compressed CSO/ZSO/DAX output
  • GET /api/cso-verify/events?path=/path/to/game.cso - SSE stream for CSO verify progress
  • POST /api/cso-verify-batch/events - SSE stream for batch CSO verification

PlayStation 3 Support (folder → ISO)

The PS3 ISO tool packs a decrypted PS3 disc or JB folder into a single .iso that RPCS3 mounts directly, using makeps3iso. This is the one tool whose input is a folder, not a file, and the one tool with no reverse mode at all. It repackages a folder you already decrypted. It does not decrypt anything and needs no keys. (The cso_to_chd chain also changes container, but a CHD still extracts back to an ISO; PS3 ISO has no way back at all.)

How to Use

Select PS3 ISO as the primary tool. A decrypted PS3 folder then shows up as a selectable source in the file browser and in Search All (clicking its name still browses into it). Pick the folder and run the one mode, folder_to_iso. The output is <folder>.iso next to the source, or in a custom output directory inside a mounted volume. The general workflow (queue, output handling) is in the Usage Guide.

A folder qualifies when it has the decrypted PS3 layout: a PS3_GAME/ directory, plus PS3_DISC.SFB for disc rips. A bare installed-game folder is not accepted.

Optional 4 GB split for FAT32

FAT32 can't hold a single file larger than 4 GB, so most PS3 discs won't fit as one .iso. The per-job Split into 4 GB parts (FAT32) toggle runs makeps3iso with -s, so an image over ~4 GB is written as Game.iso.0, Game.iso.1, and so on (RPCS3 mounts the .0). A title under 4 GB still produces a single Game.iso. The file browser folds a split set into one entry, showing Game.iso with the combined size rather than a row per chunk. The toggle is off by default; ext4, NTFS, and exFAT targets don't need it.

Notes

  • makeps3iso has no native verify, so there is no verify or delete-on-verify for this tool. After a successful build it does a light PARAM.SFO TITLE_ID readback from the produced ISO and flags a mismatch in the job message.
  • While a folder is being packed, its whole subtree is locked. A per-file job that was already queued and whose input or output lands inside the folder is deferred, re-queued, and retried once the build finishes (only reachable with MAX_CONCURRENT_JOBS > 1). A new request whose output lands inside the folder is treated as an output collision and rejected up front, since the subtree reads as locked. That covers skip, overwrite, and rename alike: rename doesn't probe numbered siblings here, because every candidate lives in the same locked subtree, so it's rejected with the same locked-output error instead of looping until the build finishes.
  • The default output (<folder>.iso) must land inside a configured volume. If the folder is itself a volume root, so the sibling output would escape every volume, the job is rejected with a message asking for an in-volume output directory.
  • The makeps3iso binary (GPL-3.0, from bucanero/ps3iso-utils) is built into the Docker image and builds on both linux/amd64 and linux/arm64.

Environment Variables

Variable Default Description
MAKEPS3ISO_PATH /usr/local/bin/makeps3iso Path to the makeps3iso binary

(Global vars, including the tool-neutral priority knobs, are in Environment Variables.)

REST API Endpoints

  • POST /api/jobs or POST /api/jobs/batch - Queue a PS3 ISO job. Use mode: "folder_to_iso" with the PS3 folder as the input path (file_path for a single job, file_paths for a batch), plus an optional split: true for the 4 GB FAT32 split.

There is no info or verify endpoint for this tool, since makeps3iso has no native verify.


CLI Mode (Batch Processing)

For automated/headless conversion, use CLI mode. CLI mode runs CHDMAN only and processes files in the top level of each mounted volume (no recursive scanning, no archives). See DOCKER-COMPOSE.md for CLI behavior details.

CD Conversion (Default)

docker run --rm \
  -e CHD_MODE=cli \
  -v "$(pwd)/isofiles:/data/games:rw" \
  pacnpal/compressatorium

DVD Conversion (PSP, PS2)

docker run --rm \
  -e CHD_MODE=cli \
  -e CHDMAN_MODE=createdvd \
  -v "$(pwd)/isofiles:/data/games:rw" \
  pacnpal/compressatorium

Multiple Volumes in CLI Mode

docker run --rm \
  -e CHD_MODE=cli \
  -e CHDMAN_MODE=createdvd \
  -v /home/user/psp:/data/psp:rw \
  -v /home/user/ps2:/data/ps2:rw \
  pacnpal/compressatorium

Check Existing CHD Files

Using the chdman info command directly:

docker run --rm \
  -v "/path/to/games:/data/games:ro" \
  --entrypoint chdman \
  pacnpal/compressatorium \
  info -i "/data/games/game.chd"

Or use the Web UI's CHD Inspector feature by clicking on any .chd file.


Compression Compatibility Tips

Some emulators (notably NetherSX2/AetherSX2) only support zlib-compressed CHDs. If you see errors like “Failed to initialize cdvd,” re-convert with zlib only.

  • zlib: best compatibility across emulators
  • zstd: fast + small, but older software may not support it
  • lzma: highest compression, slowest
  • No compression: uses -c none for uncompressed output
  • CD-specific codecs: use cdzl/cdzs/cdlz/cdfl for CD images only

For Dolphin formats, choose a single codec (zstd/bzip2/lzma/lzma2) and an optional level. Use chdman help createcd or chdman help createdvd for codec details.


Supported Operations

All actions are queued and processed by the job queue (FIFO). The queue is the only execution path.

Create CHD

  • createraw, createhd, createcd, createdvd, createld

Extract from CHD

  • extractraw, extracthd, extractcd, extractdvd, extractld

Copy / Recompress

  • copy (CHD → CHD, optionally with new compression)

Dolphin (GameCube/Wii)

  • dolphin_rvz, dolphin_wia, dolphin_gcz, dolphin_iso

Nintendo 3DS

  • z3ds_compress (.cci → .zcci, .cia → .zcia, .3ds → .z3ds, .cxi → .zcxi, .3dsx → .z3dsx)
  • z3ds_decompress (.zcci → .cci, .zcia → .cia, .z3ds → .3ds, .zcxi → .cxi, .z3dsx → .3dsx)

PSP / PS2 (CSO)

  • cso_compress (.iso → .cso, CSO v1), cso2_compress (.iso → .cso, CSO v2), zso_compress (.iso → .zso), dax_compress (.iso → .dax), cso_decompress (.cso/.zso/.dax → .iso), cso_to_chd (.cso/.zso/.dax → .chd, one-step chain through maxcso + chdman)

Handheld ROM (GB/GBC/GBA/NDS)

  • romz_7z (.gb/.gbc/.gba/.nds → .7z), romz_zip (.gb/.gbc/.gba/.nds → .zip), romz_extract (.7z/.zip → original ROM)

PS3 ISO (decrypted folder)

  • folder_to_iso (a folder containing PS3_GAME/<folder>.iso, with an optional -s 4 GB FAT32 split)

Notes:

  • Compression settings apply to CHD create/copy, Dolphin RVZ/WIA, Switch (nsz_compress), the CSO/CSO v2/ZSO/DAX compress modes, and the handheld ROM compress modes (romz_7z/romz_zip) — the last two take an effort preset. Other modes ignore them.
  • Extract/decompress operations ignore compression settings.
  • extractcd produces both .cue and .bin outputs.
  • Dolphin GCZ/ISO outputs ignore compression selection.
  • 3DS compression uses fixed settings (no user configuration needed).
  • Archive inputs are supported for the file-based convertible sources (CHD create, Dolphin, 3DS, Switch, and CSO), plus CHDMAN's extract modes decompressing a .chd pulled out of an archive. Exceptions: CHDMAN's copy/recompress mode (it would just re-compress an already-finished .chd), Handheld ROM compression (its .7z/.zip are the product), and PS3 ISO (its input is a folder, not a file).

API Endpoints

The Web UI communicates with a REST API that can also be used directly. Interactive API documentation is available at /docs when running the container.

File Operations

Method Endpoint Description
GET /api/volumes List configured volume mount points
GET /api/files List files in a directory
GET /api/files/search Recursively search for convertible files
GET /api/files/archive List contents of an archive file
POST /api/files/rename Rename a file or directory
DELETE /api/files/delete Delete a single file or empty directory
POST /api/files/delete-batch Delete multiple files at once

Conversion Jobs

Method Endpoint Description
POST /api/jobs Create a single conversion job
POST /api/jobs/batch Create multiple conversion jobs
POST /api/jobs/check-duplicates Check for existing output files
POST /api/jobs/delete-plan Build delete-on-verify confirmation list
GET /api/jobs List all jobs
GET /api/jobs/{id} Get a specific job
DELETE /api/jobs/{id} Cancel a job
DELETE /api/jobs/completed Clear completed/failed/cancelled jobs
POST /api/jobs/cancel-all Cancel all queued and processing jobs
GET /api/jobs/events SSE stream for job progress updates
GET /api/jobs/{id}/events SSE stream for a single job's progress
GET /api/jobs/stuck-status Check if job queue is in a stuck state
POST /api/jobs/recover Manually trigger recovery from stuck job queue

Destructive jobs actions require explicit confirmation headers:

  • DELETE /api/jobs/completed requires X-CHD-Action-Confirm: clear-completed-jobs
  • POST /api/jobs/cancel-all requires X-CHD-Action-Confirm: cancel-all-jobs

CHD Information & Verification

Method Endpoint Description
GET /api/info Get CHD file metadata
GET /api/verify Verify a CHD file's integrity
GET /api/verify/events SSE stream for verification progress
POST /api/verify-batch/events SSE stream for batch verification
GET /api/verified List all verified CHD paths

CHD Metadata & Version

Method Endpoint Description
GET /api/version Get app version
POST /api/chd-metadata Fetch cached CHD metadata for multiple files
POST /api/chd-metadata/scan Trigger background metadata scan
GET /api/chd-metadata/scan/status Check metadata scan status

Dolphin Disc Info & Verification

Method Endpoint Description
GET /api/dolphin-info Get Dolphin disc metadata
GET /api/dolphin-verify Verify a game image's integrity
GET /api/dolphin-verify/events SSE stream for Dolphin verification progress
POST /api/dolphin-verify-batch/events SSE stream for batch Dolphin verification

3DS Info & Verification

Method Endpoint Description
GET /api/z3ds-info Get 3DS ROM metadata
GET /api/z3ds-verify Verify a compressed 3DS file's integrity
GET /api/z3ds-verify/events SSE stream for 3DS verification progress
POST /api/z3ds-verify-batch/events SSE stream for batch 3DS verification

Switch Info & Verification

Method Endpoint Description
GET /api/nsz-info Get Switch file metadata
GET /api/nsz-verify Verify a compressed Switch file's integrity
GET /api/nsz-verify/events SSE stream for Switch verification progress
POST /api/nsz-verify-batch/events SSE stream for batch Switch verification

CSO Info & Verification

Method Endpoint Description
GET /api/cso-info Get CSO/ISO file metadata
GET /api/cso-verify Verify a compressed CSO/ZSO/DAX file's integrity
GET /api/cso-verify/events SSE stream for CSO verification progress
POST /api/cso-verify-batch/events SSE stream for batch CSO verification

Environment Variables

Variable Default Description
CHD_MODE webui Mode: webui (web interface) or cli (batch processing)
COMPRESSATORIUM_MOUNT_ROOT /data Startup scan root. When no explicit volumes are set, directories under this path (/data/*) are auto-registered
COMPRESSATORIUM_VOLUMES (unset) Explicit comma-separated volume paths. When set, startup scan is skipped
CHD_MOUNT_ROOT /data Legacy alias for COMPRESSATORIUM_MOUNT_ROOT
CHD_VOLUMES (unset) Legacy alias for COMPRESSATORIUM_VOLUMES
PUID 999 Optional runtime UID remap for converter before app startup (useful on Unraid/home servers)
PGID 999 Optional runtime GID remap for converter; if that GID already exists, converter is reassigned to the existing group
CHD_DATA_DIR /config Directory for persistent application data
COMPRESSATORIUM_SEARCH_AUTO_RETURN_TO_FILE_LIST true Web UI: when true, Search All conversions return to the previous file-list view after queueing
CHD_SEARCH_AUTO_RETURN_TO_FILE_LIST true Legacy alias for COMPRESSATORIUM_SEARCH_AUTO_RETURN_TO_FILE_LIST
CHD_TEMP_DIR /config/temp Temporary working directory for archive extraction (auto-created)
CHD_CONCURRENCY_LOCK_DIR /tmp/chd-locks Directory for job lock files (ephemeral, auto-cleaned on container restart)
COMPRESSATORIUM_DB_PATH /config/compressatorium.db Unified SQLite database for DATs, match cache, CHD metadata, verification state, and DAT-sync state
CHD_METADATA_STORE (deprecated) Legacy JSON path. Ignored at runtime; auto-migrated into the SQLite DB on first startup (custom path honored if set) and renamed to chd_metadata.json.migrated.bak
CHD_VERIFICATION_STORE (deprecated) Legacy JSON path. Ignored at runtime; auto-migrated into the SQLite DB on first startup (custom path honored if set) and renamed to verified_chds.json.migrated.bak
CHDMAN_MODE createcd Conversion mode: createcd or createdvd (CLI mode only)
CHDMAN_PATH /usr/bin/chdman Path to chdman binary (for custom builds)
DOLPHIN_TOOL_PATH /usr/local/bin/dolphin-tool Path to dolphin-tool binary
Z3DS_COMPRESSOR_PATH /usr/local/bin/z3ds_compressor Path to z3ds_compressor binary
MAXCSO_PATH /usr/local/bin/maxcso Path to maxcso binary (PSP/PS2 CSO/CSO v2/ZSO/DAX)
MAKEPS3ISO_PATH /usr/local/bin/makeps3iso Path to the makeps3iso binary (PS3 folder → ISO)
NSZ_PATH nsz Path to the nsz binary (Nintendo Switch); resolved on PATH by default
SEVENZIP_PATH 7z Path to the 7z binary (handheld ROM archives); resolved on PATH by default (set an absolute path or 7zz if your distro ships the newer 7zip package)
MAX_CONCURRENT_JOBS 1 Maximum parallel conversion jobs (1 = serial queue processing)
MAX_QUEUE_DEPTH 0 Max queued+processing conversion jobs before create endpoints return 429 (0 disables)
COMPRESSATORIUM_CHAIN_DISK_MARGIN_MB 512 Free-space margin in MB the cso_to_chd chain keeps beyond the room needed for the temporary .iso plus the final .chd. A job is rejected when free space is below required + margin, so a bigger margin is stricter. If a valid chain job is wrongly rejected for headroom, lower this or free up space (or point CHD_TEMP_DIR / the output at a roomier volume).
MAX_VERIFY_CONCURRENCY 1 Maximum concurrent verify workloads across CHD/Dolphin/3DS verify endpoints
MAX_METADATA_SCAN_CONCURRENCY 1 Maximum concurrent metadata scan tasks
MAX_MATCH_CONCURRENCY 1 Maximum concurrent DAT hash-matching operations. Raise only if your storage can handle parallel full-file reads (matching a raw Wii ISO is a full-file SHA1).
MATCH_MAX_FILE_SIZE 0 Skip DAT hash-matching for files larger than this many bytes (0 disables the cap). Set e.g. 2147483648 on slow storage to keep 8 GB ISOs from blocking the browse-triggered matcher.
MAX_JOB_HISTORY 500 Maximum completed jobs to retain in history
COMPRESSATORIUM_TOOL_NICE 10 Nice level for every conversion tool (0-19, higher = lower priority). Legacy alias: CHD_CHDMAN_NICE.
COMPRESSATORIUM_TOOL_IOPRIO_CLASS 2 I/O priority class for every tool (1 realtime, 2 best-effort, 3 idle). Legacy alias: CHD_CHDMAN_IOPRIO_CLASS.
COMPRESSATORIUM_TOOL_IOPRIO_LEVEL 6 I/O priority level for every tool (0 highest, 7 lowest). Legacy alias: CHD_CHDMAN_IOPRIO_LEVEL.
COMPRESSATORIUM_TOOL_INFO_TIMEOUT 60 Timeout in seconds for info/header subprocesses, used by chdman and Dolphin (nsz/3DS read info from the filesystem, so it doesn't apply to them). 0 disables. Legacy alias: CHD_INFO_TIMEOUT.
COMPRESSATORIUM_TOOL_VERIFY_TIMEOUT 0 Timeout in seconds for verify runs across all tools (0 disables). Legacy alias: CHD_VERIFY_TIMEOUT.
COMPRESSATORIUM_<TOOL>_NICE / _IOPRIO_CLASS / _IOPRIO_LEVEL / _VERIFY_TIMEOUT (shared default) Optional per-tool overrides that fall back to the shared COMPRESSATORIUM_TOOL_* values. <TOOL> is CHDMAN, DOLPHIN_TOOL, NSZ, Z3DS, MAXCSO, ROMZ (handheld ROM), or MAKEPS3ISO (e.g. COMPRESSATORIUM_DOLPHIN_TOOL_NICE=15, COMPRESSATORIUM_NSZ_VERIFY_TIMEOUT=300, COMPRESSATORIUM_MAXCSO_VERIFY_TIMEOUT=300). MAKEPS3ISO takes the _NICE/_IOPRIO_* knobs but has no _VERIFY_TIMEOUT, since makeps3iso has no verify step.
COMPRESSATORIUM_<TOOL>_INFO_TIMEOUT (shared default) Optional per-tool info-timeout override, only for <TOOL> = CHDMAN or DOLPHIN_TOOL (the only tools whose info runs a subprocess); falls back to the shared COMPRESSATORIUM_TOOL_INFO_TIMEOUT.
CHD_ARCHIVE_MAX_ENTRIES 5000 Max archive members to list (0 disables limit)
CHD_ARCHIVE_MAX_MEMBER_SIZE 0 Max size in bytes per archive member (0 disables limit)
CHD_ARCHIVE_MAX_TOTAL_SIZE 0 Max total size in bytes for archive listings/extractions (0 disables limit)
CHD_VERIFY_PROGRESS_TIMEOUT 0 Timeout in seconds without verify output (0 disables)
LOGLEVEL INFO Log verbosity level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
LOG_PATH (none) Path to log file (logs to stdout only if unset)
LOG_COLOR always ANSI-color stdout logs by level. Values: always (default, colored docker logs out of the box), auto (TTY and no NO_COLOR), never. File logs are never colored.
CHD_DEBUG_HEARTBEAT 30 Maintenance loop interval in seconds
CHD_DEBUG_PROGRESS_INTERVAL 30 Debug progress log interval in seconds
CHD_DEBUG_PROGRESS_TIMEOUT 300 Debug progress timeout in seconds
CHD_PROGRESS_TIMEOUT 600 Fail a conversion if progress and output size do not advance for this many seconds (0 disables)
CHD_PROGRESS_TIMEOUT_PER_GIB 120 Additional stall timeout seconds per GiB of input size
CHD_PROGRESS_TIMEOUT_CAP 7200 Upper bound for adaptive conversion stall timeout (0 disables cap)
STATIC_DIR /static Path to static web assets

Defaults are intentionally conservative to reduce host impact during conversion. Increase MAX_CONCURRENT_JOBS or adjust COMPRESSATORIUM_TOOL_* only if your host has ample CPU/RAM and fast storage. By default temp files go to /config/temp; set CHD_TEMP_DIR to use a faster disk and mount it into the container.


Persistent Data

The /config volume is required and must be mounted for the application to store persistent data.

-v /path/to/config:/config

Data Files

File Location Description
compressatorium.db /config/ SQLite database holding DAT index, hash match cache, CHD metadata cache, verification records, and DAT-sync state. Override path with COMPRESSATORIUM_DB_PATH.
*.json.migrated.bak /config/ Legacy JSON stores, preserved as read-only backups after the one-time SQLite migration on first upgrade. Safe to delete once you've confirmed the app is working.

First-run migration from JSON

On the first startup after upgrading from a JSON-backed install, the app imports dat_store.json, verified_chds.json, chd_metadata.json, and dat_sync.json into the new SQLite database. The originals are renamed to <name>.migrated.bak and never deleted, so you can always roll back. Migration is transactional, idempotent, and checks row counts. A failed or corrupt file is quarantined with a .corrupt suffix and the other stores still migrate.

Schema changes (for developers)

Schema is managed by Alembic. On every startup:

  1. If the DB already has an alembic_version row, Alembic runs upgrade head.
  2. If the DB has the baseline tables but no alembic_version (pre-Alembic install), Alembic stamps the baseline revision (0001) and then runs upgrade head if later migrations are present. Alembic will create the alembic_version table as part of this process.
  3. If the DB is empty, Alembic initializes it by applying the migration chain up to head.

To evolve the schema:

scripts/new_migration.sh "add foo column to dats"
# review migrations/versions/NNNN_*.py
# commit the new migration alongside your ORM changes

The test test_no_model_drift_after_upgrade fails if Base.metadata drifts from the migration chain. It runs on every test run and catches forgotten migrations.

Ephemeral Runtime Data

The application also uses a non-persistent directory for runtime lock files:

File / Directory Location Description
locks/ /tmp/chd-locks Job lock files (ephemeral, stored outside /config and automatically cleaned on container restart)

Docker Compose

The repository includes ready-to-use Docker Compose configurations:

  • docker-compose.yml - Single volume setup with subdirectory support
  • docker-compose.multi-volume.yml - Multiple separate volume mounts
  • docker-compose.cli.yml - CLI/batch processing mode

Quick Start

  1. Single Volume Setup (recommended for most users):
    • Mount a top-level directory containing your games in subdirectories
    • The Web UI will recursively browse all subdirectories
docker-compose up -d

The default compose files include conservative CPU/memory limits to help avoid host lockups during large conversions. Adjust those limits to match your system.

Tuning and Host Recommendations

How to change settings

  • Docker Compose: edit docker-compose.yml (or docker-compose.multi-volume.yml) and update MAX_CONCURRENT_JOBS, COMPRESSATORIUM_TOOL_* (priority/timeout), and the deploy.resources limits.
  • Docker run / Unraid: set environment variables in the container template and apply CPU/memory limits there.

Recommended starting points

  • Low/medium hosts (≤16 GB RAM, HDD or parity-backed arrays): keep MAX_CONCURRENT_JOBS=1, COMPRESSATORIUM_TOOL_NICE=10, COMPRESSATORIUM_TOOL_IOPRIO_CLASS=2, COMPRESSATORIUM_TOOL_IOPRIO_LEVEL=6. Set a container memory limit (8–12 GB).
  • Faster hosts (32+ GB RAM, SSD cache): try MAX_CONCURRENT_JOBS=2 and a higher memory limit (16–24 GB). Raise I/O priority only if the host remains responsive.
  • If the host becomes sluggish: lower MAX_CONCURRENT_JOBS, increase COMPRESSATORIUM_TOOL_NICE, or set COMPRESSATORIUM_TOOL_IOPRIO_CLASS=3 (idle) with COMPRESSATORIUM_TOOL_IOPRIO_LEVEL=7.

Docker host tips

  • Prefer SSD/cache for CHD_TEMP_DIR and CHD output to reduce array contention.
  • Avoid running other heavy services during conversion.
  • Always set container CPU/memory limits on shared hosts.
  1. Multiple Volumes:
docker-compose -f docker-compose.multi-volume.yml up -d
  1. CLI Batch Processing:
docker-compose -f docker-compose.cli.yml up

Example Configuration

version: '3.8'

services:
  compressatorium:
    image: pacnpal/compressatorium
    ports:
      - "8080:8080"
    environment:
      - COMPRESSATORIUM_MOUNT_ROOT=/data
      - PUID=99
      - PGID=100
      - MAX_CONCURRENT_JOBS=1
      - COMPRESSATORIUM_TOOL_NICE=10
      - COMPRESSATORIUM_TOOL_IOPRIO_CLASS=2
      - COMPRESSATORIUM_TOOL_IOPRIO_LEVEL=6
    volumes:
      - /home/user/compressatorium-config:/config
      - /home/user/games/dreamcast:/data/dreamcast
      - /home/user/games/psp:/data/psp
      - /home/user/games/ps1:/data/ps1
    restart: unless-stopped

For production deployment guidance, see DEPLOYMENT.md.


Supported File Types

Input formats:

  • .gdi - GD-ROM (Dreamcast)
  • .iso - ISO 9660 game images (CHD or Dolphin based on ISO handling)
  • .cue / .bin - CD images with cue sheets
  • .gcz, .wia, .rvz, .wbfs - GameCube/Wii game images (Dolphin)
  • .cci, .cia, .3ds, .cxi, .3dsx - Nintendo 3DS ROM images (3DS compression)
  • .zcci, .zcia, .z3ds, .zcxi, .z3dsx - compressed 3DS ROMs (3DS decompression)
  • .cso, .zso, .dax - PSP/PS2 compressed ISO images (CSO decompression, or cso_to_chd to a .chd)
  • .gb, .gbc, .gba, .nds - Game Boy / GBC / GBA / DS ROMs (handheld ROM compression)
  • A decrypted PS3 folder (one containing a PS3_GAME/ directory) - packed to .iso (PS3 ISO tool; the input is a folder, not a file)

Archive formats (Web UI):

  • .zip - ZIP archives
  • .7z - 7-Zip archives
  • .rar - RAR archives

Output formats:

  • .chd - Compressed Hunks of Data (MAME/CHDMAN)
  • .rvz, .wia, .gcz, .iso - Dolphin output formats
  • .zcci, .zcia, .z3ds, .zcxi, .z3dsx - Compressed Nintendo 3DS ROMs (z3ds_decompress restores the original ROM)
  • .cso, .zso, .dax - Compressed PSP/PS2 ISO images (maxcso; .cso covers CSO v1 and v2)
  • .7z, .zip - Handheld ROM archives (7z; romz_extract restores the original .gb/.gbc/.gba/.nds)
  • .iso (and a split .iso.0/.iso.1/… set on FAT32) - PS3 ISO packed from a decrypted folder (makeps3iso)

Frontend Development

The Web UI is a Svelte 5 + Vite single-page app. Source lives under src/, the build emits index.html plus hashed assets into static/, and FastAPI serves the result through the /static mount and a root FileResponse. The code follows the architecture in DESIGN_tool_plugin_architecture.md §3.7. A declarative tool registry (src/lib/tools/registry.js) drives every tool-specific decision, so adding a converter is one entry in TOOLS with no if (tool === ...) branches anywhere.

Quick start

# Install JS deps (one-time)
npm install

# In one shell: start the FastAPI backend
./run_dev.sh                          # or: uvicorn app.main:app --port 8080

# In a second shell: start Vite with HMR
npm run dev                           # → http://localhost:5173

Vite proxies /api and /health to http://localhost:8080, so the dev server runs the SPA against the live backend with hot reload.

Build & lint

npm run build       # Vite production build → static/index.html + static/assets/*
npm run preview     # Serve the built bundle locally on :4173
npm run lint        # ESLint (JS + .svelte), flat config in eslint.config.js

Architecture at a glance

  • src/App.svelte: the root shell. Sidebar, topbar, routed view, error boundary, focus management on route change, skip-to-content link, and the <ModeWatcher /> (theme) and <Toaster /> (notifications) mounts.
  • src/lib/stores/*.svelte.js: class-singleton stores with Svelte 5 $state fields, one per feature domain (jobs / fileBrowser / conversion / verification / datMatching / chdMetadata / ui).
  • src/lib/api/: REST client, auto-reconnecting EventSource (sse.js), and a POST-body SSE stream parser for batch verify (sseFetch.js). Backend snapshot-on-connect (/api/jobs/events) hydrates the full job state, so there's no separate REST round-trip.
  • src/lib/tools/registry.js: every tool fact (id, label, hint, verify URL segment, source/verify exts, modes, groups, default mode, glyph, accent, compression codecs / style / level range, API bindings). Adding another tool is one new entry plus the backend plugin. Helpers like registry.allFilterableExts() keep UI surfaces (file-list filter dropdown, conversion mode dropdown, compression picker, and so on) extended automatically.
  • src/lib/components/panels/: VolumeList, Breadcrumb, FileList, FileRow, RowActionsMenu (file browser); ModeSelect, CompressionPicker, ConvertPanel (conversion config); JobRow, JobsPanel (queue / completed / failed tabs with global Cancel-all / Clear / stuck-state recovery).
  • src/lib/components/modals/: BaseModal (bits-ui Dialog wrapper), ConfirmModal (canonical confirm/cancel), then BulkVerifyModal, DuplicateModal, DeleteModal, BulkDeleteModal, RenameModal, FileInfoModal, CancelAllJobsModal, ClearDoneModal. Each mounts in App.svelte and self-renders against a ui store target.
  • src/lib/components/dashboard/: StatCard wrapper plus QueueSummaryCard, VolumeOverviewCard, RecentConversionsCard, VerificationStatusCard, QuickToolsCard. QuickToolsCard iterates registry.all(), so adding a tool auto-adds a tile.
  • src/styles/tokens.css: semantic design tokens keyed by :root (light defaults) and :root.dark (dark overrides). No hex colors live outside this file.

Runtime dependencies

  • @lucide/svelte: the official Lucide icon library for Svelte 5 runes, tree-shakeable per icon.
  • bits-ui: headless accessibility primitives (Dialog, DropdownMenu, ContextMenu, Tooltip, and so on). Pulled in per component as panels need them, which keeps the bundle small.
  • svelte-sonner: toast notifications. Call toast.success(...) / toast.error(...) / toast.promise(...) from anywhere. The <Toaster /> in App.svelte is the surface.
  • mode-watcher: light/dark/system mode with localStorage persistence, system-preference tracking, and cross-tab sync. It adds the .dark class to <html>, and a matching inline script in index.html prevents a flash of the wrong theme on first paint.

Docker / CI

The multi-stage Dockerfile has a dedicated frontend-builder stage that runs npm ci && npm run build inside node:lts-slim, then copies the output into the Python runtime image. The runtime image has no Node; node:lts-slim ships linux/amd64 + linux/arm64 so the existing multi-arch buildx pipeline keeps working unchanged.


Acknowledgments

This project is a fork of the original Docker CHD Converter project by MarcTV. The original project provides a simple CLI-based batch converter, and this fork extends it with a Web UI and additional features.

Original Project:

Additional Tools:

Thanks to everyone who built and shared these tools.

Install Compressatorium on Unraid in a few clicks.

Find Compressatorium in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for Compressatorium Review the template variables and paths Click Install

Download Statistics

10,491
Total Downloads

Related apps

Explore more like this

Explore all

Details

Repository
pacnpal/compressatorium:latest
Last Updated2026-06-14
First Seen2026-04-06

Runtime arguments

Web UI
http://[IP]:[PORT:8080]/
Network
bridge
Shell
bash
Privileged
false
Extra Params
--cap-add SYS_NICE

Template configuration

WebUI PortPorttcp

Port for the web interface

Target
8080
Default
8090
Value
8090
AppdataPathrw

Persistent application data (verified files DB, metadata cache)

Target
/config
Default
/mnt/user/appdata/compressatorium
Value
/mnt/user/appdata/compressatorium
GamesPathrw

Primary game library. Add additional volumes under /data/ for separate libraries. All directories under /data in the container will be automatically mounted, and you can browse and use subdirectories.

Target
/data/games
More GamesPathrw

Optional: Additional game library

Target
/data/games2
Log LevelVariable

Logs to be shown in the docker logs

Target
LOGLEVEL
Default
INFO
Value
INFO
Maximum Concurrent JobsVariable

Number of parallel conversion jobs

Target
MAX_CONCURRENT_JOBS
Default
1
Value
1