No description
  • Rust 96.9%
  • CSS 2.3%
  • Shell 0.5%
  • Makefile 0.3%
Find a file
Grandiras 444cb5cd1b Keep the tune-in connection open as long as the node does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 01:22:45 +02:00
build-aux Past broadcasts: VOD playback with seeking, streamer pages; desktop files, icon, Flatpak manifest 2026-10-06 04:24:34 +02:00
data Surf: readable controls in light mode; clear empty state 2026-10-07 08:35:36 +02:00
src Keep the tune-in connection open as long as the node does 2026-10-10 01:22:45 +02:00
tests UI test: Ctrl+K opens a stream with Enter 2026-10-07 09:27:01 +02:00
.gitignore Watchplace: native GNOME client for Streamplace 2026-10-06 04:10:05 +02:00
.set_theater(!w.theater.get()));|&\n act("mute", \|w\| w.toggle_mute());| Composer completion (@ people, : emoji, / commands); consistent chat names; fullscreen hides chat; calmer chat loading 2026-10-06 21:37:35 +02:00
build.rs Watchplace: native GNOME client for Streamplace 2026-10-06 04:10:05 +02:00
Cargo.lock Play live streams over WebRTC (WHEP), with HLS fallback 2026-10-06 15:24:39 +02:00
Cargo.toml Past broadcasts: playback speed (0.75–2×) with normal pitch 2026-10-07 07:43:18 +02:00
LICENSE Add README and license 2026-10-06 04:30:05 +02:00
Makefile Past broadcasts: VOD playback with seeking, streamer pages; desktop files, icon, Flatpak manifest 2026-10-06 04:24:34 +02:00
README.md Chat: newest message fully in view, full handles, replies quote the original 2026-10-07 22:57:03 +02:00

Watchplace

A native GNOME client for watching Streamplace — the livestreaming service built on the AT Protocol. Watching only: no streaming features, just a fast, clean way to find and enjoy streams.

Built with Rust, GTK 4, libadwaita and GStreamer. Talks to the Streamplace node and the public Bluesky AppView directly, using the place.stream.* lexicons — no extra servers.

Features

  • Following — sign in and see who you follow the moment they go live, with the most-watched one featured up top. Offline streamers get a bell for go-live notifications, Continue watching brings back broadcasts you started, and Catch up shows recent ones. Works offline from a cache and starts instantly.
  • Live — everything live, with search, sort, language and category filters tucked away in a popover. Optional shelves (Just started, Picked for you, Small and cozy) can be switched off for a minimal grid.
  • Watch — low-latency playback with an optional ambient glow, auto-hiding controls, theater mode (T), fullscreen (F), screenshots (S), a stream statistics overlay (D), the delay behind live next to the viewer count, the streamer's content warnings, and live chat with badges, name colors, replies (click to jump to the original), links, mentions, pinned messages and @/:// completion. Click a name for a user card with their banner, or hide someone's messages. Chat follows new messages unless you scroll up, and can float over the video in theater mode.
  • Audio only — just listen (with a fraction of the bandwidth and power), from the watch menu.
  • Mini player (I) — pop the stream into a small borderless window and keep browsing.
  • Sign in with ATProto OAuth — one login through your browser (Watchplace never sees your password) powers Following, chat, replies, mentions and following or unfollowing streamers. Watching never needs an account.
  • Live previews — hover a card for a moment to see the stream, muted.
  • Quick switcher (Ctrl+K) — jump to any live stream or streamer by typing a few letters.
  • Past broadcasts — streamer pages with VODs and clips, played with a seek bar (←/→ to skip), at 0.75–2× speed (</>), resuming where you left off.
  • Surf — lean-back channel flipping. Scroll, swipe or use the arrow keys; optional auto-advance.
  • Multiview — up to four streams at once in the largest grid that fits, or a focus layout; click to choose whose audio you hear, and the chat follows along. Drag any stream card onto Multiview to add it. It comes back as you left it.
  • Notifications — when someone you follow goes live, optionally running in the background and starting at login.
  • Customization — light/dark style, accent color, card size, accent glow, live previews, featured banner, chat position, width, text size, timestamps, badges, name colors, latency buffer, start muted, start in theater mode, and more.
  • Adaptive and accessible — works down to phone width (chat moves under the video), with a compact sidebar option, keyboard navigation throughout and named controls for screen readers.

