chadMueller/Nostalgex

Public

Retro cable TV guide for your Plex, Jellyfin or Emby library. Native Apple TV app + web tuner.

  • Stars159+28 tuần này
  • Forks12
  • Watchers1
  • Issues8
  • Ngày tạo29/09/2026
  • Cập nhật gần nhất29/10/2026
  • Ngôn ngữSwift
  • Giấy phépMIT
README.md34.1 KBRaw

Nostalgex

Retro TV for your own movie and show library. Free and open source, for Plex, Jellyfin and Emby.

License: MIT Discord App Store Web tuner Docker

The Nostalgex channel guide on Apple TV, with CH 12 Action Adventure playing The Empire Strikes Back and a grid of channels and showtimes below

Nostalgex turns your library into 130+ channels in 14 bundles, plus a channel for every film series you own, with a real channel guide. Every channel plays on a set daily schedule, so tuning in feels like live TV. No account to make, and it never supplies any media of its own.

Pick your way to watch

Apple TV app Web tuner Docker container
What it is An app for your TV and Siri Remote Nostalgex in your browser The web tuner, running on a computer at home
Best for Watching on a TV Trying it right now, on a laptop or phone Jellyfin or Emby setups the web tuner can't reach
Works with Plex, Jellyfin, Emby Plex, Jellyfin, Emby Plex, Jellyfin, Emby
Get it Download on the App Store Open the web tuner
Open the web tuner
Docker logo
Docker container guide

All three are free. Not sure? Use the app on a TV and the web tuner everywhere else.

Download on the App Store Apple TV app

The best way to watch on a TV. Connect one or more servers, then flip channels with the Siri Remote. Needs tvOS 18 or later.

Quick start: install Nostalgex from the App Store, connect your server, pick a channel.

Web tuner Web tuner

Nothing to install. Works on computers and phones.

Quick start: open nostalgex.app/web-tuner and sign in to your server. Plex just works. Jellyfin and Emby need a secure (https) address; if yours doesn't have one, use the Docker container instead.

Docker logo Docker container

The same web tuner, packaged as a Docker container that runs on a computer at home, so it can reach servers the website can't. Most Plex users don't need it.

Quick start:

docker run -d --name nostalgex -p 8080:8080 --restart unless-stopped ghcr.io/chadmueller/nostalgex:latest

Then open http://YOUR-SERVER-IP:8080. Step by step help is in the Docker container guide.

Latest: tuner-v1.0.6. A new sign-in for Jellyfin and Emby, the same one the Apple TV app has: Quick Connect by default, your server's users to pick from, and the Docker tuner finds a server running on the same machine. Release notes. Already running it? docker compose pull && docker compose up -d.

What's new in 1.0.26

The App Store went straight from 1.0.23 to 1.0.26, so this rolls up 1.0.24, 1.0.25 and 1.0.26. Full release notes

  • The Docker container launched as tuner-v1.0.0. It's on tuner-v1.0.6 now.
  • Emby is officially supported. Thank you to the Emby community for all the logs and testing.
  • Franchises. Each film series in your library (Star Wars, Rocky, whatever you own) gets its own channel and its own switch in Settings. Server collections land in FRANCHISES or OTHER COLLECTIONS. NOTABLE STARS is retired.
  • iCloud sync (Settings > CONNECTION). Every Apple TV on your Apple ID shares the same lineup and settings. Off by default, and server logins never leave the device.
  • REPORT PLAYBACK. Shows what you're watching in your server's Now Playing and marks a film watched once you've seen most of it, without flooding Continue Watching.
  • Phone web tuner. Full width video, the guide in the right place, controls behind one menu.
  • Tip jar: Popcorn, TV Dinner, Pizza Night.
  • Reliability: large library crash fixed, Emby libraries load again, Plex titles with a dash (Spider-Man) keep their full name, clear cards when something can't play, stalled Jellyfin and Emby streams recover, multi-version and multipart Plex files play correctly.

