MytView

MytView

Docker app from mytview's Repository

Overview

MytView is a clean, fast player for a video library you host yourself: video files plus their metadata sidecars (.info.json, or Kodi/Emby .nfo for TV series and movies). Watch in any browser, or with the native iPhone, iPad, Apple TV, Android, Google TV and Samsung TV apps. Private by design: no cloud, no analytics, no ads. Your library is mounted read-only and MytView never writes to, moves or deletes your files. Everyone in the house gets their own sign-in and watch history, and the owner decides who sees what. Files play directly when the device can decode them; anything else is transcoded live into a stream that starts in seconds (Intel VAAPI when available, CPU otherwise), with nothing converted ahead of time and nothing stored. Sidecar and embedded subtitles, audio track selection, federation between MytView households, and two-way Plex watch-state sync. First run: open the WebUI and sign up. The first account becomes the owner. Then add your libraries under Admin > Libraries (a folder inside /media plus a format: channels, series or movies). After that, signup needs a single-use invite unless ALLOW_SIGNUP is set to all.

MytView Server

Say it "mighty view" — and the first four letters are MyTV.

A clean, fast, read-only viewer for a self-hosted video library — video files plus their metadata sidecars (.info.json, or Kodi/Emby-style .nfo for TV series and movies) — with multi-user accounts, per-user watch state, owner-controlled per-channel privacy, public share links, server-to-server federation, two-way Plex watch-state sync, and live HLS transcoding when a client can't play a file directly.

Run it on your own hardware (NAS, home server, mini-PC) and watch in any browser — or with the native iPhone / iPad / Apple TV, Google TV, and Samsung TV (Tizen) apps, which talk to this server over its documented API.

  • 🔒 Private by design — no cloud, no analytics, no ads. Streams go straight from your server to your device.
  • 📚 Read-only — your library is mounted :ro; MytView never writes to, moves, or deletes your files.
  • 👥 Multi-user — per-person sign-in, watch state, and resume points. Invite-based signup; the owner can reset passwords, deactivate, or remove accounts. Per-device session management with server-side revocation.
  • 🔦 Per-channel privacy — mark channels public or private and grant private ones to specific people, from a per-user × per-channel grid.
  • 📺 Channels, series, and movies — creator-channel libraries (.info.json sidecars), TV-series libraries (.nfo + S01E02 naming, season/episode ordering, next-episode tracking), and movie libraries (the Kodi layout media managers write, a 2:3 poster wall with genre filters and sort). Libraries are configured in the UI, not env vars; fully-watched shows tidy themselves out of the grids until something new arrives.
  • 🎞️ Direct-play first, live HLS fallback — every client tries the original file first; when it can't decode it, the server live-transcodes an ephemeral HLS stream that starts in seconds (VAAPI hardware encode when available, CPU fallback). Nothing is pre-transcoded or stored long-term.
  • 💬 Subtitles & captions — picked up from .srt/.vtt files next to the video or from text tracks inside the .mkv/.mp4 itself, with SDH/CC marked as captions. Nothing is downloaded: what's on disk is what you get. Image-based subtitles (PGS/VobSub) are not supported — they're pictures of text and would need OCR or a burned-in re-encode; use a text (SRT) version instead.
  • 🔗 Share links — per-video public links with expiry and view caps, link-preview cards, and the same live-HLS fallback for recipients.
  • 🌐 Federation — peer with any number of other MytView servers, sharing and consuming in both directions. Share different channels, shows, or whole libraries with each household; everything you consume merges into your own libraries (browse, search, and watch state stay on your server) while video streams flow directly from whichever server holds the file — plus per-peer concurrent-stream caps and consumption stats for the sharer.
  • 📲 Offline on the phone — the iPhone/iPad app (Android in open testing) keeps movies and episodes on the device and follows a series for the next unwatched ones; the server hands out each copy in the format the device plays (H.264 and HEVC MKVs are remuxed, not re-encoded), paced by a negotiated session budget so a batch never crowds out someone watching live.
  • 🔄 Plex sync — two-way watched-state and resume-point sync with a Plex server on the same library. Each user links their own Plex account (plex.tv PIN flow); years of existing Plex history import on the first sync, and an unwatch in either app propagates to the other.

