Skip to content

Add remote control feature (search, playback, fullscreen from phone)#9411

Closed
LambdaGW wants to merge 2 commits into
FreeTubeApp:developmentfrom
LambdaGW:development
Closed

Add remote control feature (search, playback, fullscreen from phone)#9411
LambdaGW wants to merge 2 commits into
FreeTubeApp:developmentfrom
LambdaGW:development

Conversation

@LambdaGW

Copy link
Copy Markdown

Pull Request Type

  • Feature Implementation

Related issue

N/A

Description

Adds an opt-in Remote Control feature (Settings → Remote Control) that lets you control FreeTube from your phone's browser over your local network no companion app to install on either side.

When enabled, FreeTube starts a local HTTP + WebSocket server (off by default) and shows a QR code / URL. Opening that link in any phone browser (iOS Safari, Android Chrome, etc.) gives you:

  • Search videos (works with both the Local API and the Invidious API, following whichever backend is currently selected in Settings)
  • Tap a search result to open/play it
  • Play / pause
  • Volume slider + quick mute toggle
  • Seek bar + skip ±10s buttons
  • Fullscreen toggle (reuses the existing toggleFullScreen bridge already used by the f keyboard shortcut)
  • Live now-playing info (title, thumbnail, progress) pushed back to the phone in real time

Security/privacy design:

  • Disabled by default; must be explicitly turned on per session (it is never auto-started, even if it was left on).
  • Access is gated by a random per-session token (crypto.randomBytes, timing-safe comparison), shown only via the QR code/URL never persisted to disk or synced between windows.
  • The server is scoped to the window that started it: only that window's playback state is ever broadcast, and other windows can't stop/hijack the session.
  • CSP with a per-response nonce (no unsafe-inline), strict input validation on every incoming command, and caps on concurrent connections/searches to bound resource use.
  • All new ipcMain handlers follow the existing isFreeTubeUrl(event.senderFrame.url) guard pattern already used elsewhere in src/main/index.js.

New dependencies: ws (WebSocket server no Node core alternative) and qrcode (QR rendering same rationale the project already applies to autolinker: don't hand-roll a well-defined, easy-to-get-wrong algorithm). Both are small, mainstream, widely-audited packages; qrcode's CLI-only transitive deps (yargs etc.) are not pulled into the renderer bundle since webpack resolves its browser field.

Testing

  1. pnpm install && pnpm run dev to launch a dev build.
  2. Go to Settings → Remote Control and enable it. A QR code and URL should appear.
  3. On a phone (or any other device) connected to the same Wi-Fi/LAN as the desktop, either scan the QR code or type the URL into a browser.
  4. On the remote page:
    • Search for a video and tap a result it should open and start playing on the desktop.
    • Use play/pause, the volume slider, the mute button, ±10s skip, the seek bar, and the fullscreen button each should immediately affect the desktop player.
    • Confirm the now-playing title/thumbnail/progress on the phone updates live as the desktop plays.
  5. Repeat step 3–4 with Settings → Preferred API Backend set to Invidious API instead of Local API, to confirm search works against both backends. (Search reliability here depends on the currently-selected public Invidious instance being reachable this is a pre-existing characteristic of Invidious support in general, not specific to this feature.)
  6. Turn Remote Control back off and confirm the remote page shows "Reconnecting…" and its controls become disabled.
  7. Confirm unrelated core features are unaffected: watch a video normally from the desktop UI, check that Subscriptions/History load normally, and that in-app volume/fullscreen/keyboard shortcuts still behave exactly as before.
  8. Open a second FreeTube window (File → New Window) while Remote Control is running in the first confirm the second window's playback does not get exposed to the connected phone, and that it can't stop the first window's remote session.

Desktop

  • OS: Windows
  • OS Version: Windows 11 Pro
  • FreeTube version: 0.24.1

Additional context

  • The server always binds to a fixed port (9482) and is not yet user-configurable; if that port is already in use, enabling the feature will show an error toast. Happy to add a configurable port as a follow-up if maintainers want it.
  • No translations were added for the new UI strings besides en-US (following the usual FreeTube convention that other locales get filled in via the translation platform, not in the PR itself).
  • Ran pnpm run lint clean; new/changed files were also exercised via a live end-to-end pass (search, play/pause/volume/seek/fullscreen, multi-window isolation) against a running dev build before opening this PR.

LambdaGW added 2 commits July 12, 2026 01:48
Adds an opt-in local HTTP+WebSocket server (Settings > Remote Control)
that serves a self-contained mobile page over the LAN, letting a phone
browser search videos and control playback without installing an app.
Off by default; access is gated by a random per-session token shown as
a QR code, and only the window that started the server can report
state or resolve searches for it.
…align code style

- Route a new 'fullscreen' command through the existing IPC command channel,
  reusing the same already-shipped toggleFullScreen bridge used by the 'f'
  keyboard shortcut.
- Add skip +/-10s, quick mute toggle, haptic feedback, and connection-status
  gating (controls disable while disconnected) to the phone remote page.
- Fix RemoteControlSettings.vue: the error message and loading states were
  nested inside `v-if="isRunning"`, so a failed start could never actually
  show its error, and the loading spinner never appeared before isRunning
  flipped true. Both now render independently of it.
- Rewrite the embedded remote-control page script to ES6 (let/const, arrow
  functions) and fill in missing JSDoc, per project conventions.
- Verified end-to-end against the running app via CDP: real search (Local
  API), real open/play/pause/volume/seek against the live player, real
  state broadcast, and a real Invidious search attempt (which surfaced a
  public instance's bot-check page rather than a bug in this code, verified
  independently with a matching curl request).
@FreeTubeBot FreeTubeBot enabled auto-merge (squash) July 12, 2026 01:05
@github-actions github-actions Bot added PR: dependencies Pull requests that update a dependency file PR: waiting for review For PRs that are complete, tested, and ready for review labels Jul 12, 2026
@absidue absidue closed this Jul 12, 2026
auto-merge was automatically disabled July 12, 2026 08:16

Pull request was closed

@FreeTubeApp FreeTubeApp locked and limited conversation to collaborators Jul 12, 2026
@github-actions github-actions Bot removed the PR: waiting for review For PRs that are complete, tested, and ready for review label Jul 12, 2026
@absidue absidue added PR: waiting for review For PRs that are complete, tested, and ready for review AI-PR PR that has been determined to be completely or majority untested and AI generated and removed PR: waiting for review For PRs that are complete, tested, and ready for review labels Jul 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

AI-PR PR that has been determined to be completely or majority untested and AI generated PR: dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants