Skip to content

Repository files navigation

Media Converter

A self-hosted web application for converting video files between formats and extracting audio from video files. Built with Python/Flask and powered by FFmpeg.


Table of Contents


Features

  • Video Format Conversion — Convert between popular video formats (MP4, AVI, MKV, MOV, WMV, FLV, WebM)
  • Audio Extraction — Extract audio tracks from video files (MP3, AAC, WAV, FLAC, OGG)
  • Social Media Downloader — Download media from YouTube, Instagram, TikTok, X/Twitter, and Spotify with mode selection (video/audio), quality presets, and abort support
  • Media Library Page — Browse converted/ and downloads/ in a simple web file browser with selectable multi-file download
  • Resolution Scaling — Upscale or downscale video (480p, 720p, 1080p, 1440p, 4K) with high-quality Lanczos filtering
  • GPU Acceleration — Automatically uses hardware encoding (NVIDIA NVENC, AMD AMF, Intel QSV, VA-API) when available, with seamless CPU fallback
  • Real-time Progress — Live progress bar with speed and ETA during conversion
  • Abort Support — Cancel in-progress conversions with automatic cleanup
  • No File Size Limits — Upload files of any size
  • Automatic Cleanup — Temporary uploads and converted files are automatically deleted after 24 hours
  • Persistent Downloads — Downloaded media is stored under downloads/<service>/ and is never auto-deleted
  • Dark/Light Mode — Modern UI with dark mode as default and easy toggle
  • Docker Ready — Run with GPU support via Docker Compose in one command
  • Self-Contained — Runs in a Python virtual environment with minimal dependencies

Quick Start

🐳 Docker (recommended)
git clone https://github.com/M1XZG/media-converter.git
cd media-converter
docker compose up -d

Open http://localhost:5000. GPU acceleration works automatically if you have an NVIDIA GPU and the NVIDIA Container Toolkit installed.

Driver compatibility: the image is based on nvidia/cuda:12.6.3. The NVIDIA Container Toolkit will refuse to start a CUDA image that is newer than your host driver supports, so if GPU startup fails with a cuda>=... requirement error, either update your NVIDIA driver or pin the FROM line in the Dockerfile to a CUDA version your driver supports.

Without GPU support:

Remove the gpus: all line (and the NVIDIA_* environment variables) from docker-compose.yml, or run directly:

docker build -t media-converter .
docker run -d -p 5000:5000 --name media-converter media-converter
📥 Downloader-only instance

You can split the app so a public instance only exposes the downloader and can't be used to convert large video files on your server. Set the ENABLE_CONVERTER feature flag to false (both halves are enabled by default):

git clone https://github.com/M1XZG/media-converter.git
cd media-converter
ENABLE_CONVERTER=false docker compose up -d

Or run directly without the converter:

docker build -t media-converter .
docker run -d -p 5000:5000 \
  -e ENABLE_CONVERTER=false \
  -e ENABLE_FILE_MANAGER=false \
  -v "$(pwd)/downloads:/app/downloads" \
  --name media-downloader media-converter

When the converter is disabled, its UI and its HTTP routes are turned off (disabled endpoints return 403). To run a converter-only instance instead, set ENABLE_DOWNLOADER=false. For a public server, also set ENABLE_FILE_MANAGER=false so visitors can't browse what others have downloaded. See Configuration for the full list of deployment combinations.

🪟 Windows

Prerequisites: Python 3.10+ and FFmpeg on your PATH.

git clone https://github.com/M1XZG/media-converter.git
cd media-converter
setup.bat
🐧 Linux / macOS

Prerequisites: Python 3.10+ and FFmpeg on your PATH.

git clone https://github.com/M1XZG/media-converter.git
cd media-converter
chmod +x setup.sh
./setup.sh
⚙️ Manual Setup

Prerequisites: Python 3.10+ and FFmpeg on your PATH.

# Create and activate virtual environment
python -m venv venv

