shrinkray

module
v0.0.0-...-168bfd8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2026 License: GPL-3.0

README

shrinkray 📼➡️📦

Point shrinkray at a movie. It creates a smaller copy and leaves the original alone.

Easy guided mode

Run Shrinkray without any options:

shrinkray

It will ask you to choose a movie, how small you want it, and whether you need MKV or MP4 compatibility. The guided prompts work in a local Linux Mint terminal and over SSH on Ubuntu Server.

If you prefer an advanced direct command, provide the movie and target size:

shrinkray movie.mkv --size 700

Direct mode creates movie.shrunk.mkv by default.

Server dashboard

The lightweight server dashboard lets another device browse movies that are already on a headless server, inspect them, and queue Shrinkray jobs. It uses a single encoding worker so simultaneous software encodes cannot overload a small server. Running jobs report live pass progress, encoding speed, and ETA. The dashboard does not upload, rename, replace, move, or delete files.

Go 1.22 or newer is required to build and run the server. From a repository clone, test it locally with:

go run ./cmd/shrinkray-server \
  --root ~/Videos \
  --shrinkray-bin ./shrinkray

Then open http://127.0.0.1:8787. The server listens only on localhost by default.

Repeat --root to expose separate media libraries while keeping one global encoding queue:

shrinkray-server \
  --root /media/movies \
  --root /media/tv \
  --listen 127.0.0.1:8787 \
  --shrinkray-bin ./shrinkray

Library names are derived from directory names (movies becomes Movies and tv becomes TV). Give them explicit dashboard names with Name=/path:

shrinkray-server \
  --root "Movies=/media/movies" \
  --root "TV Shows=/media/tv" \
  --shrinkray-bin ./shrinkray

Separate roots are safer than --root /media: Shrinkray can browse only the configured Movies and TV libraries, not unrelated folders that happen to live under /media. Configured roots must not overlap.

Systemd server installation

On Ubuntu Server, Ubuntu Desktop, or Linux Mint, install the CLI, dashboard, managed configuration, and systemd service with:

curl -fsSL \
  https://raw.githubusercontent.com/AmirIqbal1/shrinkray/main/install-server.sh \
  | sudo bash -s -- \
      --user amir \
      --root "Movies=/media/movies" \
      --root "TV Shows=/media/tv"

The managed service always listens on 127.0.0.1:8787 by default. Existing Tailscale access uses a separate HTTPS listener on port 8443; Shrinkray never automatically claims HTTPS port 443. Re-running the installer updates the binaries while preserving the configured user, backend port, Tailscale HTTPS port, and roots unless replacements are provided explicitly. Use --tailscale-https-port <port> to select another unused non-443 private port, --source-dir /path/to/shrinkray to build from a local checkout, or --dry-run to validate without installing system files.

The safe layout on a server that already runs Coolify or another public reverse proxy is:

Coolify / public reverse proxy:
https://panel.example.com
host port 443

Shrinkray local backend:
http://127.0.0.1:8787

Shrinkray private browser URL:
https://hostname.tailnet.ts.net:8443/

The installer prints the server's private Tailscale dashboard URL after setup. Do not publish private tailnet hostnames in a public repository.

Port 443 remains reserved for Coolify, Traefik, Caddy, Nginx, Apache, or another host reverse proxy. Port 8443 is the private Tailscale HTTPS listener, and port 8787 remains bound to localhost only. Do not use Tailscale Funnel, do not run tailscale serve reset, and do not expose port 8787 through a router. During an upgrade, the installer can migrate a clearly owned old Shrinkray listener from Tailscale HTTPS port 443: it configures and verifies 8443 first, then removes only the old 443 listener. Ambiguous or unrelated routes are never removed.

For access without Tailscale Serve, keep the loopback default and open an SSH tunnel:

ssh -L 8787:127.0.0.1:8787 user@server

Then open http://127.0.0.1:8787 on the local device.

The managed installer does not offer a public bind mode. For diagnostics, run:

shrinkray-server-doctor
shrinkray-server-doctor --repair
systemctl status shrinkray
journalctl -u shrinkray -f
tailscale serve status
ss -ltnp | grep -E ':(443|8443|8787)\b'

Normal doctor mode is read-only. Repair mode can restart only the Shrinkray service, configure its non-443 Tailscale listener, and remove an old 443 listener only when that listener clearly proxies solely to Shrinkray. It never restarts Docker or Coolify, changes media permissions, resets Serve, or uses Funnel.

The dashboard has no authentication. Do not expose it directly to the public internet. Use localhost, SSH tunnelling, a trusted LAN, Tailscale, or a protected reverse proxy. Every browsed or submitted path is resolved against the selected --root; traversal, symlink escapes, unsupported files, and existing outputs are rejected. Absolute configured root paths are not exposed through the browser API.

