UniPlayer Docs
Docs / Specs / Archive & Catch-up: M3U and Xtream specification
Specs · Formats

Archive & Catch-up: M3U and Xtream specification

The source-of-truth spec for IPTV providers — how to declare catch-up/archive in M3U and Xtream Codes playlists so it plays correctly in UniPlayer.

14 min read / Updated June 2026
TL;DR

IPTV catch-up (also called archive, timeshift or DVR) lets a player rebuild a past-broadcast URL from a live channel URL plus a UTC start time. In an M3U playlist it is declared with the catchup, catchup-source and catchup-days attributes on each #EXTINF line; UniPlayer supports the default, append, shift and Flussonic modes, plus Xtream Codes tv_archive auto-detection. UniPlayer is a player like VLC — the provider supplies the playlist and the archive window; UniPlayer only builds the playback URL from the EPG programme's start time.

What this document is

This is the provider-facing reference for declaring catch-up TV (a.k.a. archive, timeshift, DVR, рестарт/архив) in the playlists your subscribers load into UniPlayer.

UniPlayer is a player, not a content service — the same neutral-tool model as VLC. Your server holds the streams and the recorded archive; UniPlayer reads your playlist, matches it to an EPG, and — when a user scrubs back in the guide — rebuilds the archive playback URL from the rules below. If your playlist declares catch-up the way this spec describes, every UniPlayer client (iOS, iPadOS, Apple TV) plays your archive without any per-provider integration on our side.

In short. Put the right catchup mode and (where needed) a catchup-source template on each #EXTINF line, advertise how many days you keep with catchup-days, and make sure your origin accepts a UTC Unix start time. That’s the whole contract.


1. The catch-up model

Catch-up playback is always the same three-part operation:

