Repository navigation
Remote Player
This page sets up a second PC, tv-player, that plays your channels on a TV with FieldStation42's own player. It's great for a TV with no Emby or Jellyfin app, like an old CRT in the basement.
The player never makes its own schedule. It copies the server's every hour and plays that, so it always shows the same thing as Emby and Jellyfin. This page gets the PC ready. The next page, Syncing a Remote Player, connects it to the server.
- A PC. It doesn't need to be fast. An old laptop or a small office PC works. Wired network is best.
- A way to get its picture to your TV. HDMI, a VGA adapter, whatever your TV takes. This guide doesn't cover that part. As long as the PC's desktop shows up on the TV, you're set.
-
Ubuntu Server (the current LTS), installed with a user named
tv. No desktop is needed. You'll add just enough to show video. - The server from Server Setup, already running with at least one channel.
The schedule says "this show starts at 8:00". If the two PCs disagree about what time it is, the player will be hours off.
Check the server's time zone:
timedatectl show -p Timezone --valueSet the player to the same one. For example:
sudo timedatectl set-timezone America/New_Yorksudo apt-get update
sudo apt-get install -y --no-install-recommends \
python3-venv python3-tk mpv ffmpeg cifs-utils rsync git \
xserver-xorg xinit x11-xserver-utils alsa-utils fonts-dejavu-coreThis is a bare-bones screen setup (X) plus mpv, the video player FieldStation42 uses.
This step matters more than any other.
The server's channels are made of symlinks. Inside the server's container, every link points at /mnt/media/.... The player copies those links. So the player has to see your videos at exactly /mnt/media too, or every link will point at nothing.
Set it up read-only, the same way as on the server:
sudo install -m 600 /dev/stdin /root/.smbcredentials <<'EOF'
username=<share user>
password=<share password>
EOF
sudo mkdir -p /mnt/media
echo '//192.168.1.10/media /mnt/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/media
ls /mnt/mediaYou should see the same folders the server's container sees (tv, movies and so on). If the server mounts only part of the share, or several shares, mount the same pieces here so the paths match what the container sees.
git clone https://github.com/shane-mason/FieldStation42.git ~/FieldStation42
cd ~/FieldStation42
python3 -m venv env
grep -vE "^[[:space:]]*(#|$)|PySide6|evdev" install/requirements.in > /tmp/req.txt
env/bin/pip install -r /tmp/req.txtThat grep leaves out two optional packages:
- PySide6 is the full Qt toolkit. It's huge, and most of it is for FieldStation42's "web" channels, which the server handles differently anyway. A smaller part of it, PySide6-Essentials, runs the on-screen channel banner. See Channel banner (optional) below.
-
evdev is for a USB remote control. It needs a compiler to install. If you want a remote, run
sudo apt-get install -y build-essential python3-devfirst and skip the grep.
Don't worry about picking a version. The first sync switches FieldStation42 to the exact version the server runs.
Make a small settings file:
mkdir -p ~/.config/mpv
cat > ~/.config/mpv/mpv.conf <<'EOF'
# use the graphics chip to decode video when it can
hwdec=auto-safe
# cheaper scaling, good for older PCs
profile=fast
# never show a mouse pointer on the TV
cursor-autohide=always
# no subtitles unless you turn them on
sid=no
sub-auto=no
EOFThe last two lines turn subtitles off. Without them, mpv shows subtitles on any video that marks a subtitle track as "default", which many do, and it also loads .srt files that sit next to a video.
The goal: turn on the PC, and a few seconds later the TV is playing. No login, no desktop.
The chain works like this. At boot, the tv user is logged in automatically on the first screen. That login starts X. X runs FieldStation42's player. If the player ever stops, X stops too, the login happens again, and it all starts over.
Log in automatically:
sudo mkdir -p /etc/systemd/system/getty@tty1.service.d
sudo tee /etc/systemd/system/getty@tty1.service.d/autologin.conf <<'EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin tv --noclear %I $TERM
EOFStart X after login (only on the first screen, so an SSH login doesn't start it):
cat >> ~/.bash_profile <<'EOF'
[ -f ~/.profile ] && . ~/.profile
[ -z "$DISPLAY" ] && [ "$(tty)" = /dev/tty1 ] && exec startx -- -nocursor
EOFStart the player when X starts:
cat > ~/.xinitrc <<'EOF'
#!/bin/sh
# no screen saver, no blanking
xset s off -dpms s noblank
cd /home/tv/FieldStation42
# the player's messages go to the system log: journalctl -t fs42
systemd-cat -t fs42 env/bin/python3 field_player.py
# wait a little before starting over, so a crash can't spin in a tight loop
sleep 10
EOF
chmod +x ~/.xinitrcIf the PC has more than one screen (a laptop with its own panel, say), you can pick the output here with xrandr before the player starts. For example, xrandr --output HDMI-1 --auto --primary turns on the TV's output. Run DISPLAY=:0 xrandr to see the names.
Using a laptop? Let it keep playing with the lid shut:
sudo mkdir -p /etc/systemd/logind.conf.d
sudo tee /etc/systemd/logind.conf.d/fs42-lid.conf <<'EOF'
[Login]
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
EOFDon't reboot yet. The player has no channels until the first sync. Go on to Syncing a Remote Player, then reboot at the end of that page.
FieldStation42 can show the channel number and name for a few seconds whenever you change the channel, like a cable box. For music videos with .nfo files, it can also show the artist and song when each video starts. Both need a little more software.
- Install Qt's basic parts and a few system libraries:
sudo apt-get install -y --no-install-recommends picom libxcb-cursor0 libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 \
libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libegl1 libgl1 libopengl0 libfontconfig1 libdbus-1-3
~/FieldStation42/env/bin/pip install PySide6-Essentials- Tell the banner what to show. Save this as
~/FieldStation42/osd/osd.json. The black lines are drop shadows that make the text readable on bright pictures:
[
{"type": "StatusDisplay", "format_text": "{channel_number} {network_name}", "font_size": 46,
"text_color": [0, 0, 0, 220], "display_time": 4.0, "x_margin": 0.0825, "y_margin": 0.0835},
{"type": "StatusDisplay", "format_text": "{channel_number} {network_name}", "font_size": 46,
"text_color": [80, 255, 80, 240], "display_time": 4.0, "x_margin": 0.08, "y_margin": 0.08},
{"type": "StatusDisplay", "format_text": "{title}", "font_size": 30,
"text_color": [0, 0, 0, 220], "display_time": 4.0, "x_margin": 0.0825, "y_margin": 0.2035},
{"type": "StatusDisplay", "format_text": "{title}", "font_size": 30,
"text_color": [255, 255, 255, 240], "display_time": 4.0, "x_margin": 0.08, "y_margin": 0.2}
]- Start it from
~/.xinitrc. Add these two lines just before thesystemd-cat ... field_player.pyline:
picom -b --backend xrender
(sleep 8; exec systemd-cat -t fs42-osd env/bin/python3 fs42/osd/main.py) &The banner is a see-through window on top of the video. picom is a small compositor that makes the see-through parts actually see-through. Without it, they'd show as black. The banner starts a few seconds after the player, so its window ends up on top.
- Restart the X session so the new
.xinitrcis used. Don't just restart the player, because the running session already has the old file open:
kill $(pgrep -x xinit)To make the music-video text bigger or smaller, save this as ~/FieldStation42/confs/main_config.json and change the numbers. The sync never overwrites this file.
{"overlay_conf": {"overlay_title_size": 46, "overlay_body_size": 34}}On an older PC, check the CPU first. Current Qt needs a CPU with SSE4.2 (grep -c sse4_2 /proc/cpuinfo should print more than 0). If yours doesn't have it, see FieldStation42's docs/RUNNING_ON_OLD_CPUS.md.
Change the channel by hand (from an SSH login). This tunes to channel 52:
cd ~/FieldStation42 && echo '{"command":"direct","channel":52}' > runtime/channel.socketSee what's playing. This asks mpv for the file it has open:
cd ~/FieldStation42 && python3 -c 'import socket;s=socket.socket(socket.AF_UNIX);s.connect("runtime/mpv.socket");s.send(b"{\"command\":[\"get_property\",\"path\"]}\n");print(s.recv(4096).decode())'Read the player's log:
journalctl -t fs42 -n 50Restart the player:
pkill -f field_player.pyThe autologin brings it back about 10 seconds later.
Without PySide6-Essentials, the log shows No module named 'PySide6' errors now and then. They're harmless: the player keeps playing.
Guides
- Server Setup
- Making Channels
- Client Mode Player (the easy way to a TV)
The manual way to a TV
Extras