Initial commit: LG Slim, a private LAN-only remote for LG webOS TVs

Rebuilt from the LG ThinQ app's TV features without the login, cloud,
ads, trackers or analytics. Remote, touchpad, apps, sources, keyboard,
private listening, Wake-on-LAN with live power state, DLNA photo and
video casting, quick-settings tile and widget, dark and light themes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Zakaria
2026-10-28 01:16:49 -04:00
commit a590779e31
62 changed files with 4331 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
<p align="center">
<img src="art/new-logo.png" alt="LG Slim logo" width="160">
</p>
<h1 align="center">LG Slim</h1>
<p align="center">
A slim, private Android remote for LG webOS TVs.<br>
Everything the LG ThinQ app does for a TV, minus the bloat: no login, no cloud, no ads, no trackers.
</p>
<p align="center">
<img src="docs/remote-dark.png" alt="Remote, dark mode" width="240">
&nbsp;
<img src="docs/remote-light.png" alt="Remote, light mode" width="240">
&nbsp;
<img src="docs/apps.png" alt="Apps" width="240">
</p>
---
## Why
LG ThinQ is about 313 MB, needs an LG account, and ships with analytics, ad and attribution SDKs. To control a TV that sits on your own Wi-Fi, none of that is needed.
LG Slim talks **only to the TV on your local network**. The release APK is about **1.4 MB**.
## Features
- **Remote:** D-pad, OK, Back, Home, Settings, Info, Guide, Exit, channel rocker, number pad, colour keys, and media keys. Keys fire the moment your finger touches them, and holding repeats.
- **Volume rocker:** fills with the TV's current level. Tap or hold to step, or drag to jump straight to a level. The phone's volume buttons control the TV too.
- **Live status lamp:**
- green: on
- blue, pulsing: connecting or waking
- dark: off or in standby
Power state comes from the TV itself, so standby is never mistaken for on.
- **Power:**
- **Off:** turns the TV off.
- **On:** Wake-on-LAN, using the same packet LG's app sends, plus fast reconnect polling.
- **Detection:** an off TV is noticed in about 1.5 s.
- **Private listening:** TV sound plays on the phone, so you can use your headphones. The phone receives raw PCM straight from the TV over the LAN. It keeps playing with the phone screen off, and there's a notification with a Stop button.
- **Touchpad:** pointer, tap to click, two-finger scroll.
- **Keyboard:** live typing into the TV's text fields. It opens by itself when the TV asks for text.
- **Apps:** large tiles for your pinned apps, with the on-screen app marked.
- **Sources:** HDMI inputs and a searchable channel list.
- **Photos & videos:** show phone media on the TV, served straight from the phone to the TV over DLNA. Photos are re-encoded first, which strips EXIF data such as GPS location.
- **Quick-settings tile and home-screen widget:** power, volume, mute, and private listening.
- **Multiple TVs:** auto-discovery (SSDP, with a subnet sweep as fallback), or add one by IP. You can rename TVs ("Living room", "Main TV" and so on).
- **Dark and light themes:** soft, top-lit keys.
## Privacy
| | LG ThinQ | LG Slim |
|---|---|---|
| LG account / login | Required | None |
| Cloud servers | Yes | **Never contacted** |
| Analytics, ads, attribution SDKs | Yes | None |
| ACR (screen content recognition) | Supported | Not implemented |
| Voice / microphone | Yes | Not used |
| Location permission | Yes | Not requested |
How it's enforced in code (`net/Lan.kt`):
- The only HTTP client can reach **private IPv4 addresses only**. Hostnames are refused before any DNS lookup, so the app never even resolves a domain.
- **TLS with trust on first use:** the TV's certificate is remembered at pairing. If it changes, the app refuses to connect until you re-pair on the TV screen.
- **Paired-TV data stays on the phone:** client keys and certificate fingerprints live in app-private storage, and Android backups are disabled.
- **Excluded TV services:** the TV calls that report to LG are never used. That covers content recognition (`tv/getACRAuthToken`), account linking (`iotclient/*`), the LG server relay (`sdx/*`), and `user/setUserInfo`.
## Requirements
- An LG TV running **webOS**, on the same network as the phone.
- **Android 8.0+** (API 26).
- To turn the TV on from the app, enable **Turn on via Wi-Fi** (or **Mobile TV On**) in the TV's settings.
## Build
Requires JDK 17 and the Android SDK (compileSdk 35).
```bash
./gradlew assembleRelease
adb install -r app/build/outputs/apk/release/app-release.apk
```
The release build is minified and signed with your local debug key for sideloading.
## How it works
| Feature | Protocol |
|---|---|
| Control | webOS **SSAP**: JSON over WebSocket on `wss://tv:3001`, plus the pointer socket for buttons |
| Power state | `com.webos.service.tvpower/power/getPowerState` subscription |
| Wake | Wake-on-LAN magic packet with LG's `THINQ` trailer, sent to UDP 9 and 7 |
| Private listening | `secondscreen.gateway/test/secure` → `soundshare/startStreamOut` → raw 48 kHz 16-bit stereo big-endian PCM on TCP 9000 |
| Photos & videos | UPnP/DLNA **AVTransport** on the TV's MediaRenderer (port 1966), with the file served from the phone |
| Discovery | SSDP `urn:lge-com:service:webos-second-screen:1` |
```
app/src/main/java/app/tvremote/
├── net/ SSAP client, LAN-only HTTP, discovery, Wake-on-LAN, DLNA, media server
├── data/ Connection state, power state, paired TVs
├── audio/ Private listening service
├── widget/ Quick-settings tile and home-screen widget
└── ui/ Compose UI: remote, touchpad, apps, sources, listen
```
## Disclaimer
This is an independent, unofficial project. It is not affiliated with or endorsed by LG Electronics. "LG" and "webOS" are trademarks of their respective owners.