Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2171f95
Fixed: Run search inline to prevent Kodi race condition
oliv3r Feb 23, 2026
91c0536
Fixed: Use Info notification for empty folder lists
oliv3r Feb 24, 2026
487d7fa
Fixed: Preserve insertion order for pinned and live items
oliv3r Feb 23, 2026
ee9fd9a
Fixed: Skip DRM warning when Widevine playback is available
oliv3r Feb 21, 2026
d0eed31
Fixed: Missing test case for PATCH
oliv3r Feb 24, 2026
50becca
Refactored: Flatten HTTP method dispatch in urihandler
oliv3r Feb 24, 2026
914b8b7
Added: Missing DELETE method to urihandler
oliv3r Feb 24, 2026
094cba4
Added: Profile-scoped search history in SearchAction
oliv3r Feb 22, 2026
c1f71cc
Added: DeviceAuthDialog for OAuth2 device flow
oliv3r Mar 4, 2026
ece40fb
Added: NLZIET OAuth2 authentication with headless login and device flow.
oliv3r Feb 2, 2026
e701ff1
Added: NLZIET channel with OAuth2 authentication and profile selection
oliv3r Feb 19, 2026
635a7f8
Added: NLZIET live TV, VOD categories, series browsing, and search
oliv3r Feb 20, 2026
5b9d96e
Added: Episode shortcut items on series detail page
oliv3r Feb 22, 2026
74117f8
Added: NLZIET IPTV Manager integration for live TV and EPG
oliv3r Feb 21, 2026
cf6fed9
Added: Up Next (service.upnext) integration for NLZIET episodes
Mar 1, 2026
5411fce
todo: Added: NLZIET channel with OAuth2 authentication and profile se…
oliv3r Mar 4, 2026
35738f2
Added: NLZIET localization stubs for Dutch (nl_nl)
oliv3r Feb 21, 2026
b67cad2
Added: NLZIET localization stubs for American English (en_us)
oliv3r Feb 21, 2026
0507dd0
Added: NLZIET localization stubs for German (de_de)
oliv3r Feb 21, 2026
deae644
Test: add live/mocked boundary detection tests from HAR data
Mar 2, 2026
492fcfc
Feat: add NLZIET channel settings to settings.xml
Mar 2, 2026
2cf9016
Feat: Progressive EPG description/genre enrichment via 30s queue drain
Mar 3, 2026
144ca1d
Improve: appconfig cache + isAppBlocked guard + EPG progloc cache + a…
Mar 3, 2026
53ff362
Fix: relay EPG refresh signal from retroservice.py
Mar 3, 2026
d0e1d52
Add: nlziet_epg_subscribed_only setting to filter unsubscribed channels
Mar 3, 2026
d05ec9d
Improve: debug logging in EPG/IPTV pipeline + fix epg_enrichment.py d…
Mar 4, 2026
4e56153
Fix: move large EPG caches to files, remove queue persistence
Mar 4, 2026
a3f78a9
NLZIET: watch-ahead (vooruitkijken) EPG feature
Mar 4, 2026
ad8786b
IPTV Manager: isolate per-channel errors in streams/EPG
Mar 4, 2026
451bed3
NLZIET: genre mapping for pvr.iptvsimple
Mar 4, 2026
3624fb8
Fix: catch network errors in fetch_and_cache to prevent empty EPG
Mar 4, 2026
fadf4cf
NLZIET: use manifest_config live_offset for |< / >| live seek
Mar 4, 2026
21d63e1
NLZIET: server time reference + per-channel genre XML
Mar 4, 2026
31a3e29
retroservice: merge per-channel genres + configure pvr.iptvsimple ins…
Mar 4, 2026
5d53511
Fix: enable catchup in pvr.iptvsimple instance for watch-ahead
Mar 4, 2026
e11f913
Fix: empty EPG recovery + server time sanity guard
Mar 4, 2026
0855a2e
Fix: watch-ahead incorrectly excluded when is_replay is also True
Mar 4, 2026
35dcc8e
Refactor: OAuth2 token refresh — instance-var caching + heartbeat-dri…
oliv3r Mar 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions addon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<requires>
<import addon="xbmc.python" version="3.0.0" />
<import addon="script.module.qrcode" version="7.4.2" optional="true" />
<import addon="script.module.requests" version="2.18.0" />
<import addon="script.module.pytz" version="2014.2" />
<import addon="inputstream.adaptive" version="2.0.19" />
Expand Down
117 changes: 117 additions & 0 deletions channels/channel.nlziet/nlziet/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# SPDX-License-Identifier: GPL-3.0-or-later
"""NLZIET API endpoint contracts.

All API contracts in one place so changes to versioning or paths are
easy to track. Constants are grouped by API version and sorted
alphabetically within each group.

Naming convention
-----------------
API_V{n}_RESOURCE – endpoint template (the contract)
API_V{n}_RESOURCE_PREFIX – parser match pattern (prefix-match)

The leading-underscore ``_API_BASE_URL`` is an internal building block;
external code should import the versioned ``API_V*_`` constants instead.
"""