Additional server flags are --state-dir (default ~/.local/share/shrinkray/server) and --listen (default 127.0.0.1:8787). The server version is independent of the Bash CLI; this multi-library release is shrinkray-server v0.2.0.

Persistent job history

The dashboard stores its queue and recent job history in jobs.json under the configured Shrinkray state directory. Docker persists /var/lib/shrinkray, so completed, failed, cancelled, and queued records survive container recreation. Queued work is validated and restored after restart. An encode interrupted by a restart is marked failed and must be submitted again; it is never resumed in the middle of an encode.

Shrinkray retains the newest 250 finished jobs together with every active or queued job. The dashboard's Clear history action removes completed, failed, and cancelled records only. It never removes source movies, compressed output, queued work, or running jobs.

Docker home-server deployment

Docker is the recommended way to run the dashboard on a home server. Tailscale stays installed directly on the host; it is not installed or run in the Shrinkray container. Copy the example settings and adjust the IDs and host paths:

cp .env.example .env
id -u
id -g
editor .env
mkdir -p /path/to/shrinkray-state /path/to/movies /path/to/tv

The configured user and media group must already be able to traverse, read, and write all three host directories. Media mounts are intentionally writable because compressed files are created beside their sources. The state and media directories are bind-mounted, so they survive image rebuilds and container recreation.

Manage the deployment from the repository:

scripts/shrinkray-docker.sh start
scripts/shrinkray-docker.sh status
scripts/shrinkray-docker.sh logs
scripts/shrinkray-docker.sh restart
scripts/shrinkray-docker.sh stop

build pulls current base images and builds Shrinkray. update runs git pull --ff-only, builds a new image, recreates only the shrinkray service, and verifies container and API health. If validation fails, it retags the saved previous image and recreates the previous Shrinkray container configuration. It never updates or restarts unrelated containers.

Use the read-only diagnostic command before repair:

scripts/shrinkray-docker.sh doctor
sudo scripts/shrinkray-docker.sh repair

Doctor inspects Docker, mounts, configured IDs and permissions, local health, ports, Tailscale, and Serve routes. Repair may start or restart only Shrinkray, restore only its configured private Serve listener, and remove a legacy port 443 listener only if it consists of exactly one route to Shrinkray. It does not restart Docker, Coolify, Jellyfin, reset Tailscale Serve, use Funnel, or change media ownership.

The safe port layout is:

Coolify / public reverse proxy: host port 443
Tailscale Serve:               host private HTTPS port 8443
Shrinkray Docker publication:  host 127.0.0.1:8787
Shrinkray inside container:     0.0.0.0:8787

Docker never publishes ports 443 or 8443. The dashboard has no authentication, so keep port 8787 loopback-only. Configure the host-side private listener after the local health check passes:

sudo scripts/configure-tailscale.sh

The script refuses port 443, preserves unrelated Serve routes, and prints the private URL using the current DNS name returned by tailscale status --json. It never contains a server-specific hostname.

To migrate an existing native systemd installation, first prepare and validate .env, then run:

sudo scripts/migrate-systemd-to-docker.sh

Migration backs up the native unit, configuration, CLI, server, and doctor binary under /var/backups/shrinkray-migration/. It builds the image before stopping shrinkray.service, starts and verifies Docker, configures private HTTPS, and disables only shrinkray.service after all health checks pass. On failure after the native service is stopped, it stops only the failed Shrinkray container, restores the backups, reloads systemd, restarts the old service, and verifies its previous local endpoint. It does not alter port 443, other services, media, state, or unrelated Docker data.

An optional watchdog can check the container and private route every five minutes. The repository does not enable it automatically. The supplied unit assumes the repository is installed at /opt/shrinkray; edit both paths if it is elsewhere:

sudo install -m 0644 deploy/systemd/shrinkray-watchdog.service \
  /etc/systemd/system/shrinkray-watchdog.service
sudo install -m 0644 deploy/systemd/shrinkray-watchdog.timer \
  /etc/systemd/system/shrinkray-watchdog.timer
sudo systemctl daemon-reload
sudo systemctl enable --now shrinkray-watchdog.timer

The watchdog checks for the container, verifies running state, container health, and local API health, then restarts only Shrinkray if needed. It restores only the configured port-8443 Serve route when missing and never changes port 443 or unrelated Serve routes. Disable it with sudo systemctl disable --now shrinkray-watchdog.timer.

Install

Shrinkray supports Ubuntu Server and Linux Mint. The installer adds ffmpeg with apt-get when it is missing, then installs the shrinkray command for your user.

curl -fsSL https://raw.githubusercontent.com/AmirIqbal1/shrinkray/main/install.sh | bash