# Windows:
venv\Scripts\activate
# Linux/macOS:
source venv/bin/activate

# Install dependencies and run
pip install -r requirements.txt
python app.py

Then open your browser to http://localhost:5000

Media Library page: http://localhost:5000/files

Downloader support: YouTube, Instagram, TikTok, X/Twitter, Spotify


Installing FFmpeg

FFmpeg must be installed and available on your system PATH (not required for Docker — it's included in the image). yt-dlp is installed automatically via pip from requirements and is used for YouTube, Instagram, TikTok, and X/Twitter downloads. spotdl is installed automatically via pip from requirements and is used for Spotify downloads. Because Spotify streams are DRM-protected, spotdl reads the track metadata and fetches the matching audio from YouTube, so Spotify links are always saved as audio.

Public posts generally work best. Some Instagram or X/Twitter links may require authentication or cookies depending on upstream site restrictions.

Windows
# Via winget
winget install FFmpeg

# Or via Chocolatey
choco install ffmpeg
macOS
brew install ffmpeg
Ubuntu / Debian
sudo apt update && sudo apt install ffmpeg

GPU Acceleration

The application automatically detects and uses GPU hardware encoders when available. On startup, the console and the web UI will show whether GPU acceleration is active.

GPU encoding is used for MP4, MKV, and MOV output. Other formats and audio extraction use CPU encoding.

Supported GPU encoders
GPU Vendor Encoder Requirements
NVIDIA NVENC NVIDIA GPU + driver 470+, FFmpeg built with --enable-nvenc
AMD AMF AMD GPU + Adrenalin driver, FFmpeg built with --enable-amf
Intel QSV Intel iGPU/dGPU + media driver, FFmpeg built with --enable-libmfx or --enable-libvpl
Linux (generic) VA-API VA-API capable GPU + libva, FFmpeg built with --enable-vaapi

When upscaling, quality settings are automatically increased (lower QP/CRF, slower presets) and a post-processing filter chain is applied (sharpening + denoising) for the best possible output.


Configuration

Environment variables can be set in a .env file or exported:

Variable Default Description
FLASK_HOST 0.0.0.0 Host to bind to
FLASK_PORT 5000 Port to listen on
MAX_CONTENT_LENGTH 0 (unlimited) Max upload size in bytes (0 = no limit)
CLEANUP_HOURS 24 Hours before uploaded/converted temp files are auto-deleted
DOWNLOADS_CLEANUP_MINUTES 30 Minutes before downloaded files are auto-deleted (0/off/disabled = keep forever)
ENABLE_CONVERTER true Enable the video converter / audio extractor / GIF maker
ENABLE_DOWNLOADER true Enable the social-media downloader
ENABLE_FILE_MANAGER true Enable the "Media Library" file browser at /files (list/download/delete)

Cleanup applies to uploads/ and converted/ (after CLEANUP_HOURS) and to downloads/ (after DOWNLOADS_CLEANUP_MINUTES). The downloads timer effectively starts when a download finishes — files still being written keep a fresh timestamp and are never removed mid-download. Set DOWNLOADS_CLEANUP_MINUTES=0 to keep downloaded files indefinitely.

Splitting the app (converter vs. downloader)

Out of the box both halves are enabled and the app works exactly as before. You can split the functionality using the two feature flags above — useful for hosting a public, downloader-only instance that can't be used to convert large video files on your server:

Deployment Settings
Full app (default) ENABLE_CONVERTER=true, ENABLE_DOWNLOADER=true
Downloader only ENABLE_CONVERTER=false, ENABLE_DOWNLOADER=true
Converter only ENABLE_CONVERTER=true, ENABLE_DOWNLOADER=false

When a half is disabled, both its UI and its HTTP routes are turned off — the disabled endpoints return 403, so the feature can't be triggered by hand-crafted requests. If both flags are set to false, the app falls back to full functionality.

Locking down the file manager (public instances)

The Media Library at /files lets anyone browse, download, and delete every file on the server. On a public instance you usually don't want visitors to see what others have downloaded, so set:

ENABLE_FILE_MANAGER=false

When disabled, the /files page and all /files/* endpoints return 403, the "Media Library" link is removed from the UI, and no browser file retrieval is offered anywhere (downloaded files are saved to the server only). Converter output is still delivered through its own /download/<id> link.

Example — spin up a standalone downloader on another server:

# docker-compose.yml (public downloader-only instance)
services:
  media-downloader:
    build: .
    ports:
      - "5000:5000"
    environment:
      - ENABLE_CONVERTER=false
      - ENABLE_DOWNLOADER=true
      - ENABLE_FILE_MANAGER=false
    volumes:
      - ./downloads:/app/downloads
    restart: unless-stopped

Supported Formats

Video output formats
Format Extension
MP4 .mp4
AVI .avi
MKV .mkv
MOV .mov
WMV .wmv
FLV .flv
WebM .webm
Audio output formats
Format Extension
MP3 .mp3
AAC .aac
WAV .wav
FLAC .flac
OGG .ogg
Supported input formats

MP4, AVI, MKV, MOV, WMV, FLV, WebM, M4V, MPEG, MPG, 3GP, OGV, TS, VOB


Project Structure

media-converter/
├── app.py              # Flask application
├── cleanup.py          # File cleanup utility
├── requirements.txt    # Python dependencies
├── Dockerfile          # Docker image definition
├── docker-compose.yml  # Docker Compose with GPU support
├── .dockerignore       # Docker build exclusions
├── setup.bat           # Windows setup script
├── setup.sh            # Linux/macOS setup script
├── .gitignore
├── README.md
├── templates/
│   ├── index.html      # Main web UI
│   └── files.html      # Simple media library browser
├── uploads/            # Temporary upload storage (auto-created)
├── converted/          # Temporary converted file storage (auto-created)
└── downloads/
    ├── youtube/         # Persistent YouTube downloads (not auto-cleaned)
    ├── instagram/       # Persistent Instagram downloads (not auto-cleaned)
    ├── tiktok/          # Persistent TikTok downloads (not auto-cleaned)
    ├── twitter/         # Persistent X/Twitter downloads (not auto-cleaned)
    └── spotify/         # Persistent Spotify downloads (not auto-cleaned)

Security

Media Converter is designed as a self-hosted tool for a trusted network (your own machine or LAN). Please read this before exposing it to the internet.

  • There is no authentication. Anyone who can reach the port can upload, convert, download media, browse the library, and delete files. Do not expose the app directly to the public internet. If you need remote access, put it behind a reverse proxy (nginx, Caddy, Traefik) that enforces authentication and TLS, or restrict access with a VPN or firewall rules.
  • It binds to 0.0.0.0 by default so it is reachable from other machines on your network. Set FLASK_HOST=127.0.0.1 to restrict it to the local machine only.
  • Uploads are unlimited by default (MAX_CONTENT_LENGTH=0). On a shared or exposed host this allows disk-fill denial of service. Set MAX_CONTENT_LENGTH (in bytes) to cap upload size, for example MAX_CONTENT_LENGTH=2147483648 for a 2 GB limit.
  • The downloads/ folder is never auto-cleaned. Downloaded media persists until you delete it, so monitor disk usage if you use the downloader heavily.
  • FFmpeg and yt-dlp process untrusted media and URLs. Keep them up to date so you pick up upstream security fixes (pip install -U -r requirements.txt, and update FFmpeg via your package manager or the Docker base image).

To report a security vulnerability, please use GitHub's private vulnerability reporting (see SECURITY.md). Do not open a public issue for security problems.


License

MIT License

About

Self-hosted video converter and audio extractor with GPU acceleration. Convert between video formats, extract audio, upscale resolution — all through a modern web UI. Supports NVIDIA NVENC, AMD AMF, Intel QSV. Docker ready.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages