An early, community-built LG webOS TV client for the Silo self-hosted media server. It is designed as a 10-foot interface: every primary action is usable with a TV remote, while mouse and keyboard support make browser development convenient.
Important
This project is under active development and is not store-ready. Native Silo authentication, catalog, and playback contracts still need validation against a live server, and playback needs testing across multiple LG webOS generations.
- Native Silo device/QR sign-in, with username and password as a fallback
- Multiple saved Silo servers and locally persisted sessions
- Profile-aware home layout, libraries, favorites, and watchlist
- Movies, TV, music, and audiobook library surfaces
- Series, season, and episode navigation
- Continue Watching and other server-defined home rails
- Debounced catalog search
- D-pad spatial navigation and LG Back-key handling
- Protocol-v3 playback planning and replanning
- HLS playback with negotiated request headers
- Resume, seek, chapter markers, and playback progress reporting
- Audio track, subtitle track, file version, and quality selection
- Profile appearance themes and text preferences
- Build, package, install, launch, and inspect helpers for LG TVs
The current development version is 0.2.0-dev.
The main workflows are implemented and compile successfully, but the application has not yet reached a stable release. In particular, the native Silo API payloads and playback routes must be exercised against a live Silo installation, and codec/container support must be verified on physical LG hardware.
See the first-grade client roadmap for the release blockers and longer-term parity targets.
- React 19
- TypeScript 5.7
- Vite 6
hls.jsfor HLS playback where native execution is unavailableqrcodefor device-login pairing- LG
@webos-tools/clifor packaging and deployment
For browser development:
- Node.js and npm
- A reachable Silo server
For TV deployment:
- An LG webOS TV with the Developer Mode app installed
- An LG developer account
- LG's
@webos-tools/cli - A workstation and TV on the same network
The included bootstrap script targets CachyOS and other Arch-based distributions. Other operating systems can use the same npm commands after installing Node.js and the webOS CLI manually.
Install dependencies:
npm installPoint the Vite development proxy at your Silo server and start the app:
SILO_DEV_SERVER=https://silo.example.com npm run devOpen the URL printed by Vite. Use the arrow keys to move focus, Enter to select, and Escape or Backspace to go back.
The development server proxies /__silo to SILO_DEV_SERVER. This keeps browser requests same-origin and avoids changing production server handling. Use a server URL that is reachable from the development workstation. Self-signed HTTPS certificates are accepted by the proxy during local development.
The setup helper installs the system packages, webOS CLI, and project dependencies, then checks the toolchain:
chmod +x scripts/*.sh
./scripts/setup-cachyos.shThe equivalent manual setup is:
sudo pacman -S --needed nodejs npm git base-devel
sudo npm install -g @webos-tools/cli
npm install
npm run webos:checkOn the TV:
- Install Developer Mode from the LG Content Store.
- Sign in with an LG developer account.
- Enable Dev Mode Status and Key Server.
- Note the TV's IP address and the passphrase shown by the app.
On the development workstation, register the TV:
ares-setup-deviceChoose a device name such as livingroom, then retrieve its developer key:
ares-novacom --device livingroom --getkeyConfirm that the TV is reachable:
ares-device-info --device livingroomDeveloper Mode certificates expire. If deployment suddenly stops working, reopen the Developer Mode app, extend the session, and retrieve the key again if required.
Create a production build:
npm run buildPackage it as an IPK in release/:
npm run webos:packageBuild, package, install, and launch in one command:
WEBOS_DEVICE=livingroom npm run webos:deployWEBOS_DEVICE defaults to livingroom. The application ID defaults to org.siloserver.webos; override it for launch and inspection with WEBOS_APP_ID if you change public/appinfo.json.
To open LG's Web Inspector for the installed application:
WEBOS_DEVICE=livingroom npm run webos:inspect| Command | Purpose |
|---|---|
npm run dev |
Start the Vite development server on all interfaces |
npm run build |
Type-check and create the production build in dist/ |
npm run preview |
Preview the production build locally |
npm run webos:check |
Verify Node, npm, LG CLI tools, and configured devices |
npm run webos:package |
Build and package an IPK into release/ |
npm run webos:install |
Install the first IPK in release/ on the configured TV |
npm run webos:launch |
Launch the application on the configured TV |
npm run webos:deploy |
Package, install, and launch the application |
npm run webos:inspect |
Open Web Inspector for the application |
Device sign-in is the primary TV experience and uses Silo's native API:
POST /api/v1/auth/device/start
│
├─ TV displays the QR code and pairing code
│
├─ user approves the request in Silo
│
└─ POST /api/v1/auth/device/poll
│
└─ access token, refresh token, and profile context
The approved poll response is captured immediately because the server returns token fields only on the first successful poll. Username/password login remains available from Use password instead.
Saved server details, session tokens, pending pairing state, and navigation state are stored in webOS browser localStorage. Treat a Developer Mode TV as a trusted device and sign out or remove the application before transferring it.
Playback is negotiated with Silo rather than assembled from ad hoc media URLs:
LG media capability probe
↓
Silo playback-v3 start request
↓
direct play / remux / transcode decision
↓
negotiated HLS plan
↓
HTMLMediaElement + hls.js
↓
progress, stop, seek, quality, and track replanning
The client advertises codecs based on HTMLMediaElement.canPlayType(). Original-file and progressive delivery are currently disabled in its device profile because LG's browser can report codec support while rejecting the source container. The server is asked to produce a compatible HLS route instead.
Only Silo's native API is used. Jellyfin-compatible endpoints, headers, models, and playback URLs are intentionally out of scope.
public/ webOS metadata and application icons
scripts/ setup, packaging, deployment, and inspection helpers
src/api/ native Silo API and playback contracts
src/components/ reusable 10-foot UI components
src/core/ server and session registry
src/navigation/ remote/spatial focus behavior
src/platform/ LG webOS capabilities and device behavior
src/screens/ application screens and player UI
docs/ roadmap and project documentation
Architecture boundaries are deliberate: API access belongs in src/api, LG-specific behavior in src/platform, and remote focus logic in src/navigation. UI components should not contain raw API URLs.
- The native Silo contracts have not yet been validated end-to-end against the target live server.
- Playback behavior has not yet been qualified across old and current LG webOS models.
- Token refresh and single-flight retry are not implemented.
- Household profile selection and PIN entry are not implemented.
- Network-loss recovery and expired-session UX need work.
- Subtitle styling and intro/credits controls are incomplete.
- Automated tests for navigation, auth, parsing, and player state are not yet present.
- Store assets, accessibility review, privacy copy, trademark permission, and LG certification remain outstanding.
Issues and focused pull requests are welcome. Before proposing API changes, validate them against Silo's current native server contract or official clients; do not infer endpoints from Jellyfin compatibility behavior.
For changes:
- Keep the architecture boundaries described above.
- Ensure all interactive controls remain reachable with Up, Down, Left, Right, OK, and Back.
- Run
npm run buildbefore opening a pull request. - Describe whether the change was tested in a browser, against a live Silo server, and on physical LG hardware.
No license has been granted for this repository yet. Unless and until a license file is added, normal copyright restrictions apply to the code in this repository.
The Silo name and logo are separately trademarked. Development and private sideloading may use working branding, but public distribution or LG Content Store publication requires permission from the trademark owner.