A local video streaming server that delivers films and video files from a directory tree over the network, with a modern web UI for browsing, filtering, and playing videos in any browser — featuring automatic H.264 transcoding for unsupported codecs.
What is XteVision Media Server and who is it for?
XteVision Media Server (xtevision-media-server v1.0.0) is a local video streaming server that delivers films and video files from a directory tree over the network. It offers a modern web UI for browsing, filtering, and playing videos in any browser — without additional software installation on the client. It is designed to be re-branded and run by any company.
High-level design and communication flow
┌─────────────────────────────────────────────────────────────────┐
│ Browser (any modern browser) │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────────────────┐ │
│ │ Video │ │ Category │ │ Video Player (HTML5 modal) │ │
│ │ Grid │ │ Filters │ │ + Smart Codec Fallback │ │
│ └──────────┘ └──────────┘ └──────────────────────────────────┘ │
└──────────────────────────────┬──────────────────────────────────┘
│ HTTP/REST API
┌──────────────────────────────┴──────────────────────────────────┐
│ Node.js Server — Express.js (port 5002) │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ /videos │ │ /thumbnail│ │ /video/ │ │ FFmpeg (transcode) │ │
│ │ (list) │ │ (JPEG) │ │ original │ │ H.264 + AAC │ │
│ │ │ │ │ │ /h264 │ │ │ │
│ └───────────┘ └───────────┘ └───────────┘ └──────────────────┘ │
└──────────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────────┴──────────────────────────────────┐
│ Filesystem (source of truth) │
│ video/ → folder tree (categories) │
│ .cache/ → h264/ + thumbnails/ │
└───────────────────────────────────────────────────────────────────┘GET /videos lists all files; GET /thumbnail/... fetches JPEGs; GET /video/original/... and GET /video/h264/... stream mediareaddirSync() reads the video/ tree on every /videos callXteVision Media Server is designed for self-hosted, LAN-only operation:
ffmpeg-staticFrontend, backend, and infrastructure technologies
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Node.js ≥ 18 | Server runtime |
| Server | Express.js | HTTP server + API routes |
| Transcoding | fluent-ffmpeg + ffmpeg-static | FFmpeg control + embedded binary |
| Storage | Filesystem | Sources of truth (video/, .cache/) |
| Frontend | Vanilla HTML/CSS/JS | Single-page app, no framework |
| I18n | Client-side data-lang-* | EN / DE / ZH translation |
ffmpeg-static — no system installation required. The server ignores files starting with a dot (e.g. Apple Double ._file.mp4).Get XteVision Media Server running on your server
# 1. Switch to the project directory
cd /path/to/video_server
# 2. Install dependencies
npm install
The following packages are installed:
| Package | Purpose |
|---|---|
| express | HTTP server and routing |
| fluent-ffmpeg | FFmpeg control for video transcoding |
| ffmpeg-static | FFmpeg binary (no system installation needed) |
npm start
# or: node server.js
The server then runs on http://localhost:5002. Console output on successful start:
Using ffmpeg: /path/to/ffmpeg-static
Video server running at http://localhost:5002
nohup node server.js > server.log 2>&1 &
The video directory and supported formats
All videos live in the video/ folder in the project directory. The structure is organized by customer/project:
video/
├── Anting/
│ ├── anting.mp4
│ ├── biergarten720p.m4v
│ └── tiky_xuyun720p50.mp4
├── Porsche_VW/
├── Deutsche-Schule/
├── prodigy/
│ ├── prodigy_cn.mp4
│ ├── prodigy_de.mp4
│ └── prodigy_en.mp4
└── ...
video//videos call.) — e.g. Apple Double ._file.mp4.| Format | Extension | MIME-Type |
|---|---|---|
| MPEG-4 | .mp4 | video/mp4 |
| QuickTime | .mov | video/quicktime |
| MPEG-4 Video | .m4v | video/x-m4v |
| Matroska | .mkv | video/x-matroska |
| AVI | .avi | video/x-msvideo |
| WebM | .webm | video/webm |
Browsing, filtering, and playing videos
The web UI at http://localhost:5002 is divided into three areas:
localStorage), and a theme toggle (dark/light)Clicking a video opens an overlay player:
× or press EscThe player automatically detects whether the browser can play the video natively:
Direct HTTP access to data and media
| Endpoint | Description |
|---|---|
| GET /videos | Lists all video files as a JSON array |
| GET /thumbnail/{path} | Returns a JPEG thumbnail; generated on demand, then cached for 24 hours |
| GET /video/original/{path} | Streams the original file with HTTP range support (seeking in the timeline) |
| GET /video/h264/{path} | Streams an H.264-transcoded version; transcoded on first call, then cached |
# List all videos
curl http://localhost:5002/videos
# Get a thumbnail
curl http://localhost:5002/thumbnail/Anting/anting.mp4
# Stream the original (with range support)
curl http://localhost:5002/video/original/Anting/anting.mp4
# Stream an H.264-transcoded version
curl http://localhost:5002/video/h264/Anting/anting.mp4
/videos:[
"Anting/anting.mp4",
"Anting/biergarten720p.m4v",
"prodigy/prodigy_cn.mp4"
]
Transcoding, thumbnails, and cache management
When a video cannot be played natively, the server automatically transcodes it to H.264 + AAC — the format every modern browser can play.
| Parameter | Value |
|---|---|
| Video Codec | libx264 |
| Audio Codec | aac |
| Pixel Format | yuv420p |
| Profile | main |
| Preset | veryfast (fast, acceptable quality) |
| Quality | CRF 23 |
| Streaming | frag_keyframe+empty_moov (immediate playback) |
To relieve the server, thumbnail generations are queued and concurrent requests for the same thumbnail are deduplicated. Generated thumbnails live in .cache/thumbnails/ and are served directly for 24 hours (Cache-Control: public, max-age=86400).
.cache/
├── h264/ # H.264-transcoded videos
└── thumbnails/ # JPEG thumbnails
Both directories mirror the folder structure of video/. To clear the cache (e.g. after changes to the original files):
# Delete cache subdirectories
rm -rf .cache/h264/* .cache/thumbnails/*
# Or delete the whole cache folder
rm -rf .cache
Common issues and solutions
lsof -i :5002, then kill the process (kill -9 [PID]).Using ffmpeg: undefined means ffmpeg-static is not installed correctly — run npm install ffmpeg-static..cache/h264/ folder is writable.video/. Filenames with special characters are expected URL-encoded..cache/thumbnails/ is writable.-ss 2).