_API_BASE_URL = "https://api.nlziet.nl"

# ── v7 ────────────────────────────────────────────────────────────────
API_V7_APPCONFIG = f"{_API_BASE_URL}/v7/appconfig?os=web&origin=app"
API_V7_CONTINUE_WATCHING = f"{_API_BASE_URL}/v7/continueWatching"
API_V7_CURRENT_TIME = f"{_API_BASE_URL}/v7/currenttime"

# ── v8 ────────────────────────────────────────────────────────────────
API_V8_PROFILE = f"{_API_BASE_URL}/v8/profile"
API_V8_RECOMMEND = f"{_API_BASE_URL}/v8/recommend/"
API_V8_SERIES = f"{_API_BASE_URL}/v8/series/{{}}"
API_V8_SERIES_PREFIX = f"{_API_BASE_URL}/v8/series/"
API_V8_TRACKED_SERIES = f"{_API_BASE_URL}/v8/trackedseries"

# ── v9 ────────────────────────────────────────────────────────────────
API_V9_CONTINUE_WATCHING = f"{_API_BASE_URL}/v9/continueWatching"

API_V9_EPG = f"{_API_BASE_URL}/v9/epg"
API_V9_EPG_ITEM_DETAIL = f"{_API_BASE_URL}/v9/item/detail/{{}}/{{}}"
API_V9_EPG_LIVE_CHANNEL = f"{_API_BASE_URL}/v9/epg/programlocations/live?channel={{}}"
API_V9_EPG_DATE = f"{_API_BASE_URL}/v9/epg/programlocations?date={{}}"
API_V9_EPG_LIVE = f"{_API_BASE_URL}/v9/epg/programlocations/live"

API_V9_PLACEMENT_EXPLORE_PREFIX = f"{_API_BASE_URL}/v9/placement/rows/explore-"
API_V9_PLACEMENT = f"{_API_BASE_URL}/v9/placement/rows/{{}}"

API_V9_RECOMMEND_WITH = f"{_API_BASE_URL}/v9/recommend/with"
API_V9_RECOMMEND_FILTERED = f"{_API_BASE_URL}/v9/recommend/filtered"

API_V9_SEARCH = (
f"{_API_BASE_URL}/v9/search"
"?searchTerm=%s"
"&limit=100"
"&offset=0"
"&contentType=Movie"
"&contentType=Series"
)
API_V9_SEARCH_PREFIX = f"{_API_BASE_URL}/v9/search?"

API_V9_SEASON_ALL_EPISODES = (
f"{_API_BASE_URL}/v9/series/{{}}/episodes"
"?seasonId={}"
"&limit=400"
)
API_V9_SERIES_EPISODES = (
f"{_API_BASE_URL}/v9/series/{{}}/episodes"
"?limit=100"
"&offset=0"
)
API_V9_SERIES_PLAY = f"{_API_BASE_URL}/v9/series/{{}}/play"
API_V9_SERIES_PREFIX = f"{_API_BASE_URL}/v9/series/"
API_V9_SERIES_SEASON_EPISODES = (
f"{_API_BASE_URL}/v9/series/{{}}/episodes"
"?seasonId={}"
"&limit=100"
"&offset=0"
)

