video_press/README.md

215 lines
5.8 KiB
Markdown
Raw Permalink Normal View History

2026-03-09 17:42:26 -05:00
# VideoPress — FFmpeg Video Compressor
2026-03-09 17:54:34 -05:00
NOTE: This application was built with the help of AI.
- [x] The application code has been reviewed by this developer.
- [x] The application code has been tested by this developer.
If you find any issues, please feel free to post an issue, and / or a pull request for a fix.
## What is VideoPress?
2026-03-09 17:42:26 -05:00
A web-based video compression tool served via **Gunicorn + gevent** (WSGI),
containerised with **Docker**. FFmpeg compresses video files to approximately
1/3 their original size. All file-system access is restricted to a single
configurable media root for security.
2026-03-13 09:53:49 -05:00
1. Set your folder to scan, and minimum size to scan for.
2026-03-13 09:49:05 -05:00
![Image 1](screens/VideoPress_Screen_1.png)
2026-03-13 09:46:54 -05:00
2026-03-13 09:53:49 -05:00
2. Select from the files found.
![Image 2](screens/VideoPress_Screen_2.png)
3. Start the Compression and See the Progress
![Image 3](screens/VideoPress_Screen_3.png)
2026-03-17 14:10:44 -05:00
4. Get an email notification when a compresion run finishes.
![Image 4](screens/VideoPress_Screen_4.png)
![Image 5](screens/VideoPress_Screen_5.png)
2026-03-09 17:42:26 -05:00
---
## Quick start with Docker (recommended)
Step. 1. You have two options
2026-03-12 16:53:21 -05:00
A. Build the image
2026-03-12 16:53:21 -05:00
2026-03-12 16:54:21 -05:00
`docker build -t videopress .`
B. Use the pre-built image
2026-03-12 16:53:21 -05:00
2026-03-12 16:54:21 -05:00
Already included in the `docker-compose.yml` file witht his project.
Step 2. Run — replace `/your/video/path` with the real path on your host
2026-03-17 15:26:41 -05:00
If you want to persist data between updates, changes, etc.; then you need to create a "data" directory in the same location you store your 'docker-compose.yml' file.
2026-03-17 15:12:00 -05:00
`mkdir -p data`
2026-03-17 15:26:41 -05:00
Ensure the 'data' directory is accessible with permissions = 775.
`chmod -R 775 ./data`
A. Using `docker run`:
- with an image you build:
2026-03-12 16:55:53 -05:00
```
docker run -d \
2026-03-09 17:42:26 -05:00
--name videopress \
--restart unless-stopped \
-p 8080:8080 \
-v /your/video/path:/media \
2026-03-17 15:12:00 -05:00
-v ./data:/data \
2026-03-09 17:42:26 -05:00
videopress
```
2026-03-17 15:12:00 -05:00
2026-03-17 15:26:41 -05:00
- with the pre-built image:
```
docker run -d \
--name videopress \
--restart unless-stopped \
-p 8080:8080 \
-v /your/video/path:/media \
-v ./data:/data \
bmcgonag/videopress:latest
```
B. Using Docker Compose
2026-03-12 16:53:21 -05:00
`docker compose up -d`
2026-03-09 17:42:26 -05:00
Step 3. Open http://localhost:8080
2026-03-09 17:42:26 -05:00
---
## Bare-metal (without Docker)
### Requirements
| Tool | Version |
|------|---------|
| Python | 3.8+ |
| FFmpeg + FFprobe | any recent |
| pip packages | see requirements.txt |
```bash
2026-03-09 17:54:34 -05:00
# Create a python virtual environment to run in
python3 -m venv videopress
#start the virtual environment
source ./videopress/bin/activate
2026-03-09 17:42:26 -05:00
# Install Python dependencies
pip install -r requirements.txt
# Development server (Flask built-in — not for production)
./start.sh
# Production server (Gunicorn + gevent)
MEDIA_ROOT=/your/video/path ./start.sh --prod
# or on a custom port:
MEDIA_ROOT=/your/video/path ./start.sh --prod 9000
```
---
## Security model
Every API call that accepts a path validates it with `safe_path()` before any
OS operation. `safe_path()` resolves symlinks and asserts the result is inside
`MEDIA_ROOT`. Requests that attempt directory traversal are rejected with
2026-03-17 15:26:41 -05:00
HTTP 403. The container runs as a non-root user (e.g. your id. You can find this by entering the command `id` in the terminal, make note of the number for `uid` - usually 1000).
2026-03-09 17:42:26 -05:00
---
## Architecture
```
Browser ──HTTP──▶ Gunicorn (gevent worker)
├─ GET / → index.html
├─ GET /api/config → {"media_root": ...}
├─ GET /api/browse → directory listing
├─ POST /api/scan → ffprobe metadata
├─ POST /api/compress/start → launch ffmpeg thread
├─ GET /api/compress/progress/<id> ← SSE stream
└─ POST /api/compress/cancel/<id>
```
2026-03-17 15:12:00 -05:00
2026-03-09 17:42:26 -05:00
**Why gevent?** SSE (`/api/compress/progress`) is a long-lived streaming
response. Standard Gunicorn sync workers block for its entire duration.
Gevent workers use cooperative greenlets so a single worker process can
handle many concurrent SSE streams and normal requests simultaneously.
**Why workers=1?** Job state lives in an in-process Python dict. Multiple
worker *processes* would not share it. One gevent worker with many greenlets
is sufficient for this workload. To scale to multiple workers, replace the
in-process job store with Redis.
---
## Environment variables
| Variable | Default | Description |
|----------|---------|-------------|
| `MEDIA_ROOT` | `/media` | Root directory the app may access |
| `PORT` | `8080` | Port Gunicorn listens on |
| `LOG_LEVEL` | `info` | Gunicorn log level |
---
## File layout
```
videocompressor/
2026-03-17 15:12:00 -05:00
├── app
├── __init__.py
├── config.py
├── db.py
├── jobs.py
├── media.py
├── notify.py
└── routes.py
├── wsgi.py
├── gunicorn.conf.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── start.sh
2026-03-09 17:42:26 -05:00
├── README.md
├── templates/
│ └── index.html
└── static/
2026-03-17 15:12:00 -05:00
├── css
└── main.css
└── js
├── app.js
└── modules
├── browser.js
├── compress.js
├── progress.js
├── scan.js
├── session.js
├── settings.js
├── state.js
├── stream.js
├── theme.js
└── utils.js
2026-03-09 17:42:26 -05:00
```
2026-03-17 15:12:00 -05:00
## Contribute
Feel free to clone the repository, make updates, and submit a pull request to make this more feature rich.
Keep in mind, I like to keep things fairly simple to use.
If you need to know too much about ffmpeg and how to configure the perfect compression, then that may be too much for this app, but feel free to fork this repository and make your own as well.