Files
Classroom_Desktop/lib/classroom_vlc.py
T
ekklesiaandClaude Opus 5 f8ddfbe345 feat: make DVD playback a classroom surface, not a media player
Pressing DVD now enters DVD mode rather than opening VLC. VLC is still
the backend, because its dvdnav module is what decodes disc menus and
nothing else on Debian does that reliably, but nothing a person can see
or press belongs to it any more.

classroom-dvd-session owns the whole thing. It puts a full-screen black
layer-shell surface up the moment the button is pressed, starts VLC
behind it, and drops it once playback is actually on screen — so the
harsh cut from wallpaper to VLC's black window is gone, and no partial
VLC window or reserved dock strip is ever visible. A deadline drops the
surface regardless, because DVD mode must never leave a black screen
with nothing behind it.

The controls are a classroom bar on the overlay layer, the one layer
sway draws above a fullscreen window. It slides up when the pointer
reaches the bottom of the screen and hides again shortly after it
leaves. It is drawn from the dock's own stylesheet at the room's UI
scale, so it is the same surface, the same radius and the same white
icons. While hidden it only accepts the pointer in a thin strip along
the bottom edge, so a click on a disc menu goes to the disc.

The bar reaches VLC through an HTTP interface on loopback behind a
password generated per session, sending hotkey *actions* by name. That
is what makes the next part possible.

All 108 hotkeys VLC 3.0.23 defines are unset, then Space, Esc and the
arrow keys plus Enter are bound. Crop, aspect ratio, subtitles, audio
tracks and deinterlacing are no longer reachable by pressing a key at
random, and the arrow keys no longer change VLC's volume — the
television owns volume, and CEC will own it properly later.

Esc quits instead of leaving fullscreen. There is nothing to leave, and
leaving it was what stranded people on a black VLC window. Close, Eject
and Esc all ask VLC to quit and escalate to SIGTERM then SIGKILL if it
does not; when VLC exits by any route, including a crash, the session
ends and the classroom desktop comes back.

Verified against VLC 3.0.23 on Trixie: every argument accepted, every
control action accepted over the control interface, a wrong password
refused, and quit exiting cleanly. The surfaces were rendered under a
headless sway and screenshotted to check the bar against the dock.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-04 22:33:53 -05:00

128 lines
5.0 KiB
Python

"""How the classroom launches VLC.
VLC is the DVD backend because its dvdnav module is what decodes disc
menus. Everything a user can see or press, though, belongs to the
classroom: the visible controls are classroom-dvd-session's overlay, and
VLC's own interface and keyboard are shut down here.
"""
import secrets
PLAYER = "vlc"
# Every hotkey VLC 3.0.23 defines, read out of `vlc -H --advanced` on
# Debian Trixie. All of them are unset before anything is bound, so a
# volunteer cannot land on crop, aspect ratio, subtitle tracks, audio
# tracks, deinterlacing or the volume by pressing a key at random.
#
# A future VLC that adds a hotkey would leave it bound. Regenerate with:
# vlc -H --advanced | grep -oP '^\s+--key-\K[a-z0-9-]+'
ALL_HOTKEYS = (
"aspect-ratio", "audio-track", "audiodelay-down", "audiodelay-up",
"audiodevice-cycle", "chapter-next", "chapter-prev", "clear-playlist",
"crop", "crop-bottom", "crop-left", "crop-right", "crop-top",
"decr-scalefactor", "deinterlace", "deinterlace-mode", "disc-menu",
"faster", "frame-next", "incr-scalefactor", "intf-boss",
"intf-popup-menu", "intf-show", "jump-extrashort", "jump-long",
"jump-medium", "jump-short", "leave-fullscreen", "length", "loop",
"nav-activate", "nav-down", "nav-left", "nav-right", "nav-up", "next",
"pause", "play", "play-bookmark1", "play-bookmark10", "play-bookmark2",
"play-bookmark3", "play-bookmark4", "play-bookmark5", "play-bookmark6",
"play-bookmark7", "play-bookmark8", "play-bookmark9", "play-pause",
"position", "prev", "program-sid-next", "program-sid-prev", "quit",
"random", "rate-faster-fine", "rate-normal", "rate-slower-fine",
"record", "set-bookmark1", "set-bookmark10", "set-bookmark2",
"set-bookmark3", "set-bookmark4", "set-bookmark5", "set-bookmark6",
"set-bookmark7", "set-bookmark8", "set-bookmark9", "slower",
"snapshot", "stop", "subdelay-down", "subdelay-up", "subpos-down",
"subpos-up", "subsync-apply", "subsync-markaudio", "subsync-marksub",
"subsync-reset", "subtitle-revtrack", "subtitle-text-scale-down",
"subtitle-text-scale-normal", "subtitle-text-scale-up",
"subtitle-toggle", "subtitle-track", "title-next", "title-prev",
"toggle-autoscale", "toggle-fullscreen", "uncrop-bottom",
"uncrop-left", "uncrop-right", "uncrop-top", "unzoom",
"viewpoint-fov-in", "viewpoint-fov-out", "viewpoint-roll-anticlock",
"viewpoint-roll-clock", "vol-down", "vol-mute", "vol-up", "wallpaper",
"zoom", "zoom-double", "zoom-half", "zoom-original", "zoom-quarter",
)
# The only keys a classroom DVD responds to.
#
# Esc quits rather than leaving fullscreen: DVD mode is the whole screen,
# so there is nothing to leave, and leaving it used to strand people on a
# black VLC window with no way out. Volume is deliberately absent — the
# television owns volume.
CLASSROOM_HOTKEYS = {
"play-pause": "Space",
"quit": "Esc",
# Disc menu navigation. Without these a menu can only be clicked.
"nav-up": "Up",
"nav-down": "Down",
"nav-left": "Left",
"nav-right": "Right",
"nav-activate": "Enter",
}
# VLC dressed down to a playback surface. Verified against 3.0.23.
PRESENTATION = (
# DVD mode is the whole display, and sway fullscreens the window the
# moment it maps so no wallpaper is ever visible around it.
"--fullscreen",
# No menu bar, no panels, dark rather than light grey.
"--qt-minimal-view",
"--qt-dark-palette",
# No orange cone or album-art panel behind the video.
"--no-qt-bgcone",
# VLC's own fullscreen controller is replaced by the classroom bar.
"--no-qt-fs-controller",
# Nothing that behaves like a desktop application.
"--no-qt-system-tray",
"--no-qt-name-in-title",
"--no-qt-video-autoresize",
"--qt-notification=0",
# Never offer to resume, never keep a list of the discs played here.
"--qt-continue=0",
"--no-qt-recentplay",
# No first-run privacy dialog, no title banner over the video.
"--no-qt-privacy-ask",
"--no-video-title-show",
)
def control_password():
"""A fresh password for this session's control interface."""
return secrets.token_urlsafe(24)
def player_command(device, port, password):
"""The full VLC command line for a DVD session.
The HTTP control interface is how the classroom's own control bar
reaches VLC. It triggers hotkey *actions* by name, which keeps
working after every key has been unbound, and it listens on the
loopback address behind a password generated for this session only.
"""
command = [PLAYER, *PRESENTATION]
for hotkey in ALL_HOTKEYS:
command.append(f"--key-{hotkey}=")
for hotkey, binding in CLASSROOM_HOTKEYS.items():
command.append(f"--key-{hotkey}={binding}")
command += [
"--extraintf",
"http",
"--http-host",
"127.0.0.1",
"--http-port",
str(port),
"--http-password",
password,
]
# dvd:// selects dvdnav, which is what provides the disc menus.
command.append(f"dvd://{device}")
return command