Join in

Tips and supporting the project

Nostalgex is free. If it gives you a good Friday night, you can buy me a coffee or leave a tip in the Apple TV app (Settings has Popcorn, TV Dinner and Pizza Night). Tips are a thank you. They cover the Apple developer fee and keep updates coming. The Sponsor button at the top of this repo goes to Buy Me a Coffee.

Helping costs nothing too: star the repo, rate the app on the App Store, or tell me about a channel that's always empty.


More details

Privacy: what leaves your network

Apple TV app:

  • Your media server. Direct from the Apple TV to your Plex, Jellyfin or Emby. Sign-in goes straight to the server, and Show Now Playing and Mark Watched only talk to that same server. No credentials are ever sent anywhere else.
  • plex.tv (Plex only). The PIN sign-in flow and server discovery, like every Plex client.
  • iCloud (only if you turn on sync). Your lineup and settings, in your own iCloud. Server logins stay on the device.
  • MusicBrainz. Public metadata for the music video channels. No key, no account.
  • TMDB, via nostalgex.app. When Supabase values are present, the TMDB ids of titles in your library go to the site's proxy (api/tmdb.js, in this repo), which forwards them to TMDB with the site's key, keeps no log, and caches the answer at the edge. OMDb only if you build with a key. Off in your own build unless you add the Supabase values.
  • Supabase. The shared enrichment cache, keyed on TMDB id. Same condition as above.
  • TelemetryDeck. Anonymous usage signals in the App Store build. No identifiers, no library contents, no server addresses. Off in your own build unless you keep the key.

The website and web tuner at nostalgex.app load one page analytics script (statsngraphs). The Docker container has its own list in the Docker container extras below. The privacy policy at /privacy covers all of this in plain language.

Docker container extras: Compose, updates, devices and limits

The image is nginx serving static files on port 8080, no database, nothing to sign up for. Because it's plain http on your own network, it can reach a plain http:// Jellyfin or Emby server, which the https site can't. You probably don't need it if you use Plex, or if your Jellyfin or Emby is already on https with a valid certificate.

Port 8080 already taken? Use -p 8099:8080 and open port 8099 instead.

Compose (fuller version in docker/compose.yaml, which also sets no-new-privileges), then docker compose up -d:

services:
  nostalgex:
    image: ghcr.io/chadmueller/nostalgex:latest
    container_name: nostalgex
    ports:
      - "8080:8080"
    environment:
      NOSTALGEX_ENRICHMENT: "on"   # "off" for no outside requests, see below
    read_only: true
    tmpfs:
      - /tmp
    restart: unless-stopped

Update: docker compose pull && docker compose up -d, or docker pull ghcr.io/chadmueller/nostalgex:latest and recreate the container. Image tags are latest, 1.0 and 1.0.0; each release adds its own version tag. Releases are tagged tuner-v*. The bottom of Settings says which one you're running, e.g. WEB TUNER 1.0.6 · DOCKER.

Platforms: amd64 and arm64 (Synology and Unraid on Intel or AMD, NUCs, Raspberry Pi 4 and 5 on a 64 bit OS). No armv7. Runs as a non root user (uid 101) and works with a read only root filesystem as long as /tmp is writable.

Where it's been tested: Chrome, Safari and Firefox on a Mac, iPhone and iPad Safari, and the TV Bro browser on Google TV. Fire TV Silk, Samsung and LG browsers are untested. Roku has no browser. On Apple TV, use the app. The current table is in the Docker container guide.

What the Docker container talks to:

Where When Turn it off
Your media server Always. Sign-in and playback go straight from the browser to your server.
plex.tv Plex only: PIN sign-in and finding your server, like every Plex app. Use Jellyfin or Emby
The shared metadata cache (Supabase) and the nostalgex.app TMDB/OMDb relay On by default. Nine or more channels need keywords, studios or IMDb ratings to fill (TEEN MOVIES, TRUE CRIME, CULT CLASSICS and others). Only TMDB and IMDb ids leave the browser: no titles, no server address, no credentials. NOSTALGEX_ENRICHMENT=off

