No description
  • Python 93.9%
  • Nix 4.4%
  • Just 0.9%
  • Shell 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-05 15:34:38 +02:00
resources Point metadata URLs at git.lundsaunet.no 2026-08-05 15:34:38 +02:00
tests initial commit: working addon 2026-08-05 15:26:27 +02:00
tools initial commit: working addon 2026-08-05 15:26:27 +02:00
.gitignore initial commit: working addon 2026-08-05 15:26:27 +02:00
addon.xml Point metadata URLs at git.lundsaunet.no 2026-08-05 15:34:38 +02:00
changelog.txt initial commit: working addon 2026-08-05 15:26:27 +02:00
default.nix use flake 2026-08-05 15:30:49 +02:00
flake.lock initial commit: working addon 2026-08-05 15:26:27 +02:00
flake.nix use flake 2026-08-05 15:30:49 +02:00
justfile initial commit: working addon 2026-08-05 15:26:27 +02:00
LICENSE initial commit: working addon 2026-08-05 15:26:27 +02:00
main.py initial commit: working addon 2026-08-05 15:26:27 +02:00
package.nix Point metadata URLs at git.lundsaunet.no 2026-08-05 15:34:38 +02:00
README.md initial commit: working addon 2026-08-05 15:26:27 +02:00
shell.nix initial commit: working addon 2026-08-05 15:26:27 +02:00

NRK TV for Kodi

A Kodi addon for NRK TV, built on the same API that powers the NRK website.

The goal is to make NRK's catalogue browsable. Existing addons expose NRK as a tree of menus, which is fine if you already know what you want to watch but useless for finding out what is actually available. This addon gives you the real front page, the editorial sections, and — most importantly — a complete AZ overview of every series NRK currently offers, rendered as a poster wall with plots, artwork and cast information.

At the time of writing that AZ contains 1663 series, built in about 2.5 seconds.

Features

  • Complete series overview. "Alle serier AÅ" across the whole catalogue, and a per-category equivalent on every genre page. De-duplicated and sorted using Norwegian collation (Æ/Ø/Å last, but Á/Š filed under A/S so Sami titles do not get exiled to the end).
  • NRK's own front page and editorial sections — "Mest sett", "Krim", "Klassiske NRK-serier" and so on.
  • Proper Kodi metadata. tvshow/season/episode media types, plots, posters, fanart, clearlogos, duration, production year, age rating, premiere date, and cast/director/writer. This is what makes skins render poster walls and lets Kodi track watched state.
  • Live TV with the current programme shown per channel.
  • Search, with persistent history (typing on a remote is miserable).
  • Adaptive streaming through inputstream.adaptive, with an optional resolution cap for low-powered devices.
  • Norwegian subtitles, with a choice of regular or hard-of-hearing.

Requirements

  • Kodi 19 (Matrix) or newer. Tested against Kodi 21 (Omega).
  • script.module.requests, script.module.routing, script.module.inputstreamhelper — all in the official Kodi repository.
  • inputstream.adaptive (recommended, not strictly required).

NRK geo-restricts most content to Norway.


Installation

On NixOS

The addon ships as a Nix package, which is the only sane route on NixOS since Kodi's addon directory is read-only in the store.

With flakes, add the input:

inputs.nrk-plugin.url = "github:blund/nrk-plugin";
# or, while developing locally:
# inputs.nrk-plugin.url = "path:/home/blund/prosjekt/nrk2";

then bundle it into your Kodi package. With the apps.kodi module in rpi-cluster:

{ inputs, pkgs, ... }:
{
  apps.kodi.enable = true;
  apps.kodi.package = pkgs.kodi-gbm.withPackages (kodiPkgs: [
    inputs.nrk-plugin.packages.${pkgs.system}.nrk-plugin
  ]);
}

withPackages pulls in requests, routing, inputstreamhelper and inputstream-adaptive automatically — they are declared as propagated inputs.

Without flakes, using callPackage:

