No description
  • Python 97.9%
  • CSS 1.4%
  • Shell 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Brian 2188025939
All checks were successful
Build Flatpak / flatpak (push) Successful in 2m10s
Read the runtime from the manifest, and allow a remote title
Both changes come from reusing this workflow for a second app, where the
parts that were quietly specific to this one showed up.

The runtime was hardcoded to org.gnome.Platform//50 with a comment about
GTK4 and libadwaita. That is true here and nowhere else: the other repo
builds against freedesktop 25.08 and failed with "Unable to find sdk
org.freedesktop.Sdk version 25.08" while GNOME 50 was installed around it.
Runtime, runtime-version and sdk are now read from the manifest alongside
app-id, unquoting as they go since versions are written '50' or '25.08'.
Checked against both manifests: this one resolves to exactly the pair that
was hardcoded, so nothing about this build changes.

FLATPAK_TITLE gives the published .flatpakrepo a readable name, falling back
to the slug. Without it the other app would have lost the title it had from
hardcoding one.

The two workflows now differ only in vendored dependencies and which test
suites run, which is as it should be.
2026-08-22 11:03:42 -06:00
.forgejo/workflows Read the runtime from the manifest, and allow a remote title 2026-08-22 11:03:42 -06:00
data Match the app id to the Flatpak, and fix a racy player harness 2026-08-20 09:20:25 -06:00
flatpak Give AMD and Intel machines a working hardware decoder 2026-08-22 00:33:40 -06:00
kickclient Consume mpv's render notification so software decoding draws 2026-08-22 02:20:51 -06:00
scripts Consume mpv's render notification so software decoding draws 2026-08-22 02:20:51 -06:00
tests Take the remaining synchronous mpv calls off the UI thread 2026-08-22 01:58:50 -06:00
.gitignore Make app identification robust on the runner 2026-08-17 21:24:29 -06:00
install.sh Match the app id to the Flatpak, and fix a racy player harness 2026-08-20 09:20:25 -06:00
pytest.ini Untangle chat visibility from full screen, and fix the quality menu 2026-08-20 10:45:25 -06:00
README.md Initial commit: native GTK4 Kick.com client with HTPC mode 2026-08-17 00:03:48 -06:00
run.py Initial commit: native GTK4 Kick.com client with HTPC mode 2026-08-17 00:03:48 -06:00

KickClient

A native GTK4 / libadwaita desktop client for watching Kick.com streams on Linux, with live chat and a full-screen HTPC mode you can drive entirely from a remote.

Features

  • Browse live channels, categories, search, and the channels you follow
  • Watch through libmpv, rendered inside the app with hardware decoding
  • Live chat with inline emotes, badges and colour-coded names, over Kick's Pusher websocket
  • Send chat once signed in
  • HTPC mode (F11) — a 10-foot interface navigable with arrow keys, Enter and Escape, or an IR remote's media keys
  • Quality selection across every rendition the stream offers
  • Keeps the screen awake while a stream is playing

Viewing works without signing in. A Kick account is only needed to see your followed channels and to send chat messages.

Requirements

Arch / CachyOS:

sudo pacman -S gtk4 libadwaita mpv webkitgtk-6.0 python-gobject

Python dependencies are installed into a local virtualenv by the installer.

Install

./install.sh

This creates .venv/, installs a kickclient launcher into ~/.local/bin, and registers the desktop entry and icon.

Usage

kickclient
kickclient xqc
kickclient --htpc

A channel slug, a full kick.com/<channel> URL, or a kick: URI all work.

Signing in

Menu → Sign in. Kick's real site opens in an embedded browser view; sign in exactly as you would in a browser, including two-factor if you have it enabled. The app never sees or handles your password — it reads only the session cookie Kick sets afterwards, and stores that in your system keyring. The window closes itself once the session is captured.

If the page shows "Oops, something went wrong" — click the account icon in Kick's own header (top right) and sign in from there. This is Kick's error boundary tripping on the freshly loaded page, not a fault in this client: the site's header keeps working, and navigating from it lands on a working sign-in form. Sometimes the page also recovers on its own after ~30 seconds, and the reload button in the title bar retries. /login is affected identically, so the homepage is loaded deliberately — its header is the reliable route in.

Remote / keyboard controls

Key Action
Arrows Navigate the grid
Enter Open the focused channel
Escape / Backspace Back, or leave HTPC mode
Space / Play Pause and resume
C Show or hide chat
I Show stream info
M / Mute Mute
+ / − / Volume keys Volume
Page Up/Down, Prev/Next Previous or next channel
F11 Enter or leave HTPC mode

IR remotes that emit the standard XF86Audio* media keys work without configuration.

Configuration

Settings live in a SQLite database at ~/.local/share/kickclient/kickclient.db and are edited from the Preferences window (Ctrl+,) — there are no environment variables to set. Credentials are kept in the system keyring, never in that database.

Development

.venv/bin/python -m pytest tests/ -q

The scripts/ directory holds verification harnesses that run against the live site — smoke_api.py, smoke_chat.py, smoke_player.py, smoke_app.py (add --htpc), and smoke_login.py (--check / --logout).

How it works

Kick's official public API cannot drive a viewer client: it exposes no playback URLs, cannot read chat, and delivers events only by webhook. This client therefore uses the same internal endpoints the Kick website itself calls.

  • Playback is standard AWS IVS HLS with no DRM. The signed URL carries a token that expires after roughly four hours, so it is refreshed automatically mid-session.
  • Chat reading needs no authentication. The Pusher app key is discovered at runtime rather than hardcoded, because Kick rotates it.
  • All HTTP goes through one swappable session layer, so browser TLS impersonation can be enabled from Preferences if Kick's bot protection ever tightens.

A note on Kick's Terms of Service

Kick's terms prohibit accessing the service "through any technology or means other than those provided or authorized," and this client is by definition a third-party means. In practice the risk is to your account, not a legal one, and it rises if you distribute modified builds. This project is intended for personal use.

It deliberately does not automate past any bot challenge: signing in happens in a real browser engine, driven by you.