"""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 the compositor 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