MediaLyze
Self-hosted media library analysis for large video collections
Install / Use
/learn @frederikemmer/MediaLyzeREADME
MediaLyze
<p align="center"> <a href="./LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/License-MIT-yellow.svg"></a> <img alt="Python 3.12" src="https://img.shields.io/badge/Python-3.12-3776AB?logo=python&logoColor=white"> <img alt="FastAPI" src="https://img.shields.io/badge/FastAPI-009688?logo=fastapi&logoColor=white"> <img alt="React 19" src="https://img.shields.io/badge/React-19-149ECA?logo=react&logoColor=white"> <img alt="Docker" src="https://img.shields.io/badge/Docker-Single%20Container-2496ED?logo=docker&logoColor=white"> <img alt="Electron" src="https://img.shields.io/badge/Desktop-Electron-47848F?logo=electron&logoColor=white"> <img alt="SQLite" src="https://img.shields.io/badge/SQLite-07405E?logo=sqlite&logoColor=white"> </p> <p align="center"> Self-hosted media library analysis for large video collections. Scans your libraries and run analyses using <code>ffprobe</code>. Explore technical metadata through a FastAPI + React web UI. </p> <p align="center"> MediaLyze focuses (for now) on just analysis, not playback, scraping, or file modification, READ ONLY on your files! </p>
Why MediaLyze
MediaLyze is built for self-hosted setups that need visibility into large media collections without depending on external services and designed around ffprobe with normalized metadata.
Everything with a simple deployment model: one container, one SQLite database, one UI. Bring your own auth (for now).
Features
- Technical media analysis powered by
ffprobe - Full and incremental scans using
path + size + mtime - Normalized formats, streams, subtitles, scan jobs, and quality scores (feel free to suggest improvements)
- Detection of internal and external subtitle files
- Native desktop packaging for Windows, macOS, and Linux in addition to the Docker/web deployment path
- Ignore files and folders with simple glob patterns such as
*.nfoor*/Extras/* - SQLite with WAL mode and indexed filter fields
- FastAPI backend with a React + Vite frontend
- Docker-first deployment with a read-only media mount
Screenshots
<table> <tr> <td><img alt="Dashboard view" src="docs/images/Library.png"></td> <td><img alt="Settings view" src="docs/images/Library-Tableview.png"></td> </tr> <tr> <td><img alt="Dashboard view" src="docs/images/Library-Darkmode.png"></td> <td><img alt="Settings view" src="docs/images/Settings-Logs-Ignored.png"></td> </tr> </table>Quick Start
Run the published image
using docker-compose:
cd docker
cp .env.example .env
with production ready: docker-compose-prod.yaml
using docker run:
mkdir -p ./config
docker run -d \
--name medialyze \
-p 8080:8080 \
-e TZ=UTC \
-v "$(pwd)/config:/config" \
-v "/path/to/your/media:/media:ro" \
ghcr.io/frederikemmer/medialyze:latest
Open http://localhost:8080.
The container serves plain HTTP on port 8080; if you want HTTPS, terminate it in a reverse proxy.
Desktop app
The dev branch also contains a native desktop distribution path built with Electron.
Desktop builds run the same FastAPI + React stack locally with a local SQLite database and ffprobe.
Desktop behavior:
- choose local folders directly from the OS
- choose mounted NAS / SMB locations and, on Windows, UNC paths such as
\\server\share\videos - watch mode is limited to local paths; network paths fall back to scheduled scans
Release artifacts are packaged as:
- Windows: NSIS
.exe - macOS:
.dmg - Linux:
AppImage
Published GitHub releases attach those desktop installers directly as release assets.
All desktop icons are generated from frontend/public/favicon.svg, so the web favicon and native app icons stay aligned.
Build locally
cp docker/.env.example .env
docker compose up --build
The default container setup mounts:
./configto/config./mediato/mediaas read-only
If you want a different external port, set HOST_PORT in .env.
Local Development
Backend
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
uvicorn backend.app.main:app --reload --port 8080
Frontend
cd frontend
npm install
npm run dev
The Vite dev server proxies /api to http://127.0.0.1:8080.
Desktop
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
cd frontend
npm install
npm run build
cd ../desktop
npm install
npm run dev
Local desktop development expects ffprobe in your PATH.
For packaged .app, .dmg, .exe, and AppImage builds, see docs/build_desktop.md.
Configuration
Relevant environment variables:
MEDIALYZE_RUNTIME: runtime mode,serverordesktop, defaultserverCONFIG_PATH: writable config/data directory, default/configin server mode and the OS user-data directory in desktop modeMEDIA_ROOT: media mount root for server mode, default/mediaAPP_HOST: bind host for the backend, default0.0.0.0in server mode and127.0.0.1in desktop modeHOST_PORT: HTTP port exposed on the host, default8080; access the app viahttp://<host>:<HOST_PORT>APP_PORT: internal app port, default8080FRONTEND_DIST_PATH: optional explicit frontend bundle path, mainly used by packaged desktop buildsTZ: process/container timezone, defaultUTCDISABLE_DEFAULT_IGNORE_PATTERNS: optional; when set totrue, built-in default ignore patterns are not preloadedFFPROBE_PATH: optional override for theffprobebinary pathSCAN_RUNTIME_WORKER_COUNT: maximum number of libraries scanned in parallel, default4PUID/PGID: optional runtime user/group ids for shared-folder permission setups; set both or leave both unset to keep the default root runtime user
MEDIA_ROOT should be mounted read-only in production.
If you need a specific runtime uid/gid, set PUID and PGID in .env. The compose files already load .env, so no compose changes are required.
For SMB / NAS setups, the recommended approach is to mount the share on the Docker host first and then point MEDIA_HOST_DIR at that host mount path.
In the desktop app, mounted network shares and UNC paths can be selected directly.
Ignore rules use glob patterns matched against the normalized relative path inside each library. MediaLyze ships editable built-in defaults for common system and temporary paths such as */.DS_Store, */@eaDir/*, */.deletedByTMM/*, and *.part. Set DISABLE_DEFAULT_IGNORE_PATTERNS=true if you do not want those defaults preloaded on first start.
See docs/ignore_files_folders.md for a short guide.
Tech Stack
- Backend: Python, FastAPI, SQLAlchemy, SQLite
- Frontend: React, Vite, TypeScript, i18next
- Desktop packaging: Electron, electron-builder
- Media analysis:
ffprobe/ FFmpeg - Scheduling and watch mode: APScheduler, watchdog
- Packaging: GHCR
Project Status
MediaLyze is an open-source project under active development. The current focus is technical media analysis for large self-hosted libraries, with the v1 scope centered on scanning, normalization, statistics, and file inspection.
mentioned on selfh.st
Star History
Contributing & License
Contributions are welcome. Read CONTRIBUTING.md before opening a pull request.
This project is licensed under the MIT License.
Related Skills
docs-writer
98.8k`docs-writer` skill instructions As an expert technical writer and editor for the Gemini CLI project, you produce accurate, clear, and consistent documentation. When asked to write, edit, or revie
model-usage
332.3kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
project-overview
FlightPHP Skeleton Project Instructions This document provides guidelines and best practices for structuring and developing a project using the FlightPHP framework. Instructions for AI Coding A
arscontexta
2.8kClaude Code plugin that generates individualized knowledge systems from conversation. You describe how you think and work, have a conversation and get a complete second brain as markdown files you own.