Website: https://mytview.com · Privacy: https://mytview.com/privacy/

Screenshots

The web app: the Recent feed of a library, with the main features called out

Recent feed on iPhone Offline mode on iPhone: the copies on the device Downloading a video on iPhone Library on an Android phone

The demo library in these shots is Blender's open movies and NASA public-domain footage.


Quick start (Docker)

Unraid: install from Community Applications (search MytView); the template lives at https://github.com/mytview/unraid-templates. Everything else: the compose file below.

# docker-compose.yml
services:
  mytview:
    image: fbartolini/mytview:latest
    container_name: mytview
    restart: unless-stopped
    ports:
      - "8700:8700"
    environment:
      ALLOW_SIGNUP: invite            # first account becomes the owner
      # ORIGIN: https://mytview.example.com     # only behind a reverse proxy / TLS
      # ADDRESS_HEADER: x-forwarded-for         # only behind a reverse proxy / CDN
    volumes:
      - /path/to/your/library:/media:ro   # your video library — READ-ONLY
      - mytview-data:/data                # accounts + watch state + index (back this up)
      - /path/to/scratch:/transcodes      # writable scratch for live-HLS segments
volumes:
  mytview-data:
docker compose up -d

Open http://your-host:8700 and sign up — the first account bootstraps the owner. After that, signup requires a single-use invite (from /invite) unless ALLOW_SIGNUP=all.

Configuration

Volumes

Container path Purpose Notes
/media Your video library Mount read-only (:ro). MytView never modifies it.
/data Accounts, sessions, watch state + the search index Durable — back this up. The index rebuilds from disk; your users/progress do not.
/transcodes Scratch space for live-HLS segments Segments exist only while someone is watching and are cleaned up after. Keep it outside your library.

Environment

Variable Default Purpose
ALLOW_SIGNUP invite invite (first account = owner, then invite-only), all, or off.
ALLOW_INVITES owner Who may create invite links: owner or all.
ORIGIN — Your external URL — set only behind a reverse proxy / TLS. Leave it unset otherwise (from 0.4.10 a blank value counts as unset; older images refuse to start on a blank ORIGIN).
ADDRESS_HEADER — Behind a proxy/CDN, the header carrying the real client IP (e.g. x-forwarded-for), so login rate limits see clients rather than the proxy.
TRANSCODE_HWACCEL 0 1 = Intel VAAPI hardware encode for live HLS (needs /dev/dri passthrough; amd64). Falls back to CPU automatically.
EMBEDDED_SUBS 1 off stops the server reading subtitle tracks out of .mkv/.mp4 containers (sidecar .srt/.vtt files still work). Extraction reads the whole container once per file, so on slow network storage turning it off is a reasonable choice.
SUBS_CACHE_DIR /transcodes/subcache Where extracted subtitle text is cached, so a container is only ever read once. off = memory only.
HLS_DIR /transcodes/hls Where live-HLS session segments are written. off disables live transcoding (direct-play only).
SCAN_INTERVAL 5 Auto-rescan interval in minutes (0 disables). Incremental and cheap.
EXTERNAL_URL — The public address federation invites embed — needed only to share via federation and only when the auto-detected address is wrong (e.g. a bare ip:port server without TLS).

Federation and Plex sync are configured in the app, not the environment: pairing, library mappings, sync cadence, and per-peer stream caps live on the owner pages; what gets shared is picked on the Sharing page; each user links Plex from their own Account page.

Baked into the image (override only if you must): PORT=8700, HOST=0.0.0.0, MEDIA_ROOT=/media, DB_PATH=/data/index.db, TRANSCODE_DIR=/transcodes.

Hardware transcoding (amd64 + Intel iGPU)

