Skip to content

feat(playback): add opt-in local and remote playback routing - #816

Draft
SHAREN wants to merge 3 commits into
YouROK:masterfrom
SHAREN:feature/playback-devices
Draft

feat(playback): add opt-in local and remote playback routing#816
SHAREN wants to merge 3 commits into
YouROK:masterfrom
SHAREN:feature/playback-devices

Conversation

@SHAREN

@SHAREN SHAREN commented Aug 1, 2026

Copy link
Copy Markdown

Stacked PR: depends on #815. Please review this after #815; once #815 is merged, this diff will automatically shrink to the playback-routing commits only.

Why

TorrServer is often opened on a phone while the computer connected to the TV is somewhere else. A normal vlc:// link always opens VLC on the browser's device, so the phone cannot act as a remote control.

At the same time, existing users should not get a new playback workflow just because they updated TorrServer.

This change adds remote playback as an explicit opt-in feature. With the default settings, TorrServer behaves exactly as before: every browser opens VLC on itself.

Playback modes

The user can choose one of three modes:

  1. Each browser plays locally (legacy)

    • Preserves the existing vlc:// behavior.
    • No playback agent is contacted.
  2. Always use one primary device

    • All phones and computers send playback to one configured TV or media computer.
    • A browser cannot accidentally override the primary target.
  3. Choose a device in each browser

    • Every browser remembers its own target.
    • A browser may be marked Control and playback or Control only.

Remote playback itself is disabled by default. Devices may be configured in advance without enabling routing.

What changed

Server

  • Adds a versioned server-side playback-device registry.
  • Stores configuration in playback_devices.json next to the TorrServer settings.
  • Adds an explicit enable switch and the three routing modes above.
  • Adds APIs to list, add, edit, test, delete, configure, and play on registered devices.
  • Resolves the final target on the server:
    • primary mode always uses the configured primary device;
    • per-browser mode validates the browser's selected device;
    • disabled/local mode does not route playback remotely.
  • Sends playback requests from TorrServer to the agent, avoiding browser CORS and mixed-content problems.
  • Supports a device-specific TorrServer URL when the player reaches streams through a different address than the browser.
  • Safely returns to disabled/local mode if the active primary device is deleted or missing.
  • Reads the earlier prototype's array-only device file but keeps the new feature disabled after migration.

Web UI

  • Adds Remote playback settings under the Application tab.
  • Keeps the feature disabled by default.
  • Adds the three routing modes with plain-language descriptions.
  • Shows a read-only primary target in the header for primary-device mode.
  • Shows a target selector only in per-browser mode.
  • Stores per-browser role and target in local storage.
  • Uses the selected/resolved target from both the quick card action and the VLC action inside Info.
  • Allows devices to be added, edited, tested, and deleted before remote routing is enabled.
  • Updates player controls immediately after settings change, without a page reload.

Fullscreen behavior

Each remote device has its own Open VLC in fullscreen checkbox.

  • It is off by default.
  • When off, the agent opens VLC in a normal window.
  • When on, the agent opens VLC fullscreen.
  • This setting affects only that remote device and does not change local vlc:// behavior.

Agent contract

A registered agent exposes:

GET  /health
POST /play

TorrServer sends:

{
  "path": "Movie.mkv",
  "hash": "40-character torrent hash",
  "index": 1,
  "stream_url": "http://torrserver:8090/stream/Movie.mkv?...&play=",
  "fullscreen": false
}

Security

  • Agent endpoints and tokens are stored only on the server.
  • The normal browser response contains only device IDs and names.
  • Tokens are never returned by the management API; the UI only receives has_token.
  • Leaving the token field empty keeps the saved token.
  • Removing a token requires an explicit checkbox.
  • A newly entered replacement token takes priority over a stale clear checkbox.
  • The configuration file is written with mode 0600 where supported.
  • Device management stays behind the existing TorrServer authentication boundary.

Compatibility

  • No behavior changes after upgrade until the user explicitly enables a new option.
  • Remote playback is disabled by default.
  • Routing defaults to Each browser plays locally (legacy).
  • The quick card button remains separately opt-in through PR 1.
  • Fullscreen is off for every newly added device.
  • Existing local VLC links continue to use the original vlc:// behavior.
  • Multi-file torrents still require choosing a file.
  • Read-only TorrServer mode loads existing configuration but rejects changes.
  • This PR is stacked on the quick VLC-card PR.

Tested

  • go test ./playback ./web/api
  • complete TorrServer server binary build
  • compile-only check for every server package: go test -vet=off -run '^$' ./...
  • yarn lint
  • production yarn build

Automated tests cover:

  • conservative disabled/local defaults;
  • migration from the prototype array format without enabling remote playback;
  • primary mode requiring an existing device;
  • primary mode ignoring a browser-supplied alternative target;
  • per-browser target validation;
  • safe fallback when the primary device is deleted;
  • token redaction, preservation, replacement, and removal;
  • configuration file mode 0600;
  • per-device fullscreen propagation;
  • URL validation and bearer-auth agent requests;
  • forwarded HTTPS stream URLs and device-specific stream URL overrides.

The upstream full test command currently also runs unrelated tests that require the absent server/rutor/rutor.ls fixture and hits an existing vet warning in server/web/api/utils/link.go. The changed packages pass normally, every server package compiles, and the complete server binary builds successfully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant