Skip to main content

py-media-server

A simple, lightweight media server for streaming video files over HTTP with a modern web interface.

Features

  • 🎬 Stream video files (MP4, MKV, AVI, MOV, M4V, WebM) from any directory
  • 📂 Recursive scanning — subfolders are browsed, filtered and searched
  • 🔍 Search, sort (name / newest / largest / longest) and folder filter, all preserved in the URL so a view can be bookmarked or shared
  • ⏯️ Resume where you left off, with a Continue watching row and progress bars on tiles
  • 💬 Sidecar subtitles (.srt / .vtt) discovered automatically and served as WebVTT, with language labels
  • ⚠️ Codec compatibility check via ffprobe, with on-demand transcoding for files the browser cannot play natively
  • ▶️ Full custom player — play/pause, ±10s skip, next/previous, seek bar, volume, playback speed, fullscreen and keyboard shortcuts
  • ⏭️ Auto-advance to the next video when one finishes
  • 🖼️ Automatic thumbnail generation using FFmpeg
  • 📱 Responsive web interface that works on mobile and desktop
  • ⚡ Range request support for efficient video streaming
  • 🔒 Threaded TCP server for concurrent connections
  • 🎨 Modern, dark-themed UI

Installation

From PyPI (when published)

pip install py-media-server

From source

git clone https://github.com/pandiyarajk/py-media-server.git
cd py-media-server
pip install -e .

Requirements

  • Python 3.11+
  • FFmpeg and ffprobe (optional)

FFmpeg is optional but unlocks three features: thumbnail generation, codec inspection (duration, resolution, "may not play" warnings) and on-demand transcoding. Without it the server still browses and streams — the affordances that would not work are simply not rendered.

The server looks for ffmpeg/ffprobe on PATH first, then in common install locations (C: fmpegin, Homebrew, /usr/local/bin, the winget shim directory, etc.), so a normal install is picked up even when it was never added to PATH. If it lives somewhere unusual, point at it directly:

py-media-server ~/Videos --ffmpeg /opt/custom/ffmpeg/bin
# or the binary itself:
py-media-server ~/Videos --ffmpeg /opt/custom/ffmpeg/bin/ffmpeg

PY_MEDIA_SERVER_FFMPEG (path to the binary or its directory) works the same way as an environment variable.

To install FFmpeg:

  • Windows: Download from ffmpeg.org or use choco install ffmpeg
  • macOS: brew install ffmpeg
  • Linux: sudo apt-get install ffmpeg or sudo yum install ffmpeg

Usage

Basic usage

Serve media files from the current directory:

py-media-server

Or specify a directory:

py-media-server /path/to/your/movies

Custom port

py-media-server /path/to/your/movies --port 9000

Custom host and port

py-media-server ~/Videos --host 192.168.1.100 --port 8080

Help

py-media-server --help

Command-line Options

positional arguments:
  directory             Directory containing media files to serve (default: current directory)

optional arguments:
  -h, --help            show this help message and exit
  -p PORT, --port PORT  Port to run the server on (default: 8000)
  --host HOST           Host to bind the server to (default: 0.0.0.0)
  --ffmpeg PATH         Path to ffmpeg, or the directory holding it, for
                        installs not on PATH or in a common location
  -v, --version         show program's version number and exit

How it Works

  1. Start the server: Point it to a directory containing video files
  2. Open your browser: Navigate to http://localhost:8000
  3. Browse and play: Click on any video thumbnail to start streaming

The server will:

  • Scan the directory and its subfolders for supported video formats (directories beginning with . are skipped)
  • Generate thumbnails automatically (stored in the .thumbs subdirectory, alongside cached probe metadata and watch progress)
  • Serve videos with range request support for smooth playback
  • Handle concurrent connections efficiently

Library view

The index page offers a search box, a sort selector and a folder filter. The active view is written to the URL fragment, so a filtered listing can be bookmarked or shared. Files you have started appear in a Continue watching row, and every tile shows a progress bar plus badges for resolution, duration, subtitles and playback warnings.

Subtitles

Sidecar files next to the video are picked up automatically:

Shows/S01/ep01.mkv
Shows/S01/ep01.srt          -> "Subtitles"
Shows/S01/ep01.en.srt       -> "EN"
Shows/S01/ep01.English.vtt  -> "English"

