Skip to content
hanzhePublic

About

Norwegian internet radio (NRK, P4, Radio Rock, ...) and podcasts with offline downloads, for the Nokia 8110 4G on KaiOS / GerdaOS

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Eter

På eteren: Norwegian internet radio and podcasts for the Nokia 8110 4G running KaiOS 2.5 / GerdaOS.

Eter is a small packaged KaiOS app built for a 240x320 screen and a keypad. It plays NRK, the P4 group, Bauer's stations and a few others, plus any podcast, and keeps playing with the screen off. It opens on a start screen: 1 Radio or 2 Podcasts (your last choice is preselected).

ETER

Features

Radio

  • 32 Norwegian stations, all plain MP3 over HTTPS (no HLS or DRM, which this Gecko 48 engine can't handle)
  • Favourites: star any station, and it shows up at the top of the list on number keys 1-9
  • Background playback on the content audio channel, so the screen can turn off
  • Automatic reconnect with backoff when 4G drops, switching to a fallback stream URL where there is one
  • In-app volume on Left/Right with its own bar in the bottom panel, remembered between launches
  • Remembers your favourites and the last station you played

Podcasts

  • Top in Norway: Apple's live podcast chart for Norway (Forklart, Spårtsklubben, AVHØRT, ...)
  • Search any podcast by name, and follow shows. Followed shows come first, with their latest episode.
  • Episodes show date, length and where you are: 47 min left, Played, Downloaded, Downloading 34%
  • Resumes where you stopped (saved every 10 seconds, on pause and on leaving), and marks an episode played near its end
  • Skip back 15 s / ahead 30 s, pause, and speed 1x / 1.25x / 1.5x / 2x, from any podcast screen
  • Downloads for offline listening, to the phone's storage. See Downloads.
  • The now bar shows the position (10:30 / 57:03) with a progress line

Keys

Start screen: Up / Down and Enter, or 1 Radio / 2 Podcasts. SoftLeft stops playback, Back closes the app. In Radio and Podcasts, Back goes up a level, and back to the start screen from the top.

Radio

Key Action
Up / Down Move through the list
Enter Play the selected station, or stop it if it's already playing
1-9 Play favourite 1-9
SoftRight Add or remove the selected station as a favourite
SoftLeft Stop
Left / Right Volume down / up (in-app, 10% steps)
0 Jump to the top of the list

Podcasts

Key Action
Up / Down, Enter Pick a show, Top in Norway, Search or Downloads; on an episode, play / pause it
SoftRight On a show: follow / unfollow. On an episode: download, cancel, resume or delete the download
SoftLeft In a show: follow / unfollow it
5 Pause / resume the playing episode
4 / 6 Back 15 s / ahead 30 s
* Speed: 1x, 1.25x, 1.5x, 2x (remembered)
# Mark the selected episode as played / not played
Left / Right Volume
Search: type, then Enter Search (T9 works); Down / Up and Enter to open a result, SoftRight to follow it

To keep listening while using the phone, press the red End key. The app stays open in the background.

Default favourites: NRK P1, NRK P3, P5 Hits, Radio Rock, P4 Norge, NRK mP3.

Stations

Group Stations
NRK P1, P1+, P2, P3, mP3, P13, P3 Musikk, Nyheter, Sport, Klassisk, Jazz, Folkemusikk, Super, Sápmi
P4-gruppen P4 Norge, P5 Hits, P6 Rock, P7 Klem, P8 Pop, P9 Retro, P10 Country, P11 Dance, P12 Hitmix
Bauer Radio Rock, Radio Norge, NRJ Norge, Topp 40, P24-7 Mix, Norsk Pop, Radio Vinyl
Other Radio Nova, Radio Tromsø Hits

The list is in app/js/stations.js. Stream URLs were found with Radio Browser and checked to return audio/mpeg with valid MP3 frames (October 2026). Broadcasters do move streams around. If one stops working, update its url (and optionally its alt fallback).

Podcasts

Where podcasts come from

  • Top in Norway: itunes.apple.com/no/rss/toppodcasts (the chart's ids), then one itunes.apple.com/lookup call for their RSS feed URLs. Cached for 12 hours. Apple's newer chart endpoint (rss.marketingtools.apple.com) answered 502 when this was built.
  • Search: itunes.apple.com/search in the Norwegian store. No API key is needed for either.
  • Episodes: each show's own RSS feed, cached for 30 minutes (and shown from the cache when offline). Feeds are scanned with regular expressions instead of DOMParser, so the parser runs under node tests and stops after the newest 50 episodes. Forklart's feed is 1.6 MB with 600 episodes.

Requests use systemXHR, because most podcast hosts don't send CORS headers, and they identify as eter/1.1 (podcasts; https://github.com/hanzhe/eter).

Certificates

The hosts checked (NRK, Apple, Acast, Omny, Buzzsprout, Libsyn, Megaphone, Podtrac, Simplecast, SoundCloud, Smartpod, Schibsted's feeds) all chain to roots in the phone's 2016 built-in list, except Let's Encrypt's ISRG Root X1 (anchor.fm, Schibsted). That root was already added to this GerdaOS phone's certificate database, so those work here. A phone without it can't load those feeds; see Kuling's notes for how a root is added.

Downloads

Episodes are 80-200 MB (NRK publishes at 192 kbit/s), too big to fetch in one request on a phone with 512 MB of RAM. So downloads.js fetches 2 MB HTTP Range requests and appends each to the file with DeviceStorage.appendNamed:

  • Files go to eter/<episode id>.mp3 in the sdcard storage. On a phone without a card that is internal storage (2.3 GB free on this one).
  • Free space is checked first, with 20 MB to spare.
  • After the first chunk it asks the redirected URL directly, which saves a hop per chunk. On errors it goes back to the feed's URL, since redirect targets are often signed and short-lived. It retries 3 times, then stops; SoftRight resumes.
  • An interrupted download, for example when the app is closed, carries on from the file's size the next time Eter starts.
  • One download at a time, while Eter is open (in front or in the background), with a CPU wake lock.
  • A server that ignores Range requests can still deliver files up to 4 MB in one piece. Bigger ones are refused with "Server does not allow downloads in parts".

Requirements

  • Nokia 8110 4G (or another KaiOS 2.5 phone) with root adb. Sideloading writes to /data/local/webapps and the permissions database.
  • adb, Python 3, Node 18+ (tests only), zip

Build and install

npm test                  # unit tests
npm run build             # -> dist/application.zip (+ icons)
npm run install-phone     # push, register, grant permissions, restart the phone UI
npm run uninstall-phone   # remove it again

install.py reads the app id and type from app/manifest.webapp. It backs up webapps.json and permissions.sqlite on the phone (*.bak-<timestamp>) before changing them. Then it restarts b2g, which reloads the phone UI in about 20-30 seconds.

Why the installer writes permissions itself

Declaring a permission in manifest.webapp grants nothing on its own. Gecko normally writes grants into /data/local/permissions.sqlite at install time, and a hand-registered app skips that step. So the script inserts the rows while b2g is stopped. Eter needs:

  • audio-channel-content: background playback
  • systemXHR: podcast feeds and downloads from any host
  • device-storage:sdcard with readwrite access: downloaded episodes. Gecko stores this as three rows, device-storage:sdcard-read, -write and -create, which is how the phone's own apps have it. install.py expands device-storage access levels this way and still refuses other access-level permissions rather than guess at them.

In-app volume scales within the phone's system volume, so 100% in Eter is as loud as the system volume allows. Set the system volume high once and adjust in the app.

Project layout

app/
  manifest.webapp
  index.html
  style/app.css
  js/model.js      pure: favourites, list rows, selection, retry timing, volume
  js/stations.js   the station list
  js/feed.js       pure: RSS feeds, iTunes chart/search answers, episode ids, time/size text
  js/library.js    pure: followed shows, listening progress
  js/net.js        XHR (mozSystem) for text, JSON and byte ranges
  js/downloads.js  chunked downloads to DeviceStorage (storage and network injected, so it's tested)
  js/poddata.js    feeds, chart and search, with caching
  js/player.js     <audio> on the content channel, wake lock, reconnect, pause/seek/speed for episodes
  js/ui.js         rendering shared by all screens
  js/radio.js      the radio screen
  js/podcasts.js   the podcast screens
  js/main.js       start screen, now bar, volume, keys
  icons/           generated by scripts/make_icons.py
scripts/           build, icons, install, uninstall
tests/             node --test; podcast tests use real feeds and iTunes answers in tests/fixtures/

All app code is ES5 (no let/const, arrow functions or async), because the phone runs Gecko 48.

Known limits

  • No "now playing" song titles yet. NRK publishes them, so that's the natural next feature.
  • Radio streams use data: a 128 kbit/s stream is about 58 MB per hour.
  • Podcasts are audio only. Video episodes are skipped.
  • Downloads run while Eter is open. Closing the app pauses them until it is opened again.
  • No episode descriptions or show notes, to keep the 240x320 screen for the list.
  • NRK's own podcast feeds list only their latest few episodes; the NRK Radio app has the full archive.

License

MIT

About

Norwegian internet radio (NRK, P4, Radio Rock, ...) and podcasts with offline downloads, for the Nokia 8110 4G on KaiOS / GerdaOS

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages