Repository navigation
Server Setup
This page sets up Station Wrapper 43 on tv-server. When you're done, you'll have the dashboard running and Emby or Jellyfin showing your channels as live TV. You'll make the actual channels on the next page, Making Channels.
- A Linux PC that is on all the time, with Docker and the Docker Compose plugin. These steps use Ubuntu, but any Linux with Docker works.
- A regular x86 PC (amd64) or an ARM one (arm64, like a Raspberry Pi 4 or 5). Docker picks the right image on its own. On ARM every stream is encoded by the CPU, so a Pi manages only one or two at once.
- Your videos, either on this PC or on a NAS share.
- A few GB of free space on the PC's own disk. Not on a network share. You'll see why below.
- Emby or Jellyfin, if you want to watch there. It can run on the same PC.
The wrapper doesn't care how your folders are named. These examples use a share with a folder per library:
//192.168.1.10/media
├── tv/ one folder per show, then seasons
├── movies/ one folder (or file) per movie
└── music_videos/
Skip this step if the videos are already on this PC.
The server only ever reads your videos. Mounting the share read-only makes sure nothing can change them.
Install the tools for Windows-style (SMB) shares:
sudo apt-get install -y cifs-utilsSave the share's username and password in a file only root can read:
sudo install -m 600 /dev/stdin /root/.smbcredentials <<'EOF'
username=<share user>
password=<share password>
EOFMake a folder to mount it on, and add a line to /etc/fstab so it mounts at every boot:
sudo mkdir -p /mnt/nas/media
echo '//192.168.1.10/media /mnt/nas/media cifs ro,credentials=/root/.smbcredentials,vers=3.0,uid=1000,gid=1000,iocharset=utf8,_netdev,nofail 0 0' | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount /mnt/nas/media
ls /mnt/nas/mediaYou should see your library folders (tv, movies and so on).
Everything lives in one folder: the compose file, a secrets file, and a data folder.
mkdir -p ~/fieldstation42/data/config ~/fieldstation42/data/catalog
cd ~/fieldstation42data/ must be on the PC's own disk. It holds a SQLite database and thousands of symlinks. SQLite misbehaves on network shares, and most shares can't store symlinks at all.
Save this as ~/fieldstation42/docker-compose.yml. Change the lines marked CHANGE.
name: fieldstation42
services:
station-wrapper-43:
image: ghcr.io/austincnunn/station-wrapper-43
container_name: station-wrapper-43
restart: unless-stopped
ports:
- "4242:4242" # FieldStation42's console. It has no login, so keep it off the internet.
- "5004:5004" # the dashboard, the player, and the tuner and guide for Emby/Jellyfin
volumes:
- ./data/config:/config
- ./data/catalog:/app/catalog
- /mnt/nas/media:/mnt/media:ro # CHANGE: where your videos are on this PC
- /etc/localtime:/etc/localtime:ro # use this PC's time zone for the schedule
tmpfs:
- /cache:size=6g,mode=1777 # a RAM disk for reading ahead (see PREFETCH below)
environment:
# The "pool": one symlink for every video. Only these top-level folders are used.
SYNC_ENABLED: "1"
SYNC_INCLUDE: tv,movies,music_videos # CHANGE: your library folder names
SYNC_INTERVAL_MINUTES: "60"
SYNC_FULL_EVERY_HOURS: "24"
SYNC_REBUILD_HOUR: "4" # refresh changed channels around 4 am
SYNC_REBUILD_WINDOW_HOURS: "2"
# Genre folders made from .nfo files
FARM_ENABLED: "1"
FARM_INTERVAL_MINUTES: "30"
# Keeps every channel's schedule topped up
KEEPER_INTERVAL_MINUTES: "30"
# The dashboard asks for a password (you pick it on the first visit)
DASHBOARD_LOGIN: "1"
DASHBOARD_EDIT: "1"
# Read the next videos from the NAS into RAM, so playback never waits on the network
PREFETCH: "1"
PREFETCH_RAM: "1"
PREFETCH_DIR: /cache
PREFETCH_MAX_MB: "5400"
# Show names, descriptions and posters for the guide, from Emby or Jellyfin.
# Leave the key empty to skip this.
MEDIA_SERVER_URL: http://192.168.1.20:8096 # CHANGE: your Emby or Jellyfin address
MEDIA_SERVER_API_KEY: ${MEDIA_SERVER_API_KEY:-}
MEDIA_SERVER_MEDIA_ROOT: /media # CHANGE: where Emby/Jellyfin sees the same videos
logging:
driver: json-file
options: { max-size: "20m", max-file: "3" }A few notes:
-
Inside the container, your videos are always at
/mnt/media. Every link the wrapper makes points there. If you add a remote player later, it mounts the share at that same path, so the links work there too. -
SYNC_INCLUDElists the top-level folders to use. Folders not listed are ignored by the dashboard's Files page and by "follow" (more on that in Making Channels). -
MEDIA_SERVER_MEDIA_ROOTis where Emby or Jellyfin sees the share. If Emby's library points at/media/tv/..., put/media. The wrapper uses it to match a video to Emby's info about it. - If the PC doesn't have 6 GB of spare RAM, make the
/cachesize andPREFETCH_MAX_MBsmaller, or turnPREFETCHoff.
The key lets the guide show real show names, descriptions and posters.
- In Emby: Settings → Advanced → API Keys → New API Key. Name it
fieldstation42. (In Jellyfin: Dashboard → API Keys.) - Save it in
.envnext to the compose file, readable only by you:
cd ~/fieldstation42
printf 'MEDIA_SERVER_API_KEY=%s\n' '<paste the key>' > .env
chmod 600 .envDocker Compose reads .env by itself. Keep this file out of any git repo.
cd ~/fieldstation42
docker compose pull
docker compose up -d
docker logs -f station-wrapper-43Press Ctrl+C to stop watching the log. The container keeps running.
Open http://192.168.1.20:5004 in a browser. The first visit asks you to choose a password. After that, the management pages need it.
The first time it starts, the wrapper makes one symlink for every video in your SYNC_INCLUDE folders. This is called the pool. With a big library over a network share, it can take a while. The Files page and "follow" need it to finish first.
Watch for it in the log:
docker logs -f station-wrapper-43 2>&1 | grep -i poolWhen it's done, the links are in ~/fieldstation42/data/catalog/media-links/.
The wrapper pretends to be an HDHomeRun TV tuner. Emby and Jellyfin know how to use those.
In Emby, go to Settings → Live TV:
-
Tuner Devices → Add → HDHomeRun. Address:
http://192.168.1.20:5004 -
TV Guide Data Providers → Add → XMLTV. Address:
http://192.168.1.20:5004/xmltv.xml - If it asks you to map channels, the numbers already match. Just save.
Jellyfin is almost the same: Dashboard → Live TV, then add the tuner and the XMLTV guide with the same two addresses.
There are no channels yet. Make some on the next page: Making Channels.
You don't need to manage these. It helps to know they exist when you read the log.
| Part | What it does |
|---|---|
| FieldStation42 console | FieldStation42's own server. It builds channel lists (catalogs) and schedules. Port 4242. |
| Tuner and dashboard | The fake HDHomeRun, the live video for each channel, the XMLTV guide, and the web dashboard. Port 5004. |
| Sync | Keeps the pool of links matching the share, about once an hour. Refreshes the channels that changed once a day, around 4 am. |
| Follow | For every folder you "follow", links new episodes into its channel. Every 30 minutes. |
| Keeper | Adds schedule days so no channel ever runs out. It adds a day each morning. |
| Farm | Makes genre folders from .nfo files. Videos with no .nfo go into Unclassified. |
| Prefetch | Reads the next videos from the NAS into RAM ahead of time. |
~/fieldstation42/
├── docker-compose.yml
├── .env the Emby/Jellyfin key (keep it private)
└── data/
├── config/ mounted at /config
│ ├── confs/*.json one FieldStation42 config per channel
│ ├── runtime/fs42_fluid.db the schedule and catalog database
│ ├── tuner/sources.json the Sources page (live streams)
│ ├── follows.json followed folders
│ ├── settings.json keeper settings
│ └── auth.json the dashboard password (hashed)
└── catalog/ mounted at /app/catalog
├── media-links/ the pool: one link per video
└── by-genre/<list>/ the link folders your channels play
cd ~/fieldstation42
docker compose pull
docker compose up -dYour channels and schedules are in data/, so they survive updates. To keep a safe copy, see Backups.
Guides
- Server Setup
- Making Channels
- Client Mode Player (the easy way to a TV)
The manual way to a TV
Extras