SRT is converted to WebVTT on the fly, so no pre-processing is needed. Encodings other than UTF-8 (including BOM-prefixed and CP1252 files) are decoded rather than rejected.

Compatibility and transcoding

When ffprobe is available the server inspects each file as you open it and flags anything the browser is unlikely to play — HEVC video, AC3/DTS audio, or an MKV container. The player then offers a Play anyway (transcode) button, which streams a converted copy from ffmpeg. Only the parts that need it are re-encoded: an MKV of h264/AAC is remuxed, AC3 audio alone is re-encoded without touching the video, and a full transcode is the last resort.

Two transcodes run at once; further requests get a 503 rather than overloading the machine.

Player

Clicking a tile opens the player at /play/<filename>. The page is served with the whole library as its playlist, so next/previous move through the same sorted listing shown on the home page (disabled at the ends).

Controls

Button Action
Previous video
Back 10 seconds
▶ / ⏸ Play / pause
Forward 10 seconds
Next video
🔊 Mute, with a volume slider
1x Playback speed (0.5x – 2x)
Fullscreen

A draggable seek bar shows elapsed and total time.

Keyboard shortcuts

Key Action
Space / K Play / pause
/ Seek 10 seconds
/ Volume up / down
N Next video
P Previous video
M Mute
C Cycle subtitle track
F Fullscreen

Development

Setup development environment

git clone https://github.com/pandiyarajk/py-media-server.git
cd py-media-server
pip install -e ".[dev]"

Run tests

pytest

Run tests with coverage

pytest --cov=py_media_server --cov-report=html

Project Structure

py-media-server/
├── py_media_server/
│   ├── __init__.py
│   ├── server.py
│   └── templates.py
├── tests/
│   ├── __init__.py
│   └── test_server.py
├── setup.py
├── pyproject.toml
├── README.md
├── LICENSE
└── MANIFEST.in

Security Notice

⚠️ Warning: This server is intended for local network use only. It does not include authentication or encryption. Do not expose it to the public internet without proper security measures.

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Changelog

0.3.0 (2026-08-15)

  • ffmpeg/ffprobe are discovered in common install locations, and via --ffmpeg / PY_MEDIA_SERVER_FFMPEG, when absent from PATH
  • Recursive scanning of subfolders
  • Search, sort and folder filtering, with the view reflected in the URL
  • Resume playback, "Continue watching" row and per-tile progress bars
  • Sidecar subtitle discovery with SRT-to-WebVTT conversion
  • Codec compatibility warnings via ffprobe
  • On-demand transcoding for files the browser cannot play
  • Optional features are hidden when ffmpeg is unavailable rather than rendered broken
  • Page markup and scripts split out into templates.py
  • Minimum supported Python raised to 3.11

0.2.0 (2026-08-15)

  • Full custom player: play/pause, ±10s skip, next/previous, seek bar, volume, playback speed, fullscreen, keyboard shortcuts, auto-advance
  • Unmatched routes now return 404 instead of closing the connection with no response
  • Range requests are clamped to the file size
  • Filenames are escaped when embedded in page scripts

0.1.0 (2026-04-19)

  • Initial release
  • Basic video streaming functionality
  • Thumbnail generation
  • Web interface
  • Command-line interface

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py_media_server-0.3.0.tar.gz (48.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

py_media_server-0.3.0-py3-none-any.whl (29.4 kB view details)

Uploaded Python 3

File details

Details for the file py_media_server-0.3.0.tar.gz.

File metadata

  • Download URL: py_media_server-0.3.0.tar.gz
  • Upload date:
  • Size: 48.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for py_media_server-0.3.0.tar.gz
Algorithm Hash digest
SHA256 62791439d6af0e1636e0657ebb1b2d273975cf1f4633d569f1ec891ecd7688a9
MD5 4c07c0eae4737498b8c8f78720dddae2
BLAKE2b-256 ba497d1edcfb0f7526adf66068008278879e3fc64f1d2407643b979389f394b4

See more details on using hashes here.

File details

Details for the file py_media_server-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for py_media_server-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5dd33f94c82efcbb6b6f1cf82cda376e3a704d0f3f3a2eba05f89c61bb3addb2
MD5 f2f58d6daf4c66816e7df1cebccabe38
BLAKE2b-256 2f0c17ac11f7e47696b596981bd1f3b9b4e50b18140f9f764fd7dc91e7280f67

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page