Skip to content

Latest commit

 

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Wave TV

An Android TV and Fire TV player for SUB/WAVE stations. A native station picker; selecting a station loads that station's own web player fullscreen, driven by the remote. Skins, themes and artwork render exactly as they do in a browser, because it is the browser player.

This is a shell, not a client. It implements no playback, no theming and no station logic of its own — those belong to SUB/WAVE, and the app's job is to put them on a television and make a D-pad work where a mouse is assumed. No station is bundled; it ships empty.

Please note this was created with use of AI. It is an unofficial community player, not an official SUB/WAVE release, and it is installed by sideloading — review the source or build it yourself if that matters to you.

The Wave TV station picker in its light theme, showing a tuned station and the now-playing panel
The only screen the app draws. The station list on the left, what is playing on the right — cover art, track, artist, album and the show on air, read from the station's public API. Addresses are never rendered here.
The same picker in its dark theme
Light, dark, or the station's own colours. One button cycles them. In station mode the picker samples the loaded player's theme tokens and repaints to match whatever is on air.
The picker in minimal mode, with the now-playing panel collapsed to a strip above the footer
Minimal mode. NP folds the panel down to a single strip and gives the list the full width. The level meter keeps moving only while sound is actually coming out.
A SUB/WAVE web player running fullscreen on a television
Everything past the picker is SUB/WAVE's interface. Masthead, waveform, commentary line, side rail and the operator's theme, unmodified. Wave TV contributes the focus navigation and nothing else.
The SUB/WAVE request drawer, opened with a remote
The request drawer, opened by remote. D-pad navigation lands on the page's real controls; decorative targets are skipped so focus only stops where pressing OK does something.
The television's on-screen keyboard over the request drawer, with press-and-hold-to-speak offered
Typing on a television. OK on a focused field raises the keyboard against the real input; the set-top box's own press-and-hold-to-speak dictation works from there.

Features

The picker

  • Add any number of stations by address; the name is optional and is adopted from the station itself when left blank.
  • A full-height now-playing panel beside the list: cover art, track, artist, album, and the show or DJ on air where a station publishes one. Polled from the station's public API — no authentication required, even for private stations.
  • A level meter that moves only while sound is actually coming out, so a glance says whether the stream is live or stalled.
  • NP collapses the panel to a single strip and gives the list the full width.
  • A station that is answering shows a green lamp; only the tuned station is labelled, and only a station that is not responding is spelled out.
  • Light, Dark, or Station theme, the last tinting the screen with the colours of whatever is currently on air.
  • Addresses are deliberately not rendered on this screen, so a photograph of a television does not publish someone's LAN.

In the player

  • D-pad spatial navigation across the page's real focusable controls, with a visible focus ring. Decorative targets — cover art, scrub bars, volume sliders, clock readouts — are excluded, so focus only lands where pressing OK does something.
  • Song requests by remote, including voice dictation into the request slip.
  • The soft keyboard opens on an explicit OK press and never on focus alone, which is what makes arrow-key navigation usable.
  • The page renders at a 1280 px CSS viewport. Television pixel density otherwise selects each skin's mobile breakpoints, and the result is a phone layout stretched across a television.
  • Sleep timer, one to six hours, armed whenever playback starts.

Stations

  • http:// and https:// both permitted, so a station on the local network works without a certificate.
  • Private stations are handled on both paths SUB/WAVE uses: the in-page members-only gate, and HTTP basic auth.
  • A station that is down or unreachable returns to the picker rather than stranding the app on an error page.

Install

Wave TV is distributed as a sideloaded APK. It is not on any store.

  1. Download WaveTV.apk from Releases and verify its SHA256 against the value published there.

    certutil -hashfile WaveTV.apk SHA256      # Windows
    sha256sum WaveTV.apk                      # Linux
    
  2. Enable sideloading:

    • Google TV / Android TV — Settings → System → About → press Build seven times, then Settings → System → Developer options → USB debugging or Network debugging.
    • Fire TV — Settings → My Fire TV → Developer options → Apps from Unknown Sources.
  3. Transfer and install by any of:

    • adb connect <tv-ip> then adb install WaveTV.apk
    • the Send Files to TV app, which needs no computer
    • the Downloader app on Fire TV, pointed at a URL serving the APK

Requires Android 5.1 (API 22) or later. The television must be able to reach any station added by LAN address.

Adding a station

Select + Add station, or Menu → Add. The address may be a LAN host such as 192.168.1.50:7700 or a public one such as radio.example.com. Leave the name blank to adopt the station's own.

Remote controls

Button Action
D-pad Move focus between the player's controls
OK / Select Activate the focused control
Hold OK Voice request · Sleep timer · Switch station · Reload · Exit
Back Close an open drawer; twice returns to the picker, audio continuing
Play/Pause Toggle tune-in, or start voice dictation while a text field is focused
Stop Mute and unmute
Menu The same menu as holding OK, on remotes that have the button
Search / mic Voice request, where the remote routes that key to applications