Open a new terminal after installation, then check that everything is ready:

shrinkray doctor

To install from a clone instead:

git clone https://github.com/AmirIqbal1/shrinkray.git
cd shrinkray
./install.sh

For a system-wide installation in /usr/local/bin:

curl -fsSL https://raw.githubusercontent.com/AmirIqbal1/shrinkray/main/install.sh | bash -s -- --system

The default user installation goes to ~/.local/bin and does not need sudo unless ffmpeg must be installed.

Quick start

On Ubuntu Server or Linux Mint, the basic workflow is the same:

shrinkray ~/Movies/movie.mkv

Choose another target size or spend more time improving compression:

shrinkray ~/Movies/movie.mkv --size 700 --quality best

Process one directory:

shrinkray --batch ~/Movies --size 500

Include its subdirectories:

shrinkray --batch ~/Movies --recursive --size 500

Software video encoding is CPU-intensive and may be slow, especially with --quality best or the explicitly requested AV1 codec. Start with the default HEVC mode unless you specifically need AV1.

Options

Flag What it does Default
--size <MB> Target output size in whole megabytes 500
--quality <fast|good|best> Trade encoding time for compression quality good
--codec <auto|hevc|av1> Select the video encoder auto (HEVC)
--container <mkv|mp4> Select the output container mkv
--keep-all-audio Keep all audio tracks instead of the first one off
--output <path> Set a custom output for one input file automatic
--batch <dir> Process videos in a directory
--recursive Include subdirectories with --batch off
--dry-run Show planned work without encoding off
--machine-progress Emit FFmpeg key/value progress for dashboards or automation off
-y Replace an existing output without asking off

Run shrinkray --help for usage examples.

Safety

Shrinkray never deletes or replaces the source movie. It encodes to a temporary file ending in .part, validates that file with ffprobe, and only then moves it to the requested output name. Failed and interrupted encodes are cleaned up.

Disk space safety

Before each encode, Shrinkray checks free space on the filesystem containing the output directory. It requires the target output size, a 512 MB encoder working allowance, and a safety reserve equal to the larger of 2 GB or 10% of that filesystem's capacity. Queued dashboard jobs are checked again immediately before encoding because available space can change while they wait.

While an encode is active, Shrinkray continues checking the destination. If free space falls below the critical 512 MB floor, it stops the encoder and removes only its .part output and temporary encoder files. This protection never deletes or modifies the original movie or unrelated files.

Hardware acceleration

HEVC jobs accept --encoder auto|software|qsv|vaapi|nvenc. Auto mode checks the FFmpeg build, accessible DRM render devices, advertised hardware APIs, and a short generated-frame runtime encode before selecting Intel QSV, VAAPI, NVIDIA NVENC, or software x265 in that order. An encoder name in ffmpeg -encoders alone is not treated as proof that the GPU works. Use shrinkray doctor to see the detected devices, verified HEVC backends, and current auto selection.

Software remains fully supported and keeps Shrinkray's existing two-pass x265 behavior. Hardware encoding is single-pass and prioritizes speed, so its final size may vary somewhat more from the requested target. In auto mode, a hardware initialization/encode failure removes Shrinkray's exact temporary output and retries safely with software. An explicitly requested hardware backend fails clearly instead of silently changing the request.

The normal Compose configuration requires no GPU. The management script uses SHRINKRAY_HWACCEL=auto to pass through one detected /dev/dri/renderD* device and only its numeric supplementary group, or an available NVIDIA container runtime. Set it to none, dri, or nvidia in .env to choose explicitly; SHRINKRAY_DRM_RENDER_DEVICE can select a particular render node. Equivalent manual deployments can use compose.hwaccel.yaml or compose.nvidia.yaml as an additional Compose file. No privileged mode, device permission changes, or GPU driver installation is performed. scripts/shrinkray-docker.sh doctor reports host devices, permissions, container visibility, NVIDIA runtime availability, and the container's verified encoder capabilities.

MKV output keeps global metadata, chapters, and available subtitles. MP4 output drops subtitles because common movie subtitle formats are not always compatible with MP4. Audio is optional, so silent videos work too.

The target size is approximate. Shrinkray warns when the requested target is not smaller than the source.

Diagnostics

shrinkray doctor

This shows the shrinkray version and installation path, the installed ffmpeg and ffprobe versions, and whether HEVC and AV1 software encoders are available.

Uninstall

For a user installation:

rm ~/.local/bin/shrinkray

For a system installation:

sudo rm /usr/local/bin/shrinkray

Licence

Shrinkray is free software licensed under the GNU General Public License, version 3.0 (GPL-3.0).

Directories

Path Synopsis
cmd
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL