isputnik-video

isputnik-video

Docker app from isputnik-video's Repository

Overview

The video engine for isputnik.home, in a container of its own: TV shows and movies scanned from your video folders, laid out the way Jellyfin and Kodi read them, described from .nfo files and TMDB (posters, backdrops, cast, sets of films, genres), and played in the browser and in the iSputnik TV app. A file a browser plays as it is goes as it is; the rest is converted while it plays, on the CPU or on an Intel CPU's graphics, with HDR tone-mapped and Blu-ray subtitles drawn in. Each person resumes where they stopped, intros and credits are skipped, viewers away from home are held under a quality cap. Everything runs on your server; nothing is sent anywhere. This is an add-on for isputnik.home and does nothing on its own: it has no sign-in and no pages. Install it beside the isputnik container; video libraries are added, shared and watched in isputnik.home. Set it up from isputnik.home, on Control panel, Settings, Apps, Video. Before installing, press Generate secret there and copy it (it is shown once); paste it into the Gateway Secret field below, which is required. Give the container your video share as Video Folders (read-only: the engine never writes to it). Once it runs, enter its address on the same page (http://[your Unraid IP]:4300 as installed here) and press Test connection, which then says Paired. Then add a library under Control panel, Library, Libraries, Add library, Video. Needs isputnik.home 4.38 or newer.

isputnik.video

An add-on for isputnik.home: its video engine. TV shows and movies, scanned, described and played behind the home server, which owns every screen and every library. It requires the isputnik.home container, is installed beside it and is reached only through home's /video gateway; this server has no pages and does nothing on its own.

How the two fit together: home's docs/video-architecture.md (short) and docs/apps-platform-plan.md (the whole plan, phases and contract).

Status: 0.14.0, alpha. Catalog, library sync and playback work, with each person's progress (resume, next episode, Continue watching). A file a browser plays as it is goes as it is; the rest are converted to HLS as they play — the sound to AAC, the picture to H.264 only when a browser can't show it. A film with several sound tracks plays the one chosen; subtitles inside it or beside it are offered too (text as WebVTT, images burned in). Posters come from beside the files, and from TMDB with the admin's key; films that belong together are grouped into sets, from the .nfo files or TMDB's collections.

The contract, from this side

  • Reached only through home's gateway under /video. Every request carries the person's identity in X-Isputnik-* headers signed with GATEWAY_SECRET; without the secret a request is anonymous.
  • X-Isputnik-Libraries lists the libraries the person may see. The engine keeps no users or permissions of its own and filters everything by that list.
  • X-Isputnik-Profile-Id, when present, names the household viewing profile the person is watching as: watch history (progress, Continue watching, next up) is then that profile's, whoever is signed in. DELETE /video/api/admin/history/profiles/:id forgets a deleted profile's history.
  • Home tells the engine about libraries (PUT/DELETE /video/api/admin/libraries/:id, POST …/sync); a library missing from a sync is only detached, kept 30 days.
  • Home reads its events, log and a database copy for its backups; the engine never calls home.