No analytics, no scripts or fonts from a CDN, and no MusicBrainz or Deezer lookups in the image. A value the container doesn't recognize is treated as off.

Known limits:

  • A reverse proxy puts the wall back. If the tuner is behind https and Jellyfin is plain http, the browser blocks Jellyfin again. Serve both the same way.
  • Surround audio on TV browsers. Some can't decode 5.1. Try a laptop or phone first, and use the Apple TV app on a TV.
  • Music video genres from MusicBrainz and Deezer are off. Titles and artists still show.

Build the image yourself:

docker build -t nostalgex .
docker run -d --name nostalgex -p 8080:8080 nostalgex

Enrichment needs the shared cache's address and public anon key at build time: add --build-arg VITE_SUPABASE_URL=... --build-arg VITE_SUPABASE_ANON_KEY=..., or point them at your own Supabase project. Without them it builds with enrichment off. To skip Docker, npm run build:selfhost writes the same files to dist-selfhost/; any static server works if it serves .cjs as JavaScript.

Reporting a container problem? Include your server and its version, the machine running Docker, the browser, the output of docker logs nostalgex, and anything red in the browser console.

Why the web tuner can't reach some servers

The hosted tuner is served over HTTPS, so browsers block mixed content and it cannot reach a server on plain http:// or on a raw LAN IP. Plex works because plex.direct issues real certificates for local addresses. Jellyfin and Emby need an HTTPS URL with a valid certificate (reverse proxy or tunnel). A local only server with no HTTPS is reachable from the Apple TV app but not from the hosted site, unless you use the Docker container, where it is plain http too.

How channels and schedules work

Both apps read the same channel configuration, channels.json (130+ channels in 14 bundles). The Apple TV app ships its own copy, so a channel change reaches it with an app update. The web tuner reads the site's copy on every load, and the Docker image carries the copy it was built with. Franchise and collection channels are built on top of that from your own library. See CHANNELS.md for a readable breakdown of each channel.

Both apps use a daily seeded shuffle. Each channel's pool is shuffled once per day (seeded by date + channel ID), then looped end to end. Your spot in the loop comes from the clock, so tuning in at 2:15 PM always lands at the same place that day. On tvOS, when a video ends the next one starts from the beginning; on first tune in you join mid stream like real TV.

The two schedules have diverged. tvOS adds premiere priority, sequel adjacency, prime time premieres for new additions, and a 6 hour refresh. The web tuner has none of those, so the same server on the same day will not show the same lineup in both places.

Channel rules

Channels filter your library (Plex, Jellyfin or Emby, normalized to one internal model) using combinations of:

  • type: movie or episode
  • genres: include, exclude, requireAll
  • studios: Disney, HBO, etc.
  • yearRange: min/max year
  • contentRatings: whitelist (TV-Y, PG, R, etc.)
  • durationRange: min/max minutes
  • watchedOnly / unwatchedOnly / rewatched: watch history filters
  • timeRestrictions: block mature content before a set hour
Franchise channels

Each film series in your library (Star Wars, Rocky, whatever you own) gets its own channel and its own switch in Settings. Server collections land in FRANCHISES or OTHER COLLECTIONS. NOTABLE STARS is retired. There's no fixed list: it depends on your library.

Help, support and other devices

Other devices: a Roku port by tydude001 is in the works (discussion #8); it installs by sideloading for now. A Fire TV fork by WSINTRA exists; it's unofficial and I don't support it. For a supported option on a TV today, use the Apple TV app, or the Docker container in a TV browser.

Who maintains it and how often it updates

Nostalgex has been on the App Store since April 19, 2026, and gets updates every month. I'm one person, and I read every issue.

Contributing

Issues and pull requests are welcome. A few things that make them land faster:

  • The easiest first PR is a rule change in channels.json (a title on the wrong channel, a channel that is always empty). CHANNELS.md explains every rule field.
  • Keep PRs small and about one thing.
  • Web changes: npm test must pass. tvOS changes: build for a real Apple TV, not just the simulator, because the simulator keychain and storage behave differently.
  • Not sure where to start? Ask in Discord or open an issue first.
  • One person maintains this in their spare time. You will get a reply, but not always the same day.
For developers: code layout, building and deploying

Source of truth: this repository (chadMueller/Nostalgex) contains the public site, web tuner, and tvOS app together. Read docs/REPOSITORY-LAYOUT.md for boundaries, deploy split, and how to avoid duplicating Nostalgex inside unrelated monorepos.

  • Web tuner (web-tuner.html + plex-tuner.html). web-tuner.html (routed as /web-tuner) is the connect screen; after sign-in it navigates to plex-tuner.html, the tuner itself. Stack: Vanilla HTML/JS, Vite, Vercel.
  • tvOS (Nostalgex/). SwiftUI, AVPlayer, Xcode 26+, tvOS 18+. Key files: App/AppState.swift (playback engine, channel selection, filtering), Models/ChannelSchedule.swift (daily schedule builder), Models/Channel.swift (channel config and rules), Services/MediaBackend.swift (the backend protocol), Services/PlexAPIService.swift, Services/JellyfinAPIService.swift, Services/EmbyAPIService.swift (server clients), Views/ (TunerView, PlayerView, ChannelGuideView, etc.).
  • Public site (index.html). Marketing page and the path into the tuner, the Docker container guide and the App Store. Served at / on Vercel.

Web: npm install, then npm run dev.

tvOS: open Nostalgex/Nostalgex.xcodeproj in Xcode. Build target is Nostalgex (tvOS). To run on a physical Apple TV: Xcode > Window > Devices and Simulators > pair your Apple TV, then select it as the run destination.

Debug logging (tvOS): all playback logs are prefixed with [Plex90]. Filter the Xcode console to see channel selection, item loading, AVPlayer status changes, retries, and auto advance events.

Build it yourself (tvOS): you need Xcode 26 or newer and an Apple TV or the tvOS simulator. Open the project, pick your own team under Signing, and run the Nostalgex scheme. No API keys are required. Two optional extras, both off unless you turn them on:

What How to enable What it adds
TMDB / OMDb / Supabase metadata Copy Nostalgex/Secrets.example.xcconfig to Nostalgex/Secrets.xcconfig and fill in SUPABASE_URL and SUPABASE_ANON_KEY (see docs/REPOSITORY-LAYOUT.md). TMDB needs no key in the app: it goes through the site's proxy, api/tmdb.js. For a direct TMDB or OMDb connection set TMDB_API_KEY or OMDB_API_KEY as environment variables in the Xcode scheme. Read in Services/TMDBConfig.swift. Keyword and collection data for finer channel rules. Supabase is a cache keyed on TMDB ids; you can point it at your own project.
TelemetryDeck TelemetryDeckAppID in Nostalgex/Info.plist. Delete the key to turn it off. Anonymous launch and playback counts. The App Store build has it on; your own build does not have to.

Never commit real keys. .gitignore already covers .env, Secrets.plist and *.xcconfig secrets.

Deployment: the web app deploys to Vercel automatically on push to main. The Docker image is published to ghcr.io/chadmueller/nostalgex when a tuner-v* tag is pushed; the tagged commit bumps "tunerVersion" in package.json to match (see RELEASING.md).

License

MIT, see LICENSE. The Roku app in roku/ carries its own MIT license, roku/LICENSE. Bundled fonts and packages are listed in THIRD-PARTY-LICENSES.md.

The Nostalgex name, icon and the nostalgex.app site are not part of the MIT grant. Fork the code all you like, but please ship it under your own name.

Nội dung README thuộc về chadMueller và cộng đồng đóng góp, giấy phép MIT. Nguồn: github.com/chadMueller/Nostalgex