API_V9_STREAM_HANDSHAKE = f"{_API_BASE_URL}/v9/stream/handshake"
API_V9_LIVE_HANDSHAKE = (
f"{_API_BASE_URL}/v9/stream/handshake"
"?context=Live"
"&channel={}"
"&drmType=Widevine"
"&sourceType=Dash"
"&playerName=BitmovinWeb"
"&offsetType=Live"
)
API_V9_VOD_HANDSHAKE = (
f"{_API_BASE_URL}/v9/stream/handshake"
"?context=OnDemand"
"&id={}"
"&drmType=Widevine"
"&sourceType=Dash"
"&playerName=BitmovinWeb"
)
API_V9_CATCHUP_PREFIX = f"{_API_BASE_URL}/v9/stream/handshake?context=Epg"
API_V9_CATCHUP_HANDSHAKE = (
API_V9_CATCHUP_PREFIX
+ "&channel={}"
+ "&id={}"
+ "&preferredAssetId={}"
+ "&drmType=Widevine"
+ "&sourceType=Dash"
+ "&playerName=BitmovinWeb"
)

API_V9_TRACKED_SERIES = f"{_API_BASE_URL}/v9/trackedseries"
API_V9_WATCH_IN_ADVANCE = f"{_API_BASE_URL}/v9/watchinadvance"

# ── appconfig cache (stored in LocalSettings) ─────────────────────────
APPCONFIG_CACHE_KEY = "nlziet_appconfig"
APPCONFIG_CACHE_TTL = 300 # seconds (matches server epgCacheTime default)

# ── EPG enrichment cache keys (stored in LocalSettings) ───────────────
EPG_DETAIL_CACHE_KEY = "nlziet_epg_detail_cache"
EPG_BACKOFF_CYCLES_KEY = "nlziet_epg_backoff_cycles"
EPG_ENRICH_BATCH_SIZE = 10
EPG_CACHE_TTL_DAYS = 3
EPG_PROGLOC_CACHE_TTL = 1800 # seconds (30 min; programme schedules change slowly)
EPG_SIGNAL_FILE_NAME = "nlziet_epg_signal_at" # plain file in addon-data dir
61 changes: 61 additions & 0 deletions channels/channel.nlziet/nlziet/chn_nlziet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"channels": [
{
"guid": "89E7B29E-6356-4276-A435-5FA915377C2C",
"name": "NLZIET",
"description": {
"en": "Watch online TV the way you want.",
"nl": "Online tv kijken zoals jij dat wilt."
},
"icon": "nlzieticon.png",
"category": "National",
"sortorder": 2,
"language": "nl",
"hasIptv": true,
"fanart": "nlzietfanart.jpg",
"poster": "nlzietposter.png"
}
],
"settings": [
{
"order": 1,
"value": "label=\"30610\" type=\"action\" action=\"RunScript(plugin.video.retrospect, 0, ?channel=channel.nlziet.nlziet&amp;action=execute&amp;command=setup_device)\" option=\"close\"",
"id": "nlziet_device_setup"
},
{
"order": 2,
"value": "type=\"text\" label=\"30035\" default=\"\"",
"id": "nlziet_username"
},
{
"order": 3,
"value": "default=\"\"",
"id": "nlziet_password"
},
{
"order": 4,
"value": "label=\"30093\" type=\"action\" action=\"RunScript(plugin.video.retrospect, 0, ?channel=channel.nlziet.nlziet&amp;action=encryptsetting&amp;settingid=channel_89E7B29E-6356-4276-A435-5FA915377C2C_nlziet_password&amp;settingname=NLZIET&amp;tabfocus=102)\" option=\"close\"",
"id": "nlziet_password_set"
},
{
"order": 5,
"value": "label=\"30611\" type=\"action\" action=\"RunScript(plugin.video.retrospect, 0, ?channel=channel.nlziet.nlziet&amp;action=execute&amp;command=log_off)\" option=\"close\"",
"id": "nlziet_log_off"
},
{
"order": 6,
"value": "label=\"30625\" type=\"action\" action=\"RunScript(plugin.video.retrospect, 0, ?channel=channel.nlziet.nlziet&amp;action=execute&amp;command=select_profile)\" option=\"close\"",
"id": "nlziet_select_profile"
},
{
"order": 7,
"value": "label=\"30628\" type=\"slider\" option=\"int\" range=\"-120,5,120\" default=\"0\"",
"id": "nlziet_live_start_offset"
},
{
"order": 8,
"value": "label=\"30630\" type=\"bool\" default=\"true\"",
"id": "nlziet_epg_subscribed_only"
}
]
}
Loading
Loading