The repo ships docker-compose.hwaccel.yml as a merge-in override, so the base compose stays runnable on hosts without a GPU:

docker compose -f docker-compose.yml -f docker-compose.hwaccel.yml up -d

(Equivalent by hand: TRANSCODE_HWACCEL: "1" plus devices: [/dev/dri:/dev/dri].)

Library layout

Two library formats, configured by the owner in the UI (Libraries in the avatar menu) — any subfolder of /media can be its own library:

  • Channels — Channel Name/…/Video Title.mp4 + a sibling Video Title.info.json (title, date, description, tags, thumbnail…). Channels are keyed by their top-level folder.

  • Series — Show Name/Season 1/Show - S01E02 - Title.mkv with Kodi/Emby .nfo sidecars and local artwork (poster.jpg, fanart.jpg, -thumb.jpg), the layout media managers write. Falls back to SxxExx filename parsing when no .nfo exists.

  • Movies — Movie Name (2024)/Movie Name (2024).mkv with movie.nfo + poster.jpg/ fanart.jpg (the Kodi layout media managers write). Rendered as a poster wall with genre filters and title/year/recently-added sorting.

Creator archives that look like TV shows. Some download tools present a creator's channel as a show (Show/Season 2021/s2021.e031701 - Title.mp4) and write both yt-dlp's .info.json sidecar and a Jellyfin/Kodi .nfo. Either library type handles that folder: MytView reads the .info.json and indexes it as a channel (real titles, upload dates, descriptions, tags), with the same video ids in a Channels or a Series library, so watch state survives if you switch. A show with .nfo files only and date-coded episode numbers is shown by date rather than as "S2021 E31701".

Libraries are explicit: with none configured, nothing is indexed and the first-run screen walks the owner through adding one (any subfolder — or the root — per library).

Federation (share with another household)

A MytView server can peer with as many other servers as you like, sharing to some and consuming from others (or both with the same peer). Pairing is per-peer: one owner mints a single-use invite, the other pastes it. The sharer then picks channels/shows/libraries per peer on the Sharing page — each federated server appears as one more column next to your users, and a whole-library share covers future content automatically. The consumer maps each shared library into one of their own — or a new virtual library, and several peers' libraries can merge into the same one — with the same feed, search, tags, and per-user watch state, all served by the consumer's server. Media never relays: playback streams directly from the sharing server to the viewer's device via short-lived signed URLs, so a slow home uplink is never in the middle. Duplicate items (the same movie on both servers) collapse automatically — the local copy wins.

Plex sync

If a Plex Media Server serves the same files, MytView keeps watch state agreed both ways: watched flags and resume positions sync per user, in both directions, every few minutes. Items pair by tmdb/imdb/tvdb ids with a file-path fallback; the first sync imports existing Plex history without un-watching anything. Setup: the owner sets the Plex address on their Account page; each user links their own Plex account there via plex.tv/link.

Clients & API

The web UI ships with the server. The native apps (iPhone/iPad/Apple TV, Google TV, Samsung TV) are separate, closed-source products by the same author — the Samsung app is free.

They are free today and become a small one-time purchase (no subscription) from 1 November 2026. Install an app before 1 November 2026 and it stays free forever — a founder licence, detected from the install date itself, with nothing to claim or register.

Get the apps:

  • iPhone / iPad / Apple TV: on the App Store — iPhone and iPad 1.2 with offline downloads, Apple TV 1.1
  • Android phone / tablet / Google TV: on Google Play as an open beta, no invite needed (offline downloads are in testing and follow in the next release)
  • Samsung TV: free for everyone, lands on the Samsung store when Samsung's review completes — watch releases for the announcement

Third-party clients are welcome: the full client contract — auth and device pairing, the video/playback descriptors, watch-state rules, and the capabilities negotiation — is documented in docs/api.md. GET /api/v1/status advertises serverVersion and a capabilities list to feature-gate against.

Development

