Researcher Notes // Field Observations

Experiment 08 — designated S.P.A.N. — was initiated from a garage. Specifically, from a garage containing two projectors aimed at a wall and a persistent, low-grade dissatisfaction with the fact that YouTube did not natively understand this arrangement. The laboratory considered this a solvable problem. The laboratory was correct, though the path to correctness involved a non-trivial number of debugging sessions that will not be enumerated here out of professional dignity.

S.P.A.N. is a single Python script that resolves YouTube URLs through yt-dlp, separates video and audio stream URLs independently to sidestep the HTTP 403 fragment-probing behaviour that lesser solutions stumble into, and fires mpv with a geometry argument that spans the combined display exactly where you tell it to. Negative X offsets are supported. The lab did not anticipate needing to say that. The lab has since updated its assumptions about garage projector setups.

The apparatus includes a built-in remote control server — a minimal HTTP service that starts automatically when S.P.A.N. launches and makes itself reachable from any device on your local network (I mean I guess you could expose it publicly if you really want. The lab notes that "it's your lab's funeral"). Point your phone at the QR code in the interface, paste a URL, tap TRANSMIT. The video begins. The lab considers this an appropriate use of technology. The lab also considered calling this feature "Targeting Uplink" but ultimately exercised restraint. Eventually.

Chief Science Officer's note: "S.P.A.N. was built because we had two projectors and an unreasonable desire to watch YouTube on a wall. It now has a phone remote, a QR code, a themed installation wizard, and a status bar that uses words like 'transmission coordinates.' The lab maintains that all of this was strictly necessary."
Designation S.P.A.N.
Experiment No. BL-008
Status ACTIVE / STABLE
Type Desktop App / AV Apparatus
Platform Linux (Fedora / KDE)
Delivery Single Python Script
Dependencies mpv, yt-dlp, python3-tkinter
Remote Port 8765
Hazard Rating MINIMAL
Data Egress NONE — LOCAL NETWORK ONLY
Negative X Offset SUPPORTED
Phone Remote INTEGRATED
Observation Log
BL-008-1A First span achieved. Black bars present. Noted. Logged. Eliminated.
BL-008-3C 30-second freeze traced to subprocess.PIPE deadlock. The pipe was not helping anyone.
BL-008-5F HTTP 403 on DASH fragments. Root cause: mpv probing. Fixed with --print %(url)s pre-resolution.
BL-008-7B Audio and video URLs resolved separately. itag=140 no longer appears twice. The lab is satisfied.
BL-008-9D Remote server operational. Phone submits URL. Video starts. QR code displays. Lab unreasonably pleased.
BL-008-11A Negative X offset supported. Screen 2 on left confirmed working. Projectors aligned.
01

What It Does
In Plain Language

The following is a plain account for those who prefer their audiovisual apparatuses explainable and their projector configurations free of black bars and deadlocks.

Multi-Screen Spanning
Paste a YouTube URL, select a display mode, and press TRANSMIT. S.P.A.N. resolves the stream and instructs mpv to open a borderless window at whatever geometry you specify — including across both screens simultaneously. The combined width is yours to define. The projectors do not get a vote.
yt-dlp Stream Pre-Resolution
Rather than handing YouTube URLs to mpv and hoping for the best, S.P.A.N. calls yt-dlp twice — once for the best video stream and once for the best audio stream — and passes the bare CDN URLs directly to mpv. This bypasses the fragment-probing behaviour that generates HTTP 403 errors on DASH content. The lab learned this the hard way. You do not have to.
Display Mode Selection
Five modes: Span both screens, Fullscreen on Screen 1, Fullscreen on Screen 2, Windowed on Screen 1, Windowed on Screen 2. The span geometry panel — width, height, X offset, Y offset — only appears when spanning is selected. Negative X and Y values are fully supported for non-standard monitor arrangements. The lab has a non-standard monitor arrangement.
Phone Remote Control
When S.P.A.N. opens, it starts a local HTTP server on port 8765. The interface shows a QR code — scan it from your phone, open the page in any Android browser, paste a URL, tap TRANSMIT. The server receives it, hands it to the GUI thread, and playback begins. Your last ten URLs are stored locally on the phone for quick re-transmission. No app. No pairing. No account.
Quality Selection
Choose Best Available, 1080p, 720p, or 480p. S.P.A.N. constructs the yt-dlp format selector accordingly and caps resolution at your chosen limit. The lab recommends Best Available for spans over 3800 pixels wide but does not enforce this recommendation. It's your projector wall.
Stretch Mode
A checkbox — enabled by default — instructs mpv to fill the window geometry completely regardless of source aspect ratio. On a two-projector wall this eliminates the black bars that otherwise frame a 16:9 video in a 32:9 space. Uncheck it if you want letterboxing. The lab does not want letterboxing. Opinions may differ.
Wayland & X11 Support
S.P.A.N. inspects the session type at launch and selects the appropriate mpv video output context — wayland or x11egl — automatically. Display environment variables stripped by KDE's desktop launcher are re-injected into the subprocess environment so mpv can find the display regardless of how S.P.A.N. was opened. The launcher has been briefed.
Hardware Decoding & Buffering
mpv is launched with --hwdec=auto and a 300 MiB read-ahead cache with a 60-second demuxer window. Cache pause is disabled. This configuration was arrived at through the scientific method, which in this case involved watching a video freeze at precisely the 30-second mark until the cause was identified and eliminated.
Guided Installer
Run ./span.py --install and the script becomes its own installation wizard — invoking dnf to pull mpv, yt-dlp, python3-tkinter, python3-qrcode, and python3-pillow; updating yt-dlp to the latest release; copying itself to ~/.local/bin/span; and writing a KDE-compatible .desktop launcher entry that correctly forwards display environment variables. One command. The lab prefers one command.
02