Nothing is reachable only by Menu. Not every television remote has that button — the Google TV Streamer's has none at all — so in the player, holding OK opens the same menu.

On the picker: OK tunes in, holding OK on a station offers Edit, Remove and Forget saved password, and Back twice exits. Adding a station, the theme, the now-playing panel and the sleep timer are the four buttons along the top of the screen, so nothing there needs a Menu button either.

Permissions and privacy

One permission, INTERNET. That is the whole manifest. No storage, no microphone permission of its own — dictation is delegated to the system recogniser, which prompts on its own behalf — no location, no accounts.

No analytics, no telemetry, no crash reporting, no advertising. Nothing is transmitted anywhere except to the station selected. allowBackup is disabled, so the station list is never copied off the device by the platform, and uninstalling removes it.

Passwords and your network

Stations may be private, which means a password may be typed into this app with a remote. What that involves:

  • Saved basic-auth credentials are Base64-encoded, not encrypted. Ticking Remember on this device writes them to the application's private storage. Encoding is not secrecy; it protects nothing from anyone with real access to the television. Leave it unticked, or clear it later with long-press OK → Forget saved password.
  • The members-only gate stores its password in the web player's localStorage, exactly as a desktop browser would. The app does not intercept or copy it.
  • http:// traffic is unencrypted, including a password submitted to an http:// station's login form. That is a reasonable trade on a private LAN and a poor one across the internet. Use https:// for anything reachable from outside the network.
  • Only the tuned station is ever asked for, or told, a password. A page can provoke an authentication prompt, and this app's own prompt is a convincing thing to be shown. Any challenge that comes from a host other than the station is refused rather than answered, a saved credential is never replayed to anything else, and a request carrying one will not follow a redirect.
  • Treat a hobby radio station as a place not to reuse an important password.

Known limitations

  • The app is only as good as the page it loads. Layout, playback and station behaviour are SUB/WAVE's; a change there can alter or break what appears here, and the fix belongs upstream.
  • No Chromecast or second-screen support. Playback is local to the television.
  • Links out of the station don't open. The player stays on the host you tuned; a link to somewhere else is declined rather than followed. There is no browser here to hand it to, and everything the shell grants the page — the native bridge, autoplay, a saved password — is granted to that station alone.
  • Voice dictation depends on the remote and the device. Where a manufacturer does not expose the recogniser to third-party applications, the on-screen keyboard is the only input.
  • Requires a WebView modern enough for the station's player. Old or unpatched television firmware may render it poorly regardless of this app.
  • The station list is device-local. Nothing syncs between televisions, and nothing survives an uninstall.
  • The build is Windows-only. build.ps1 is PowerShell and assumes an SDK at C:\Android.

Building

powershell -ExecutionPolicy Bypass -File build.ps1

Requires JDK 17 (Eclipse Adoptium) and an Android SDK at C:\Android with build-tools and platforms;android-35. There is no Gradle; the script drives aapt2 → javac → d8 → zipalign → apksigner directly and prints the SHA256 of the result.

The first run generates a signing keystore, wave-tv.jks. Retain and back it up — without it no future build can install over an existing copy. Its password is read from WAVETV_KEYSTORE_PASS or prompted for; it is deliberately absent from this repository, as are the keystore and the built APK.

Layout

Path Contents
app/AndroidManifest.xml Leanback manifest, INTERNET only, cleartext permitted for LAN stations
app/java/com/wave/tv/MainActivity.java The screen: picker, WebView shell, key handling, now-playing polling, speech-to-text
app/java/com/wave/tv/StationStore.java What survives the process — the station list, the last-played pointer, saved passwords, address validation
app/java/com/wave/tv/Http.java Calls to a station's public API: timeouts, credentials, bounded reads, cover decoding
app/java/com/wave/tv/Palette.java The picker's colour scheme, and reading a station's own theme tokens
app/java/com/wave/tv/Colors.java Wave TV's ink, and the contrast arithmetic that keeps a station's theme readable
app/java/com/wave/tv/ThemeGlyph.java The sun / moon / broadcast marks on the theme toggle
app/java/com/wave/tv/MicGlyph.java The studio mic that marks the show/DJ line
app/java/com/wave/tv/LevelMeter.java The five-bar meter beside the transport
app/java/com/wave/tv/Station.java One entry in the picker: a name and an address
app/assets/tvhelper.js Injected into the page — spatial navigation and the JavaScript ↔ native bridge
app/res/ Launcher icon, television banner, theme

The package identifier is com.wave.tv. Earlier private builds used com.subwave.tv; Android treats the two as separate applications, so an earlier build must be uninstalled first and its station list will not carry over.

Licence

MIT. Use it, change it, ship your own build — just keep the notice with it. There is no warranty of any kind.

SUB/WAVE itself is a separate project under its own licence; nothing here grants you anything in respect of it.

About

An unofficial community player for Subwave stations on Android TV and Fire TV

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages