A local web workspace for media. Downloads, compression, audio EQ, encoding utilities, and a PDF engine — all running on your machine, in your browser, behind a single PHP server.
Nothing phones home. Nothing asks you to sign in. Nothing limits you to three files a day.
Seven tools, roughly in order of how often I use them.
Video Downloader — Paste a URL, pick a resolution, hit go. Or extract just the audio as MP3. Batch mode takes a .txt or .csv and chews through a list unattended. yt-dlp's output streams live into the browser as it works — no black box.
EQ Studio — A 13-band equalizer tuned for the Marshall Major IV, but useful for anything. Load a file, drag the sliders, listen. Batch mode applies the same curve across an entire folder. Preamp gain included so you don't clip.
Video Compressor — Drop a video, pick a CRF, walk away. Detects HDR, picks a hardware encoder if your GPU has one (NVENC / AMF / QuickSync), falls back to x265 on CPU. Non-MP4 inputs get converted automatically.
IG-Image — Lossless image compression that actually verifies its output. Every candidate gets decoded back and compared pixel-by-pixel against the original. If it doesn't match, it doesn't ship. Handles single files, multi-file drops, or an entire folder. Batch download as .zip.
Base64 Converter — Image → Base64 string or Base64 → image. Also useful for pasting a data URI back and forth when you're debugging CSS or building an inline asset.
PageWright — HTML → PDF. Write HTML and CSS on the left, see live pagination on the right, print to PDF. Pure PHP, no wkhtmltopdf, no headless Chrome, no external service.
Update — Reserved. Ignore for now.
- PHP 8 or newer
ffmpeg,ffprobe, andyt-dlpon your PATH- A modern browser
Don't have yt-dlp? pip install -U yt-dlp, or grab a binary from their releases page. FFmpeg is in every package manager worth using.
git clone https://github.com/yourname/tpg-media-tools.git
cd tpg-media-toolsIf you'd rather keep the binaries contained, drop them in bin/:
bin/
├── ffmpeg
├── ffprobe
└── yt-dlp
Then point PATH at that folder.
Windows — System Properties → Advanced → Environment Variables → Path → add the folder. Close and reopen your terminal or it won't take.
macOS / Linux — add to your shell rc:
export PATH="$PATH:/path/to/project/bin"Reload the shell.
Run it:
php -S localhost:8000Open http://localhost:8000.
That's it. No build step. No npm install. No database.
Frontend sends a POST to download.php. The PHP side runs yt-dlp and pipes stdout back to the browser as a stream. You see yt-dlp's own output — progress bars, format selection, merge steps, everything. Some of it is ugly. That's fine. It tells you exactly what's happening.
Batch mode accepts one URL per line. Format selection applies to every entry in the batch.
Built around FFmpeg's equalizer filter chain. Thirteen bands from 31 Hz to 20 kHz, ±30 dB each, plus a preamp stage. Presets are stored client-side. Batch mode walks a folder and applies the same curve to every audio file inside.
If you're using the Marshall Major IV defaults that ship with the tool, it's a mild smile curve — slight bass lift, slight presence bump, small cut at 500 Hz. Change it however you want; the defaults are just a starting point.
The pipeline is: ffprobe → detect codec, bitrate, color space, HDR metadata → pick encoder → build an FFmpeg command with sane flags → run it.
Hardware encoder order is NVENC → AMF → QuickSync → x265 CPU. If your GPU driver is out of date or the encoder isn't available, it falls back silently. The log tells you which path it took.
HDR content stays 10-bit. If you override the flags manually and force 8-bit, gradients will band. That's not a bug, that's how color depth works.
(Images already have show above)
The interesting part: it doesn't trust the encoder. For each input, it generates candidates (PNG, lossless WebP) and then decodes each candidate back and compares it pixel-by-pixel against the original. Using a Uint32Array view over the ImageData buffer, so it's fast enough to feel instant even on large images.
Only candidates that pass the pixel check are eligible. Among the survivors, the smallest one wins. If nothing beats the original size, you get the original back with a "no reduction" note — no fake savings.
Batch mode: drop files, drop a folder, or both. Each entry shows its own status. When the queue finishes, download everything as a single .zip.
Two modes. Image → string, string → image. Detects the MIME type from the Base64 prefix if you paste a bare string. Nothing fancy, but it's the tool I reach for most when building inline SVG assets or debugging a broken data URI.
A self-contained HTML → PDF engine written in pure PHP. No external binaries, no headless browser, no Composer dependencies. It parses HTML, matches CSS selectors, lays out a document, paginates it, and writes the PDF byte stream by hand.
The frontend shows live pagination — you see the actual page breaks as you type. Diagnostics panel tells you what's supported and what isn't. Flexbox and grid aren't implemented; block and inline layout are. That's a real limitation and the diagnostics panel says so.
The Generate button uses the browser's own print-to-PDF. This keeps the client-side preview and the final output consistent — the same rendering engine, top to bottom.
project/
├── bin/
│ ├── ffmpeg
│ ├── ffprobe
│ └── yt-dlp
│
├── index.html Hub page — links to everything
├── downloader.html
├── convert.html
├── vidcom.html
├── base64.html
├── ig-image.html
├── pagewright.php
│
├── download.php Backend for the downloader
├── compress.php Backend for the compressor
├── convert.php Backend for EQ Studio
├── got_path.php Returns the default save path
│
├── style.css Shared stylesheet
├── tools.json Tool registry (for the site manager)
│
└── manager.py Optional site manager (see below)
There's a small Python app called manager.py that runs a local web GUI for editing the site itself — adding new tool pages, reordering the navigation, syncing the nav across every HTML file, previewing changes as a diff, and rolling back from automatic backups.
python manager.pyOpens http://127.0.0.1:8765. Not required to use any of the media tools. It's for when you're adding your own tool to the suite.
Don't put this on the internet. No authentication, no rate limiting, no CSRF protection, and the backend shells out to binaries that fetch arbitrary URLs on command. It's a local tool. Keep it that way. If you need it from another machine, use a VPN or an SSH tunnel — not a port forward.
Update yt-dlp often. Sites change their internals constantly. When downloads start failing for no obvious reason, it's almost always yt-dlp needing an update. yt-dlp -U fixes most of it.
Hardware encoders are best-effort. If NVENC isn't detected, it's usually a driver issue or a GPU that predates the feature. The compressor tells you which encoder it picked in the log — check that first before assuming something's broken.
The console output is raw. It's yt-dlp and ffmpeg talking directly to the browser. Some of it looks like garbage. It's not decoration; it's the actual state of the process.
Large batches take time. The image optimizer processes one file at a time to keep memory flat. A folder of 200 photos will take a few minutes even on fast hardware. That's the tradeoff for not crashing the tab.
PageWright's CSS support is deliberately limited. Block and inline layout, text wrapping, tables, lists, margins, padding, borders, colors, font properties. No flexbox, no grid, no floats, no @media, no custom properties. The diagnostics panel is honest about this. If you need full CSS, use a headless browser; if you want zero dependencies, this is what you get.
Downloads → ~/Videos/Download
Compressed → ~/Videos/Compress
EQ output → chosen per-run
IG-Image → download from the browser
PageWright → browser print dialog
Both Videos subfolders get created on first use.
GPL v3. If you fork it, keep the license. If you improve it, send a pull request.