Building

Requirements: Rust (2024 edition), GTK ≥ 4.20, libadwaita ≥ 1.8, libsoup 3, GStreamer ≥ 1.24 with gst-plugins-good/-bad, an H.264 decoder (gst-libav or VA-API) and the GTK 4 paintable sink (gstreamer1-plugin-gtk4 / gst-plugin-gtk4).

On Fedora:

sudo dnf install gtk4-devel libadwaita-devel libsoup3-devel gstreamer1-devel gstreamer1-plugins-base-devel gstreamer1-plugin-gtk4 gstreamer1-plugin-libav

Then:

cargo run                 # development build
make install              # release build into ~/.local (PREFIX=… to change)
make flatpak              # build and install the Flatpak (GNOME 51 runtime)

Keyboard shortcuts

Keys Action
Ctrl+1 … Ctrl+4 Following, Live, Surf, Multiview
Ctrl+F Search live streams
Ctrl+K Go to a stream or streamer
Ctrl+R Refresh
Space / K Play / pause (live streams resume at the live edge)
T Theater mode
I Mini player
S Save screenshot (to Pictures/Watchplace)
D Stream statistics overlay
↑ / ↓ Volume (watch page)
F / double-click Fullscreen
C Toggle chat
M Mute
R Jump to live
← / → Seek 10 s (past broadcasts)
< / > Slower / faster (past broadcasts)
↑ / ↓ / scroll Previous / next stream (Surf)
Esc Leave fullscreen / theater / page

How it works

What Where it comes from
Who is live place.stream.live.getLiveUsers
Your follows app.bsky.graph.getFollows (public AppView)
Profiles app.bsky.actor.getProfiles
Categories place.stream.livestream activity and tags (lang:xx for language)
Recommendations place.stream.live.getRecommendations
Live video WebRTC via place.stream.playback.whep (like Streamplace's own player), falling back to HLS place.stream.playback.getLivePlaylist
Chat, viewers, pins, teleports, bans the node's websocket, /api/websocket/<did>
Content warnings the streamer's place.stream.metadata.configuration record on their PDS
Past broadcasts place.stream.media.getVideoList, place.stream.playback.getVideoPlaylist
Sign-in OAuth via the node's oatproxy: PAR + PKCE + DPoP (ES256) with its downstream client; the code returns through /api/app-return to the tv.aquareum: URI scheme Watchplace registers
Sending chat, following com.atproto.repo.createRecord/deleteRecord through the node (DPoP-bound token), which forwards to your PDS

Live streams play over WebRTC: the server pushes media continuously, which stays smooth even on long round trips, about half a second behind live. If WebRTC can't connect, Watchplace falls back to HLS, where Streamplace's ~1 s CMAF segments are re-anchored on the sink pads with an adaptive buffer (see src/player.rs). WebRTC needs GStreamer's libnice plugin (included in the Flatpak; libnice-gstreamer1 on Fedora).

Settings live in ~/.config/watchplace/settings.json, written with 0600 permissions; that includes the sign-in tokens and the DPoP key.

For the browser to hand the login back, the tv.aquareum: scheme must be registered: the Flatpak and make install do that through the desktop file. If your browser doesn't return to Watchplace, paste the address of the “Complete Login” page into the waiting dialog.

Testing

cargo test runs the unit tests. tests/ui-smoke.sh drives the main flows of a debug build in a private headless GNOME session with playwaita — signed out, with WATCHPLACE_SILENT=1 so nothing reaches a sound device.

License

GPL-3.0-or-later. Watchplace is an independent client and not affiliated with Streamplace.