Installation &
Configuration

Three steps. One command after that. The installer handles the rest with minimal ceremony and a non-zero quantity of terminal output that the lab considers informative.

01
Step One
Download the Script
Download span.py using the button at the top of this page, or pull it directly with curl:

curl -O https://belmontlabs.dev/span.py

The script is self-contained. It requires Python 3 — present by default on Fedora — and nothing else at this stage. The installer will acquire its own dependencies in the next step.
02
Step Two
Run the Installer
Make the script executable and run the built-in installer:

chmod +x span.py
./span.py --install

This will invoke sudo dnf install to pull mpv, yt-dlp, python3-tkinter, python3-qrcode, and python3-pillow; update yt-dlp to its latest release; copy the script to ~/.local/bin/span; and create a .desktop launcher entry in ~/.local/share/applications. The installer will ask for your sudo password exactly once.
03
Step Three
Configure Your Geometry
Launch S.P.A.N. with span from the terminal or find it in your application menu. In Span mode, set your combined geometry — for two 1920×1080 screens side by side, W=3840 H=1080. If your right screen is Screen 1 and your left screen is Screen 2, set X=-1920. If Screen 1 is on the left, set X=0. Y is almost always 0 unless your projectors are vertically offset. The lab's are not. Probably yours aren't either.
04
Step Four
Connect Your Phone
S.P.A.N. displays a QR code and its local IP address in the interface panel. Your phone and your machine must be on the same Wi-Fi network. Scan the QR code with your camera — it opens a browser page themed to match S.P.A.N. — paste a YouTube URL, tap TRANSMIT. The remote page stores your last ten transmissions for one-tap replay. If the QR code doesn't render, type the displayed address into your phone browser directly.
Quick Install Commands
Copy and run in your terminal — requires Fedora / dnf
# Download S.P.A.N. curl -O https://belmontlabs.dev/span.py # Make executable and install (pulls all deps via dnf, creates ~/.local/bin/span and .desktop entry) chmod +x span.py ./span.py --install # Launch span # Or run directly without installing python3 span.py # To update: re-download and re-run --install. Your settings are not affected. curl -O https://belmontlabs.dev/span.py && ./span.py --install
Platform
Fedora Linux with KDE or any desktop using Wayland or X11. Tested on Fedora 42. Other systemd distros with dnf should work. Arch users: install deps manually, the installer uses dnf.
Dependencies
mpv, yt-dlp, python3-tkinter, python3-qrcode, python3-pillow. All installed automatically by --install. Python 3 itself comes with Fedora.
Phone Remote
Any Android browser on the same Wi-Fi network. No app install required. The remote page is served directly from S.P.A.N. on port 8765. Open that port in firewalld if the phone can't connect.
      BL-008 S.P.A.N.: STATUS — ACTIVE / STABLE  ⋮  STREAM RESOLVER: OPERATIONAL — DUAL URL PRE-RESOLUTION ACTIVE — HTTP 403: ELIMINATED  ⋮  MPV GEOMETRY: NOMINAL — NEGATIVE X OFFSET SUPPORTED — PROJECTORS ALIGNED  ⋮  REMOTE TRANSMITTER: ONLINE — PORT 8765 — QR CODE RENDERED — AWAITING PHONE CONNECTION  ⋮  BL-008-3C: SUBPROCESS PIPE DEADLOCK IDENTIFIED AND NEUTRALIZED — THE PIPE HAS BEEN BRIEFED  ⋮  BL-008-5F: DASH FRAGMENT PROBING BYPASSED — yt-dlp PRE-RESOLUTION CONFIRMED SUPERIOR  ⋮  CACHE: 300 MiB FORWARD — 60 SECOND READAHEAD — PAUSE: DISABLED  ⋮  WAYLAND DISPLAY VARS: FORWARDED — KDE LAUNCHER ENVIRONMENT: CORRECTED  ⋮  BL-008-11A: SCREEN 2 ON LEFT FULLY SUPPORTED — THE LAB HAS UPDATED ITS MONITOR ASSUMPTIONS  ⋮  TRANSMISSION COORDINATES ACCEPTED  ⋮  SIGNAL ACQUIRED  ⋮  TRANSMISSION IN PROGRESS  ⋮