npm install
cp .env.example .env    # set MEDIA_ROOT to a local path
npm run dev             # Vite dev server
npm run check           # svelte-check — must stay clean
npm test                # vitest suite
npm run build && node build   # production build (adapter-node)

Runtime dependencies are deliberately minimal: SvelteKit + better-sqlite3 (+ hls.js on the web player). Transcoding shells out to ffmpeg/ffprobe (bundled in the Docker image). Two SQLite databases live in /data: index.db (disposable cache, rebuilt by scanning) and state.db (durable: users, sessions, watch state — the only thing worth backing up).

How it is built

MytView is a solo project, proudly co-created with Anthropic's Claude (Opus and Fable) under my direction: the design, the product decisions, the review and the field testing are mine, and every increment ships with tests and runs on my own servers before it is released. It is 2026; get over it. Opinions on the tooling are not sought here and will not be engaged with. Bug reports and pull requests about what the software does are very welcome.

License

GPL-3.0 — see LICENSE. Contributions are welcome under the terms in CONTRIBUTING.md.

Media gallery

Install MytView on Unraid in a few clicks.

Find MytView 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 MytView Review the template variables and paths Click Install

Requirements

Optional, for hardware transcoding on an Intel iGPU: set TRANSCODE_HWACCEL to 1 and add --device=/dev/dri:/dev/dri to Extra Parameters (Advanced View). Without it, transcoding uses the CPU (it only runs when a device cannot play a file directly).

Download Statistics

1,222
Total Downloads

Related apps

Explore more like this

Explore all

Details

Repository
fbartolini/mytview:latest
Last Updated2026-09-26
First Seen2026-09-27

Runtime arguments

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

Template configuration

WebUI portPorttcp

The port MytView answers on. Point the browser and the apps at http://your-server:this-port.

Target
8700
Default
8700
Value
8700
Video library (read-only)Pathro

Your video library. Mounted read-only: MytView never writes to, moves or deletes anything here. Pick the folder that holds your collections; inside the app you then add each sub-folder as a library (Admin > Libraries).

Target
/media
Default
/mnt/user/media
Value
/mnt/user/media
Data (accounts, watch state, index)Pathrw

Accounts, sessions, watch progress and the library index. Back this up: the index rebuilds from disk, your users and their progress do not.

Target
/data
Default
/mnt/user/appdata/mytview/data
Value
/mnt/user/appdata/mytview/data
Transcode scratchPathrw

Working space for live-transcode segments (they exist only while someone is watching) and the resized-artwork cache. Keep it on a cache pool and outside your library share. If the share this lives on has a Minimum free space larger than the pool can honour, Unraid refuses new files and transcodes fail.

Target
/transcodes
Default
/mnt/user/appdata/mytview/transcodes
Value
/mnt/user/appdata/mytview/transcodes
TRANSCODE_HWACCELVariable

1 = Intel VAAPI hardware encoding for live transcodes. Also add --device=/dev/dri:/dev/dri to Extra Parameters (Advanced View). Falls back to the CPU automatically if the GPU path fails.

Default
0
Value
0
ALLOW_SIGNUPVariable

invite = the first account becomes the owner, then a single-use invite link is required. all = open signup. off = no new accounts.

Default
invite
Value
invite
ALLOW_INVITESVariable

Who may create invite links: owner or all.

Default
owner
Value
owner
SCAN_INTERVALVariable

Minutes between library rescans (incremental, cheap). 0 = only on start and on demand.

Default
5
Value
5
ORIGINVariable

Only behind a reverse proxy / TLS: your real external URL, e.g. https://mytview.example.com. Leave empty for direct LAN access.

ADDRESS_HEADERVariable

Behind a reverse proxy or CDN: the header carrying the real client address (x-forwarded-for; Cloudflare: cf-connecting-ip) so per-IP login rate limits see clients, not the proxy. Leave empty for direct LAN access.

EXTERNAL_URLVariable

Federation only: the address other MytView servers reach you at, if it differs from what the app can derive.