{ pkgs, ... }:
let
  nrk-plugin = pkgs.callPackage (fetchGit {
    url = "https://github.com/blund/nrk-plugin";
    ref = "main";
  }) { };
in
{
  apps.kodi.package = pkgs.kodi-gbm.withPackages (_: [ nrk-plugin ]);
}

Then rebuild and restart Kodi:

sudo nixos-rebuild switch --flake .#<host>
sudo systemctl restart kodi

Note on the Raspberry Pi. pkgs.rpi.kodi-gbm (the nixos-raspberrypi tuned build) is not in the binary cache and will build from source. Plain pkgs.kodi-gbm substitutes fine and is what apps.kodi defaults to. On a Pi, also consider setting the addon's Maximum resolution to 1080p.

On any other Kodi (LibreELEC, Windows, macOS, generic Linux)

Build a zip and install it from the Kodi UI:

just package        # or: ./tools/package.sh

This writes dist/plugin.video.nrk-plugin-<version>.zip. Then, in Kodi:

Settings → Add-ons → Install from zip file, and point it at the zip. You will need "Unknown sources" enabled under Settings → System → Add-ons.

Alternatively copy the addon directory straight into your Kodi profile:

cp -r . ~/.kodi/addons/plugin.video.nrk-plugin

and restart Kodi. Install script.module.requests, script.module.routing and script.module.inputstreamhelper from the official repository first.


Settings

Setting Default Notes
Enable subtitles on
Subtitle type Regular Regular / hard-of-hearing (SDH) / all
Use InputStream Adaptive on Better seeking and adaptive bitrate
Maximum resolution Unlimited Cap this on a Pi or similar
Open the NRK front page on start off Skip the main menu
Skip season list for single season series on
Hide unavailable programmes off Hides expired and not-yet-published items
Prefer poster artwork on Portrait posters instead of landscape stills
Cache API responses on Strongly recommended
Cache lifetime 60 min

Development

nix-shell              # python + requests + pytest
pytest                 # 150 tests, no network needed

The addon is layered so that everything except the two Kodi-facing modules can be imported and tested outside Kodi:

Module Responsibility Imports Kodi?
api.py HTTP, TTL disk cache, parallel fetch no
models.py psapi JSON → Item / Section no
browse.py aggregation, de-duplication, AZ collation no
playback.py manifest → Stream, subtitle selection no
history.py search history no
kodi.py settings, logging, ListItem construction yes
addon.py routes yes

tests/stubs/ contains stand-ins for xbmc, xbmcgui, xbmcplugin, xbmcaddon, xbmcvfs, routing and inputstreamhelper, so the full route layer is exercised in CI without a device.

Tools

python tools/probe.py az                # build the A-Z against the live API
python tools/probe.py page dokumentar   # inspect one page's sections
python tools/probe.py series skam       # seasons + episodes
python tools/smoke.py                   # walk every route against the live API
python tools/stress.py 80               # parse 80 random real series, report problems
python tools/record_fixtures.py         # refresh tests/fixtures from live

tools/smoke.py and tools/stress.py are the ones to run after NRK changes something: the fixture-based tests will keep passing against stale recordings, but these hit the live service.

Notes on the NRK API

  • The catalogue lives under /tv/pages (categories) and /tv/pages/frontpage. Each page holds sections, each section holds plugs with targetType of series, episode, standaloneProgram, channel, liveChannelProgram or page.
  • /tv/catalog/series/<id> returns every season and every episode of a sequential series in one response. Do not fetch per episode.
  • Series come in three shapes, and they behave differently:
    • sequential — numbered seasons, episodes embedded.
    • standard — seasons are years, episodes not embedded, so each season needs its own request. Årsrevyen has 47 of them.
    • news — "seasons" are calendar months (202608), which is useless for browsing; use /instalments instead.
  • Playback manifests are tokenised and short-lived. Never cache them, and only fetch them when the user actually presses play.
  • Image lists come in three different shapes depending on endpoint (uri/width, imageUrl/pixelWidth, url/width).

Licence

GPL-3.0-or-later. Not affiliated with or endorsed by NRK.