MediaLyze

MediaLyze

Docker app from MediaLyze's Repository

Overview

Self-hosted technical media analysis for large video and audio collections.

MediaLyze

AGPL-3.0 License Python 3.12 FastAPI React 19 Docker Electron SQLite

Self-hosted media library analysis for large video collections. Scans your libraries and run analyses using ffprobe. Explore technical metadata through a FastAPI + React web UI.

MediaLyze focuses (for now) on just analysis, not playback, scraping, or file modification, READ ONLY on your files!

Desktop Downloads

Platform Download
macOS Apple Silicon Download
Linux Download
Windows Download
All release assets Open latest release

MediaLyze dashboard

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
  • historical analysis
  • many different charts for all metrics
  • Normalized formats, streams, subtitles, scan jobs, and quality scores (feel free to suggest improvements)
  • recognize shows, seasons, bonus content
  • Ignore files and folders with simple glob patterns such as *.nfo or */Extras/*
  • Native desktop packaging for Windows, macOS, and Linux in addition to the Docker/web deployment path
  • and more

Screenshots

Dashboard view Comparison Page Library edit
Library Tableview

Support MediaLyze

If you find MediaLyze useful and would like to support ongoing development, you can do so here:

Donate with PayPal GitHub Sponsors Buy Me a Coffee

Quick Start

Docker Compose

use the production ready docker compose file: docker-compose.yaml

services:
  medialyze:
    image: ghcr.io/frederikemmer/medialyze:latest
    container_name: medialyze
    ports:
      - 8080:8080
    environment:
      # change to your timezone, e.g. "Europe/Berlin" or "America/New_York"
      TZ: UTC
    volumes:
      - ./config:/config
      # use .env or change "./media" to the path of your media directory
      - ./media:/media:ro

      # additional media mounts by extending this pattern if needed:
      # /PATH/TO/MEDIA0:/media/MEDIA0:ro
      # /PATH/TO/MEDIA1:/media/MEDIA1:ro

can be extended by .env using: docker-compose-ENV.yaml and env.example

Open http://localhost:8080. The container serves plain HTTP on port 8080 by default - if you want HTTPS, terminate it in a reverse proxy.

Configuration through Docker configuration


Desktop app

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: .exe
  • macOS: .dmg
  • Linux: AppImage

Build locally

run:

cp docker/env.example .env
docker compose -f docker-compose-dev.yaml up --build

The default container setup mounts:

  • ./config to /config
  • ./media to /media as read-only

If you want a different media-path, or external port change env.example or .env.

Local Development

For a single-command local dev setup, use scripts/dev-local.sh on macOS/Linux or scripts/dev-local.ps1 on Windows.

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.

Combined startup scripts

macOS/Linux:

./scripts/dev-local.sh

Windows PowerShell:

.\scripts\dev-local.ps1

Both scripts expect:

  • .venv with pip install -e .[dev]
  • frontend/node_modules from npm --prefix frontend install
  • a valid MEDIA_ROOT directory, defaulting to your Desktop if not overridden

They start the backend with reload enabled, wait for /api/health, then launch the Vite dev server in the foreground.

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.

Docker configuration

Relevant environment variables:

  • MEDIALYZE_RUNTIME: runtime mode, server or desktop, default server
  • CONFIG_PATH: writable config/data directory, default /config in server mode and the OS user-data directory in desktop mode
  • MEDIA_ROOT: media mount root for server mode, default /media
  • APP_HOST: bind host for the backend, default 0.0.0.0 in server mode and 127.0.0.1 in desktop mode
  • HOST_PORT: HTTP port exposed on the host, default 8080; access the app via http://<host>:<HOST_PORT>
  • APP_PORT: internal app port, default 8080
  • FRONTEND_DIST_PATH: optional explicit frontend bundle path, mainly used by packaged desktop builds
  • TZ: process/container timezone, default UTC
  • DISABLE_DEFAULT_IGNORE_PATTERNS: optional; when set to true, built-in default ignore patterns are not preloaded
  • MEDIALYZE_TELEMETRY_DISABLED: optional; when set to true, telemetry is forced off and the UI toggle is locked
  • MEDIALYZE_TELEMETRY_ENDPOINT: optional; overrides the telemetry ingest endpoint, default https://www.medialyze.app/api/telemetry/ingest
  • FFPROBE_PATH: optional override for the ffprobe binary path
  • PUID / 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.

Scan parallelism is configured in the UI under Settings -> App settings -> Scan performance. MediaLyze exposes separate limits for per-scan analysis workers and parallel library scans so you can tune throughput without editing compose or env files.

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/patterns.md for folder discovery, series recognition, bonus-content rules, and ignore-pattern examples.

Telemetry payloads are documented in docs/telemetry.md, including the none, minimal, and enabled payload contracts and the privacy-preserving rounding rules for coarse usage counts.

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
ServersatHome

Star History

Star History Chart

Contributing

Contributions are welcome. Read CONTRIBUTING.md before opening a pull request.

License

MediaLyze is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See the LICENSE file for details.

Install MediaLyze on Unraid in a few clicks.

Find MediaLyze in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for MediaLyze Review the template variables and paths Click Install

Requirements

Persistent storage for /config and read-only media mounts below /media.

Related apps

Details

Repository
ghcr.io/frederikemmer/medialyze:latest
Last Updated2026-07-01
First Seen2026-06-01

Runtime arguments

Web UI
http://[IP]:[PORT:8080]/
Network
bridge
Shell
bash
Privileged
false

Template configuration

WebUI PortPorttcp

External port for the MediaLyze web interface.

Target
8080
Default
8080
Value
8080
ConfigPathrw

Persistent configuration and SQLite database storage.

Target
/config
Default
/mnt/user/appdata/medialyze
Value
/mnt/user/appdata/medialyze
Primary Media MountPathro

Required read-only media mount. Change the container path to your preferred visible name, but keep it below /media, for example /media/Movies.

Target
/media/Media
Default
/mnt/user/media
Value
/mnt/user/media
Movies Media MountPathro

Optional additional read-only media mount. Change the container path to your preferred visible name, but keep it below /media, for example /media/Movies.

Target
/media/Movies
Shows Media MountPathro

Optional additional read-only media mount. Change the container path to your preferred visible name, but keep it below /media, for example /media/Shows.

Target
/media/Shows
Music Media MountPathro

Optional additional read-only media mount. Change the container path to your preferred visible name, but keep it below /media, for example /media/Music.

Target
/media/Music
TimezoneVariable

Container timezone, for example Europe/Berlin or America/New_York.

Target
TZ
Default
UTC
Value
UTC
PUIDVariable

Optional runtime user id. On Unraid, 99 is usually nobody.

Default
99
Value
99
PGIDVariable

Optional runtime group id. On Unraid, 100 is usually users.

Default
100
Value
100