PartWho supplies itNotes
Live URLYour playlist (#EXTINF → URL line)The normal live channel address.
Start timeUniPlayer, from the EPGThe selected programme’s start, as a UTC Unix timestamp (seconds).
Duration / windowYour playlist (catchup-days) + EPGHow far back the archive reaches; programme length.

UniPlayer derives the start offset as programme_start − now (a negative number of seconds, “into the past”), converts it to an absolute UTC Unix timestamp, and injects it into your live URL according to the channel’s catchup mode. There is no separate “archive playlist” — the archive URL is generated from the live URL.

Terminology (all interchangeable in the wild): catch-up = archive = timeshift = DVR = catchup TV = rewind. UniPlayer treats them as one feature.


2. M3U attributes UniPlayer reads

Declare catch-up with attributes on the #EXTINF line. UniPlayer parses any key="value" pair; the catch-up–relevant keys are:

AttributeRequiredMeaning
catchupYes¹The catch-up mode (see §3). Also accepted as catchup-type.
catchup-sourceMode-dependentURL template or query string with placeholders (see §4). Required for default/append when the URL can’t be derived automatically.
catchup-daysRecommendedInteger — how many past days of archive you keep. Drives how far back the guide lets users scrub.
timeshiftOptionalLegacy SIPTV signal. Its presence makes UniPlayer treat the channel as shift mode; its value is also read as a days fallback.
tvg-recOptionalLegacy “recording days” — read as a catchup-days fallback (>0 ⇒ archive available).
catchup-timeOptionalWindow expressed in seconds (converted to days internally). Lowest-priority days fallback.

¹ If you omit catchup but the stream URL shape clearly indicates an archive-capable origin (e.g. it contains /archive-, /rewind-, or timeshift), UniPlayer infers the mode. Explicit is always better — don’t rely on inference.

Days resolution order. UniPlayer reads the window from the first present of: catchup-daystimeshifttvg-reccatchup-time÷86400. If none is present but the channel is otherwise detected as catch-up–capable, UniPlayer assumes a 30-day window. Always set catchup-days so users see the real depth.


3. Catch-up modes (the catchup value)

UniPlayer normalises the catchup / catchup-type value to one of the modes below. Aliases in the right column are all accepted and folded to the canonical mode.

Canonical modeAccepted aliasesUse when…
defaultdefaultYou give a full archive URL template in catchup-source.
appendappendYou give a query-string fragment in catchup-source to append to the live URL.
shiftshift, timeshiftYour origin accepts the SIPTV utc/lutc query parameters.
flussonicflussonic, fs, flussonic-hls, flussonic-tsYour origin is Flussonic (or Flussonic-compatible). UniPlayer builds the URL — no catchup-source needed.
xstream-1xstream, xtream, xcXtream Codes archive (usually auto-detected — see §6).
vodvodVideo-on-demand–style catch-up entries.

3.1 default — full URL template

catchup-source is the complete archive URL, with placeholders UniPlayer substitutes:

#EXTINF:-1 catchup="default" catchup-days="7" catchup-source="https://origin.example/ch12/video-${start}-${duration}.m3u8",Channel 12
https://origin.example/ch12/index.m3u8

3.2 append — query fragment

catchup-source is just the part to append to the live URL. Start it with ? (or & if your live URL already has a query string):

#EXTINF:-1 catchup="append" catchup-days="7" catchup-source="?utc=${start}&lutc=now",News 24
https://origin.example/news/index.m3u8?token=abc

3.3 shift — SIPTV utc/lutc

No catchup-source needed. UniPlayer appends utc=<start>&lutc=<now> to the live URL (using & when the URL already contains ?):

#EXTINF:-1 catchup="shift" catchup-days="5",Sports 1
https://origin.example/sports1/index.m3u8

→ archive request becomes …/sports1/index.m3u8?utc=1717400000&lutc=1717420000. If the live URL’s last path segment is mpegts, UniPlayer instead rewrites it to timeshift_abs-<start>.ts (see §5).

3.4 flussonic — auto-built from the live URL

No catchup-source needed — set the mode and UniPlayer rewrites the live URL using Flussonic’s own timeshift convention (see §5 for the exact transform):

#EXTINF:-1 catchup="flussonic" catchup-days="14",Movie Channel
https://origin.example/movie/index.m3u8

3.5 xstream-1 / xc — Xtream Codes

Normally you don’t hand-write this — when UniPlayer ingests an Xtream Codes playlist it sets this automatically from tv_archive/tv_archive_duration (§6). The aliases exist so M3U exports from Xtream panels are recognised too.


4. URL template placeholders

When you supply a catchup-source (modes default / append), UniPlayer substitutes these tokens. All times are UTC Unix epoch seconds.

TokenSubstituted withNotes
${start}Programme start, absolute UTC Unix secondsThe primary token. Use this for the archive start time.
${duration}Programme duration in secondsRecognised inside the Flussonic-style literal video-${start}-${duration} (see below).
utc=<n> / lutc=<n>Injected by shift modeutc = start, lutc = now. Not template tokens — emitted automatically in shift.

Flussonic literal shortcut. If your catchup-source (or live URL) contains the literal segment video-${start}-${duration}, UniPlayer replaces that whole segment with Flussonic’s relative form mono-timeshift_rel<seconds> (negative seconds into the past). This lets a single template serve both HLS and Flussonic origins.

Compatibility note (Kodi / {utc} convention). The wider IPTV ecosystem (Kodi’s PVR IPTV Simple Client) also defines {utc}, {lutc}, {utcend}, {duration}, {offset}, the strftime tokens {Y}{m}{d}{H}{M}{S}, and {catchup-id}. UniPlayer’s reliably-supported set is the ${start}/${duration} tokens plus the shift (utc/lutc) and flussonic auto-modes. For maximum compatibility across players and guaranteed playback in UniPlayer, prefer catchup="flussonic" for Flussonic origins and catchup="shift" for utc/lutc origins — these need no template and can’t be mistyped.


5. Flussonic origins (exact transform)

For catchup="flussonic" (and fs / flussonic-hls / flussonic-ts), UniPlayer rewrites the live URL into Flussonic’s timeshift URL. Two cases:

Live URL ends withArchive URL UniPlayer buildsForm
…/mpegts…/timeshift_abs-<startUnixUTC>.tsAbsolute HTTP-MPEG-TS timeshift
…/index.m3u8, …/mono.m3u8, …/video.m3u8 (HLS)the index / mono / video segment → timeshift_rel<seconds>Relative HLS timeshift (negative seconds)

Examples:

Live:    https://origin.example/ch/mpegts
Archive: https://origin.example/ch/timeshift_abs-1717400000.ts

Live:    https://origin.example/ch/index.m3u8
Archive: https://origin.example/ch/timeshift_rel-3600.m3u8     (1 hour back)

Your Flussonic DVR must therefore accept both the absolute (timeshift_abs-<utc>.ts) and relative (timeshift_rel<-seconds>.m3u8) forms. These are Flussonic’s native DVR endpoints; no custom configuration on your side beyond enabling DVR for the stream.


6. Xtream Codes archive

When a user adds an Xtream Codes account, UniPlayer reads the live streams via the panel API (player_api.php?action=get_live_streams). Two fields drive catch-up per stream:

FieldMeaning
tv_archive1 ⇒ catch-up is enabled for this channel; 0 ⇒ none.
tv_archive_durationInteger days of archive retained (e.g. 7).

UniPlayer auto-maps these into the catch-up model: tv_archive=1 marks the channel as archive (internal mode xstream-1) and tv_archive_duration becomes the catchup-days window. The playlist as a whole is tagged with an archive_type so the UI advertises catch-up.

Xtream timeshift URL. The Xtream-native archive endpoint format is:

http://host:port/timeshift/USERNAME/PASSWORD/DURATION/START/STREAM_ID.EXT
# e.g.
http://host:port/timeshift/user/pass/60/2026-06-03:14-30/1234.ts
  • DURATION — minutes of the requested segment.
  • STARTYYYY-MM-DD:HH-MM in the server’s archive timezone.
  • EXTts or m3u8.

Provider recommendation. Xtream catch-up is signalled through tv_archive / tv_archive_duration, and that’s what UniPlayer reads for the window. For the most robust archive playback today, panels that can also emit M3U exports should include explicit catchup="shift" (utc/lutc) or catchup="flussonic" attributes on archive channels, since those modes are unambiguous and origin-agnostic. If your panel only exposes the Xtream API, ensure tv_archive_duration is accurate so the guide depth is correct.


7. Time, timestamps & timezones

These rules are non-negotiable for archive to line up with the guide:

  • Start time is UTC Unix epoch seconds. UniPlayer substitutes ${start} / utc / timeshift_abs-… with an integer UTC timestamp. Your origin must interpret it as UTC.
  • EPG must be UTC-correct. UniPlayer derives the archive start from the EPG programme’s start time. If your XMLTV programme times drift from the actual broadcast, the archive will start at the wrong moment. Publish EPG times with correct timezone offsets (UniPlayer normalises everything to UTC on ingest).
  • Relative offsets are negative. Flussonic timeshift_rel values are negative seconds (e.g. -3600 = one hour ago). UniPlayer computes them from now.
  • No client-side correction offset. UniPlayer does not apply a catchup-correction shift. If your archive needs a fixed hour correction, bake it into your origin or EPG — don’t rely on a per-channel correction attribute.
  • Minimum offset. Requests less than ~1 second into the past fall back to the live URL.

8. Worked examples

A complete, mixed playlist a provider can model theirs on:

#EXTM3U url-tvg="https://origin.example/epg.xml.gz"

# Flussonic origin — simplest, no template needed
#EXTINF:-1 tvg-id="ch.movie" tvg-logo="https://origin.example/logo/movie.png" catchup="flussonic" catchup-days="14",Movie Channel
https://origin.example/movie/index.m3u8

# SIPTV utc/lutc origin
#EXTINF:-1 tvg-id="ch.sports1" catchup="shift" catchup-days="7",Sports 1
https://origin.example/sports1/index.m3u8?token=abc

# Full template (default mode)
#EXTINF:-1 tvg-id="ch.news" catchup="default" catchup-days="5" catchup-source="https://origin.example/news/video-${start}-${duration}.m3u8",News 24
https://origin.example/news/index.m3u8

# Append a query fragment
#EXTINF:-1 tvg-id="ch.kids" catchup="append" catchup-days="3" catchup-source="?utc=${start}",Kids TV
https://origin.example/kids/index.m3u8

# HTTP-MPEG-TS Flussonic (absolute timeshift)
#EXTINF:-1 tvg-id="ch.doc" catchup="flussonic" catchup-days="30",Docs HD
https://origin.example/doc/mpegts

9. Provider checklist

Before you ship a playlist, verify:

  • Every archive channel has a catchup (or catchup-type) value from §3.
  • catchup-days is set and matches your real retention.
  • default/append channels include a catchup-source with ${start} (and ${duration} if needed).
  • Flussonic channels expose both timeshift_abs-<utc>.ts and timeshift_rel<-sec>.m3u8.
  • Your origin accepts a UTC Unix start time.
  • tvg-id is present and maps to an EPG channel (catch-up is selected from the guide — no EPG, no archive UI).
  • EPG programme times are timezone-correct.
  • Xtream panels return accurate tv_archive / tv_archive_duration.

10. Common mistakes

SymptomLikely cause
Archive button never appearsNo tvg-id / no EPG match, or no catchup/catchup-days and URL shape isn’t inferable.
Guide only scrolls back a few dayscatchup-days missing → 30-day assumption, or set lower than real retention.
Archive plays the wrong momentEPG programme times in the wrong timezone, or origin treats ${start} as local time, not UTC.
Template not substitutedUsed a Kodi-only token ({utc}, {Y}{m}{d}…) instead of ${start} / shift / flussonic — switch to a supported mode (§4).
Flussonic archive 404sDVR not enabled for the stream, or origin doesn’t accept timeshift_rel / timeshift_abs.
Xtream archive depth wrongtv_archive_duration inaccurate in the panel.

  • M3U / M3U8 playlist format — base attributes, encoding, and structure.
  • XMLTV / EPG — how programme times feed the archive start.
  • UniPlayer is a neutral player; this spec describes how your playlist must be structured, not what content it carries.