Turn local video folders into a polished private streaming library.
Supports movies, anime, and JAV.
English · 简体中文 · Quick Deploy · Docs Site · Changelog
MediaTree is built for people who keep movies, TV shows, anime, and private niche libraries on their own disks. Point it at your folders, let it scan and enrich the files, then watch from the browser or stream to external players without running a heavy media stack.
- Your files stay where they are - mount existing folders read-only and keep the original directory structure.
- Metadata without manual busywork - scrape posters, titles, cast, seasons, episodes, and details from TMDB, Bangumi, and Javdatabase.
- Clearer folder browsing - folder pages can show Chinese or English TMDB title logos, while episodes without stills fall back to shared landscape artwork.
- A player made for real libraries - stream directly, seek with HTTP Range, transcode on demand, render ASS/SSA subtitles, show playback state in the browser tab, and open in IINA, mpv, VLC, or PiP.
- Useful from day one - browse by library, folder tree, favorites, categories, or seasons; scan on startup or let the file watcher pick up changes.
- Works with more than the web UI - the web player can generate external playback links and M3U playlists for VLC, IINA, and mpv.
- Simple to run at home - Docker Compose, SQLite, persistent
./data, linux/amd64 and linux/arm64 images.
For a mobile experience, pair it with the standalone Android client ZASENJC/mediatree-app. It can connect to MediaTree, and it also works as an independent client for Jellyfin, Emby, SMB, and WebDAV.
| Library | Player |
|---|---|
![]() |
![]() |
| Poster grid for scanned libraries | Streaming with rich details and subtitles |
| Browse | Settings |
|---|---|
![]() |
![]() |
| Folder tree and season navigation | Library, scraper, backup, and update controls |
Create .env and docker-compose.yml, update the data and media paths in the comments, then start the container. You can either preset the admin account or create it on first launch.
services:
mediatree:
image: zasenjc/mediatree:latest
container_name: mediatree
restart: unless-stopped
init: true
stop_grace_period: 30s
user: "${PUID:-1000}:${PGID:-1000}"
security_opt:
- no-new-privileges:true
ports:
# Left side is the host port. Open http://localhost:27580 after startup.
- "27580:80"
volumes:
# Persistent data: database, covers, fonts, backups, and app-package updates.
- ./data:/app/data
# Mount your media folder as read-only. Change the left side to your real host path.
- /path/to/your/movies:/media/movies:ro
# Add more media folders if needed.
# - /path/to/your/anime:/media/anime:ro
# Optional: let Settings perform full Docker image updates.
# This gives the container Docker control on the host; app-package updates do not need it.
# - /var/run/docker.sock:/var/run/docker.sock
env_file:
- .env
environment:
# Internal service port. Usually keep this unchanged.
PORT: "80"
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:80/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"Start:
docker compose up -dOpen http://localhost:27580, sign in, scan your library, and start watching. If AUTH_USER / AUTH_PASS are not preset, the first launch asks you to create an admin account.
You can also clone the repo and use the example config:
git clone https://github.com/ZASENJC/mediatree.git
cd mediatree
cp .env.example .env
cp docker-compose.example.yml docker-compose.yml
# Edit .env and docker-compose.yml, then start.
docker compose up -dDocker Hub image: zasenjc/mediatree:latest
The default image is size-optimized. It includes the lightweight fonts-wqy-microhei package and the bundled frontend subtitle fallback font, but it does not include full Noto CJK or emoji font packages by default. Upload custom fonts in Settings when you need wider subtitle coverage; maintainers only build with INCLUDE_FULL_CJK_FONTS=true or INCLUDE_EMOJI_FONT=true when a release explicitly needs those larger font packages.
| Variable | What it does |
|---|---|
AUTH_USER / AUTH_PASS |
Presets the admin login; leave empty to create it on first launch |
PUID / PGID |
UID/GID used to run the container; on Linux/macOS check them with id -u and id -g |
| Media mounts | Configure in docker-compose.yml volumes, for example /host/movies:/media/movies:ro |
| Data mount | Configure in docker-compose.yml volumes, for example ./data:/app/data |
| Web port | Configure in docker-compose.yml ports, for example 27580:80 |
TMDB_ACCESS_TOKEN |
Optional, improves TMDB scraping; see the docs |
Javdatabase is now provided as a built-in scraper plugin; choose Javdatabase for the relevant library in Settings to use it. Scraper cache TTLs and the Javdatabase request interval are managed internally instead of being tuned from Settings or environment variables. Manual scans, rescrapes, and manual apply actions bypass cache, and empty results are not cached, so stale empty responses do not block later metadata fixes.
See .env.example for all options. Detailed setup, scraper behavior, playback, and troubleshooting live in the Docs Site.
Most updates can be installed directly from Settings. MediaTree downloads a small app package into ./data, so you usually do not need to pull a new Docker image. After an app-package update restarts successfully, MediaTree keeps the current package and one rollback package, then removes older packages. New installs that use zasenjc/mediatree:latest also start from the newest version.
For app-package releases, maintainers now build and push zasenjc/mediatree:latest locally instead of syncing DockerHub through GitHub Actions. Existing installs keep using the Settings app-package path, while new installs still start from the latest application baseline.
Some releases show "full image update required". That usually means the runtime changed too, such as Python, ffmpeg, fonts, or startup behavior. The simplest path is to run the two host-side commands below. If you want Settings to perform full image updates automatically, mount /var/run/docker.sock:/var/run/docker.sock in docker-compose.yml and use an image that includes the Docker CLI; this gives the container control over Docker on the host, so leave it unmounted if you are unsure.
For full image updates:
docker compose pull
docker compose up -d| Document | Description |
|---|---|
| Docs Site | Recommended entry for deployment, configuration, scraping, updates, API, and development docs |
| README.md | 简体中文 README |
| CHANGELOG.md | Version history and release notes |
| CLAUDE.md | Development and AI-assisted maintenance notes |
- Telegram group: Join the discussion
- Telegram update channel: Subscribe to updates
MIT © ZASENJC