Route Who What
GET /video/api/health anyone { ok, version }
GET /video/api/me signed who home says this is, and which libraries
GET /video/api/libraries signed the libraries this person may see
GET /video/api/shows, /shows/:id signed shows, then seasons and episodes
GET /video/api/movies, /movies/:id signed movies
GET /video/api/play/:id?audio= signed an episode or movie for the player: how it plays (playback: direct, remux or transcode, and its address) with the sound track asked for, its audioTracks, where to resume, what is next
GET /video/api/stream/:id signed the file, with byte ranges
GET /video/api/hls/:id/t<track>/index.m3u8, /:n.ts signed the film as HLS with that sound track, its segments cut as they are asked for
DELETE /video/api/hls/:id signed the player has gone: stop converting
PUT /video/api/progress/:id signed { position, duration, watched? } — this person's place in it
GET /video/api/continue signed left halfway, and the next episode of a show, newest first
GET /video/api/admin/libraries admin every library with counts and scan state
PUT /video/api/admin/libraries/:id admin create or change a library (scans it)
DELETE /video/api/admin/libraries/:id admin delete it and its catalog
POST /video/api/admin/libraries/sync admin home's whole list: others are detached
POST /video/api/admin/libraries/:id/scan admin scan now
GET /video/api/admin/folders?path= admin folders under MEDIA_ROOT, for the picker
GET /video/api/admin/events, /log admin the admin's window
GET /video/api/admin/backup admin the whole catalog as one SQLite copy
POST /video/api/admin/restore admin puts a copy home holds back, at once, in one transaction (application/vnd.sqlite3, X-Isputnik-Backup-Version); a newer copy is refused, and so is any restore while a scan or metadata pass runs. Home's gateway refuses this path: only its Backup page calls it
GET, POST /video/api/admin/restore/undo admin describes the catalog the last restore replaced (<db>.pre-restore), and puts it back once
GET /video/api/admin/disks admin the disks the libraries, catalog, posters and conversion folder sit on, one per mounted folder (home's Dashboard)

Library layout

Show (Year) [imdbid-tt…]/Season 01/Show (Year) S01E01 - Title.mkv   (+ .nfo, tvshow.nfo)
Movie (Year) [tmdbid-…]/Movie (Year).mkv                            (+ movie.nfo)
Movie (Year)/Movie part1.avi, Movie part2.avi                        one film in two files
Set name/First film.mkv, Second film part-2.mkv                      a set of films

The layout Jellyfin and Kodi read. .nfo files come first; names fill in the rest, including release names as they are downloaded. A file written in the last two minutes is left for the next scan, so a copy in progress is never catalogued.

A movie folder holds one film unless its files say otherwise. Names that differ only by a part number counting from 1 (part 2, pt2, CD2, disc 2, часть 2, серия 2) are one film in parts, played in turn. Other files at least a fifth of the biggest's size are films of their own, in a set named after the folder and ordered by any part number in their names. Trailers and extras are left out by name (-trailer, Extras/), and a movie.nfo says the folder is one film.

Configuration

Variable Default
GATEWAY_SECRET unset from home's Control panel → Apps → Setup; required in production
MEDIA_ROOT data/media the video folders, mounted read-only (image: /media)
DB_PATH data/video.sqlite the catalog (image: /config/video.sqlite)
PORT / HOST 4300 / 127.0.0.1
TRANSCODE_PATH temp folder where ffmpeg writes segments while someone watches (image: /transcode); finished ones move into memory up to the share set on home's Apps → Installed, the rest stay here; emptied on start
ART_PATH art beside DB_PATH posters, backdrops and stills fetched from TMDB (image: /config/art); not in backups — fetched again
FFMPEG_PATH / FFPROBE_PATH on PATH the image installs both; a checkout uses the ffmpeg-static dev dependencies
LOG_LEVEL info
DEV_USER dev:Developer development without a secret: an admin who sees every library

Running it

The image is ghcr.io/isputnikdotnet/isputnik.video (what the Unraid template pulls) and, the same bytes, isputnikdotnet/isputnik.video on Docker Hub; every release tag publishes both, and latest is the newest release. Mount /config (the catalog) and /media (the video share, read-only) — and, if you like, /transcode on RAM or a fast disk — then:

  1. In home, Control panel → Settings → Apps → Video: Generate secret and copy it; paste it here as GATEWAY_SECRET. The container won't start without it.
  2. On the same page, save the address: http://<host IP>:4300 with the port published, http://isputnik-video:4300 on a user-defined Docker network shared with the isputnik container, or http://<its IP>:4300 on br0 with a fixed IP. Test connection says Paired.
  3. Add a library: Control panel → Library → Libraries → Add library → Video.

Unraid — the repository carries a Community Applications template, isputnik-video.xml, listed in CA as isputnik-video. It publishes port 4300 on bridge (safe: without the secret every request is answered 401), maps /config and the read-only video share, offers /transcode and /dev/dri for an Intel GPU, and asks for the gateway secret, which is made in home first because the field is required.

Home's guide docs/users/apps.md has the whole walk-through.

Development

npm install
npm run dev        # :4300, the developer identity, data/ under the repo
npm test
npm run typecheck && npm run lint

License: AGPL-3.0-only.

Requirements

Needs the isputnik (isputnik.home) container, version 4.38 or newer, installed on the same server. The engine is reached only through it.

Download Statistics

72
Total Downloads

Related apps

Explore more like this

Explore all

Details

Repository
ghcr.io/isputnikdotnet/isputnik.video:latest
Last Updated2026-11-09
First Seen2026-11-10

Runtime arguments

Network
bridge
Shell
sh
Privileged
false
Extra Params
--stop-timeout=30

Template configuration

Engine PortPorttcp

The port the isputnik container reaches the engine on: enter http://[your Unraid IP]:[this port] as the Video address in isputnik.home (Control panel, Settings, Apps). Not for browsers: video is watched inside isputnik.home. On br0 with a fixed IP, or on a user-defined network shared with the isputnik container, this mapping is not used and the address is the container's own IP or name with port 4300.

Target
4300
Default
4300
Value
4300
Config &amp; DataPathrw

Stores the catalog: shows, seasons, episodes and movies found in the video folders, posters and each person's progress (a SQLite database and a picture cache). Keep it apart from the isputnik container's appdata. isputnik.home's backups include a copy of the database.

Target
/config
Default
/mnt/user/appdata/isputnik-video
Value
/mnt/user/appdata/isputnik-video
Video FoldersPathro

The share that holds your shows and movies, mounted read-only: the engine never writes to it. Each video library is a folder under it, for example Shows or Movies, chosen in isputnik.home when the library is added.

Target
/media
Default
/mnt/user/data/video
Value
/mnt/user/data/video
TranscodePathrw

Optional. Where a video is converted while someone watches it (a few hundred MB per viewer, deleted as they go). Point it at RAM (/tmp/isputnik-video) or a cache-pool folder to keep it off the array; left empty, it stays inside the container.

Target
/transcode
Intel GPUDevice

Optional. /dev/dri to convert video on an Intel CPU's graphics (Quick Sync) instead of the CPU: several viewers at once for little CPU. Leave empty to convert on the CPU. Settings, Video in isputnik.home shows what was found.

Target
/dev/dri
Gateway SecretVariable

The secret isputnik.home signs its requests with, so this engine knows who is signed in. Make it first, in isputnik.home on Control panel, Settings, Apps, Video (Generate secret; it is shown once), and paste it here. Required: the engine refuses to start without one, or with one shorter than 32 characters. Everything else about video is managed inside isputnik.home.

Target
GATEWAY_SECRET
PUIDVariable

User ID the engine runs as. It runs unprivileged (not root); on first start it takes ownership of the Config &amp; Data path as this user. This user must be able to read the Video Folders. 99 (nobody) matches the default owner of an Unraid share.

Default
99
Value
99
PGIDVariable

Group ID the engine runs as. 100 (users) matches the default group of an Unraid share.

Default
100
Value
100
Log LevelVariable

trace, debug, info, warn, error, fatal or silent. isputnik.home shows this log and the engine's own event record under Control panel, Overview, Logs.

Target
LOG_LEVEL
Default
info
Value
info