Cast your screen, YouTube and media to Chromecast & LG webOS TVs on Linux, with native screen mirroring.
Schwupp is a self-contained casting app for Linux desktops and Linux phones
(Phosh, e.g. FuriPhone FLX1). It streams your screen, YouTube and local media to the TV
and supports both Chromecast / Google TV and LG webOS from a single adaptive
GTK4/libadwaita interface — without depending on external CLI tools like catt.
The interface follows your system language (English and German included; English is the fallback for unsupported locales).
| Feature | Chromecast / Google TV | LG webOS (2024+) | AirPlay 2 (Hisense, Samsung …) |
|---|---|---|---|
| Automatic discovery | ✅ | ✅ | ✅ |
| Local media files | ✅ | ✅ | ✅ |
| YouTube | ✅ | ✅ | ✅ (as video stream) |
| Web videos | ✅ | ✅ | ✅ |
| Play / pause / stop, volume | ✅ | ✅ | stop (play/pause device-dependent) |
| Screen mirroring (native) | ✅ | ✅ | — |
| Screen mirroring (HLS) | ✅ | ✅ | ✅ |
Most TVs are found and connected automatically. Newer LG webOS TVs (≈2024 and later) work just like a Chromecast, including screen mirroring.
AirPlay 2 TVs (Hisense/VIDAA, Samsung Tizen, Sony, older non-Cast models …) pair with the code shown on the TV the first time you connect; the pairing is stored, so this happens only once.
Samsung, Sony, Panasonic, Philips and many Hisense TVs without AirPlay are also detected via DLNA and can play your media, web videos and YouTube, with playback and volume control. (Screen mirroring on these needs a Chromecast.)
Mirror your desktop to the TV. (Curious how it works? See docs/MIRRORING.md.)
app/
discovery.py unified discovery (Chromecast + LG via zeroconf)
receivers/ device backends behind one interface:
base.py Receiver interface + feature gating
chromecast.py pychromecast
webos.py pywebostv (control/YouTube) + DLNA (media)
airplay.py pyatv (AirPlay 2: PIN pairing + play_url)
dlna.py minimal UPnP-AVTransport client (webOS media)
server/ local HTTP server (files w/ Range, HLS, live stream)
sources/ YouTube / web video (yt-dlp)
mirror/ pluggable mirror engines (native, hls, dlnats, openscreen)
updater.py self-update (git pull or GitHub ZIP)
ui/ GTK4/libadwaita interface (adaptive desktop/phone)
The GUI only talks to the Receiver interface; which actions appear is driven by
receiver.supports(...).
Arch / Manjaro:
sudo pacman -S python gtk4 libadwaita gobject-introspection \
gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libavDebian / Ubuntu (and derivatives):
sudo apt install python3 python3-venv python3-gi gir1.2-gtk-4.0 gir1.2-adw-1 \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly gstreamer1.0-libavFedora / CentOS / RHEL (dnf):
sudo dnf install python3 python3-gobject gtk4 libadwaita \
gstreamer1-plugins-base gstreamer1-plugins-good gstreamer1-plugins-bad-free \
gstreamer1-plugins-ugly gstreamer1-libavOn CentOS/RHEL enable EPEL (and RPM Fusion for
gstreamer1-plugins-ugly/gstreamer1-libav, which carry patent-encumbered codecs).
The Python dependencies (including yt-dlp) are installed into the venv in the next
step — no extra system package needed.
git clone https://github.com/misc-de/Schwupp.git
cd Schwupp
python -m venv --system-site-packages .venv
.venv/bin/pip install -r requirements.txtFrom inside the cloned Schwupp folder:
./installation.sh # icon + menu entry in ~/.local (no sudo)
./installation.sh --uninstall # remove againAfterwards Schwupp appears in your app menu and launches like any other desktop app — no terminal needed.
Open Schwupp from your app menu. The computer and TV must be on the same network and the TV must be on. The first time you connect to an LG TV, a pairing dialog appears on the TV — confirm it with the remote (the key is then stored). On AirPlay TVs (e.g. Hisense) the TV shows a code instead — type it into the dialog in Schwupp (also stored, one-time).
On startup Schwupp checks that everything it needs is installed: if something required is missing it tells you and stops; if only optional parts are missing it lists them and lets you continue anyway.
Go to Settings → App → "Check for updates". Schwupp checks for a newer version and updates itself in place — your settings are kept — and then offers to restart.
Schwupp stands on the shoulders of these projects:
| Project | Used for | License |
|---|---|---|
| pychromecast | Google Cast protocol (incl. bundled casttube for YouTube) |
LGPL-2.1 |
| pywebostv | LG webOS SSAP control | MIT |
| pyatv | AirPlay 2 pairing & playback (Hisense, Samsung …) | MIT |
| yt-dlp | web video extraction (fallback) | Unlicense |
| python-zeroconf | mDNS service discovery | LGPL-2.1 |
| cryptography | AES-128-CTR for the native mirror | Apache-2.0 / BSD |
| requests | HTTP for the updater | Apache-2.0 |
| PyGObject · GTK4 · libadwaita | the user interface | LGPL |
| GStreamer | screen capture & H.264 encoding | LGPL |
The native Cast-streaming wire format was derived from the public
Chromium Open Screen Library /
media/cast sources (no code copied). The self-update flow is modeled on the author's
DrivePulse app.
These dependencies keep their own licenses; the table above is informational.
Released under the MIT License © 2026 misc-de.
