Guides .md

Building a Kodi integration

Connect a Kodi addon running on a TV to FlickList, so playback there updates watch history and feeds a next-episode prompt back into the addon's UI.

1. Get a device code and let the user approve it#

Kodi runs on a screen with no keyboard sign-in, so use the device-code flow instead of a password form. Request a code, show the user_code on screen, and poll until the person approves it from their phone or laptop. The full request-and-poll sequence is in Quickstart. This guide picks up once your addon is holding a bearer token in its settings.

# see /dev/quickstart for the request/poll loop itself
token = run_device_code_login(client_id="fl_kodi_scrobbler")
addon.setSetting("access_token", token)

2. Start tracking playback#

Call this from your player class's onPlayBackStarted callback (and again from onPlayBackResumed, after a seek). Resolve the title to a TMDB ID first, since scrobble targets must carry one.

curl -X POST "https://flicklist.tv/api/v3/scrobble/start" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "media_type": "movie",
    "ids": { "tmdb": 550 },
    "progress": 0.0
  }'

For an episode, send "media_type": "show" (or "tv"), the show's ids block, and season and episode numbers. The full shape is on the Scrobbling page.

3. Keep sending start as your heartbeat#

Kodi doesn't fire a periodic "still playing" event, so start a 30 to 60 second interval timer while the title plays and re-POST start with the current progress each time. start is an upsert, so every call updates the same resume point rather than creating a new one.

4. Pause when the person actually pauses#

Wire this to onPlayBackPaused, not to buffering or seek events. Send it only when playback genuinely stops for the user.

{ "id": null }

If nothing was actively playing that item, pause is a no-op and id comes back null. It never creates a new resume point on its own.

5. Stop at the end of playback#

Call this from onPlayBackStopped and onPlayBackEnded alike, with the final progress value.

{ "watch_status": "watched" }

watch_status tells you the outcome. At 90% progress or more, with enough of the runtime actually played, the item is marked watched. At 90% or more but under that time floor, it's recorded as a preview. Below 90%, the resume point is kept as partial so the person can pick up where they left off.

6. Sync watched state without hammering the API#

Don't refetch full watched history every time the addon's menu opens. Poll GET /v3/sync/last_activities first and compare its per-domain timestamps against what you last cached.

curl -H "Authorization: Bearer $TOKEN" \
  "https://flicklist.tv/api/v3/sync/last_activities"

Only when a domain's timestamp moved forward do you call GET /v3/sync/watched/movies or GET /v3/sync/watched/shows to refresh that part of your local cache. Everything else stays as it was.

7. Surface what's next#

GET /v3/sync/up_next returns the next unwatched episode for each show the person is in the middle of, which is exactly what a "play next" prompt needs once credits roll. Scrobbling a finished episode updates it immediately, so calling it right after stop reflects the episode that just ended. Details, including dropping a show from the list, are on Up Next & change detection.