Skip to content
Michael Sotnikov edited this page Jan 12, 2024 · 4 revisions

General

M3U encoding

Default playlist encoding is UTF-8, but any other encoding can be specified during playlist configuration.

M3U structure

M3U playlist is text file which has header block and channels information. For example:

#EXTM3U url-tvg="http://example.com/xmltv.zip"
#EXTINF:-1 group-title="Music", MTV
http://example.com/channel/01
#EXTINF:-1 group-title="News", Euronews
http://example.com/channel/02

EPG resources

When TVirl installs playlist it process additional EPG resources to fill EPG information. All EPG resources are configured during initial playlist installation. Initial list of EPG resources is loaded from url-tvg attribute from M3U header.

TVirl supports next types of EPG resources:

  • EPG in XmlTv format (archived or plain XML)
  • EPG in JTV format (archived NDX + PDT files)
  • channels logo (archive with image files: PNG/JPG)

EPG resource can be:

  • local (on-device memory, sdcard, attached external disk and so on). Local file is selected using TVirl's picker UI or can be referenced using url with file:// scheme.
  • remote, represented by it's url.

TVirl supports M3U/EPG urls:

  • HTTP(s) (For ex.: https://example.com/xmltv.xml, http://user:pswd@example.com/epg.tar.gz)
  • FTP (For ex.: ftp://user:pswd@ftp.example.com/playlist.m3u)
  • local (For ex.: file:///storage/emulated/0/Download/icons.zip)

Supported archives

Main archive formats supported by TVirl:

  • zip
  • gzip (.gz, .tar.gz)
  • bzip (.bz2)

It's possible to specify archive encoding to read file names properly from it. Default archive encoding is cp866.

⚠️ TVirl does not support: 7z, RAR

M3U header

Header block declares information about playlist itself and additional attributes shared among all channels in it. Header block starts with #EXTM3U tag and ends before first channel (which starts with #EXTINF:).

Global attributes

All global attributes are declared using #EXTM3U tag.

#EXTM3U url-tvg="http://example.com/jtv.zip" tvg-shift=-2 catchup="shift" catchup-days=7

Global attributes TVirl supports:

  • url-tvg
  • tvg-shift
  • catchup, catchup-type, catchup-source, catchup-days, timeshift, tvg-rec

All global attributes (except url-tvg) are added to all channels entries. But if channel entry has same attribute already - TVirl will ignore inherited global value.

Attribute: url-tvg

url-tvg defines coma-separated list of additional resources, which will be loaded with a playlist to fill EPG information.

#EXTM3U url-tvg="http://example.com/xmltv.zip,http://example.com/icons.zip"

Global tags

TVirl supports additional tags declared in M3U header.

#EXTM3U
#EXTVLCOPT:http-user-agent=Restream/5.20408.171030 (mag250, mag250) SmartSDK/1.5.63-rt-25 Qt/4.7.3 API/0.30.0
#EXTINF:-1,CBS
http://example.com/01

Global tags work the same way as global attributes. All values are added to all channels entries.

M3U channels

M3U playlist declares information about channels, their title, logo, catch-up information if supported, media stream url.

#EXTINF:0 tvg-id="493" tvg-logo="http://best-logo.net/images/euronews.png" group-title="NEWS",Euronews
udp://@235.1.1.2:5678

The general structure of channel entry is:

#EXTINF:<duration> <attrib_name1>=<attrib_value1> <attrib_value2>="<attrib_value2>",<channel_title>
<optional_tag>:<value>
<media_url>
  • duration is float number. In most cases it does not make any sense for IPTV live streaming, but it can be used to bypass channel number.
  • attributes are key-value pairs. Attributes names have to be unique, if multiple attributes with same name are declared - last one wins.
  • channel title is title which will be used to represent channel in EPG. It's also used to search matching channel in EPG resources (XmlTv, JTV, logo)
  • media url

Media stream url

TVirl supports transports:

  • udp (natively or through UDP-to-HTTP proxy)
  • rtp (only through UDP-to-HTTP proxy)
  • http(s) with HLS/Dash/SmoothStreaming/HTTP Progressive (MPEG-TS, mkv, mp4, ...) (see ExoPlayer supported formats)

Additional tags

TVirl supports additional tags: #EXTGRP, #EXTVLCOPT, #KODIPROP. All tags declared before first channel are inherited by all channels (see Global tags).

#EXTINF:0,Fox Life
#EXTGRP:MOVIES
http://example.com/fox_life.m3u8

⚠️ While TVirl supports syntax where tags are declared before #EXTINF:

#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha
#KODIPROP:inputstream.adaptive.license_key=http://example.com/license
#EXTINF:-1,Star Plus
http://example.com/Star_Plus.mpd|user-agent="Foo"

This syntax breaks possibility to read tags in header properly. I'm highly erncorouge you to use standard syntax:

#EXTINF:-1,Star Plus
#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha
#KODIPROP:inputstream.adaptive.license_key=http://example.com/license
http://example.com/Star_Plus.mpd|user-agent="Foo"

Channels numbering

TVirl can use custom channels numbering if there is one provided.

Attribute: tvg-chno

#EXTINF:-1 tvg-chno="18",TCM UK
http://example.com/01

#EXTINF:-1 tvg-chno="1.003",MTV
http://example.com/02

Duration as channel number

TVirl can use duration value as channel number. Next channels will have numbers 15 and 16.

#EXTINF:15,TCM UK
http://example.com/01

#EXTINF:16,MTV
http://example.com/02

Grouping

TVirl reads information about channels grouping using different tags and attributes. But while TVirl understands all kinds of category/group names, system with its TV App and TV Input Framework accept canonical program GENRES. TVirl allows to map channels groups/categories to canonical genres during playlist installation.

Tag: EXTGRP

#EXTINF:-1, Best Music
#EXTGRP:MUSIC
http://example.com/best3.m3u8

#EXTINF:-1, Euronews
#EXTGRP:NEWS
http://example.com/news.m3u8

Attribute: group-title

group-title attribute defines group for current and all further channels, till another group-title is declared. In the next example, both channels (Movies 1, Movies 2) share same group: MOVIES.

#EXTINF:-1 group-title="MOVIES", Movies 1
http://example.com/best1.m3u8

#EXTINF:-1,Movies 2
http://example.com/best2.m3u8

#EXTINF:-1 group-title="MUSIC", MTV
http://example.com/music.m3u8

Attribute: groups

groups attribute can declare multiple (using | as separator) groups for a single channel.

#EXTINF:-1 groups="MOVIES|COMEDY", Movies 3
http://example.com/01

Matching M3U channel to EPG

When playlist is installed with EPG resources attached, TVirl performs channel look-up to find how different entities match to channels from a playlist. Here is the list of identities in the order from higher priority to lower:

  • attribute tvg-logo (for logo only).
  • attribute tvg-id
  • attribute tvg-name
  • channel title

When EPG is archive with logo images, TVirl uses file names to compare with identities. Comparing is case-insensitive, where symbol "_" equals to " " (space).

When processing XmlTv TVirl checks identities against channel id and it's display-name's.

=== M3U Playlist:

#EXTINF:-1 tvg-id="LA1.es",la 1 HD
http://example.com/01

=== XmlTv (tvg-id matches id):

<channel id="LA1.es">
  <display-name lang="es">LA 1 ES</display-name>
</channel>

=== XmlTv (title matches display name):

<channel id="132">
  <display-name lang="en">LA 1 HD</display-name>
</channel>

=== zip archive with images:

/LA1.es.png
/la_1_hd.jpg

Logo

Channel logo can be provided using tvg-logo or logo attributes:

#EXTINF:-1 tvg-logo="http://static.example.com/logo/01.png",Paramount Channel
http://example.com/01

#EXTINF:-1 logo="http://static.example.com/logo/02.png",Paramount Comedy
http://example.com/02

Additionally to logo from M3U playlist itself TVirl loads logo from EPG resources:

  • archive with images
  • <icon src="..." /> from XmlTv
<channel id="Telecinco.es">
  <display-name lang="es">Telecinco ES</display-name>
  <icon src="http://static.example.com/es/Telecinco.es.png"/>
</channel>

Custom HTTP headers

TVirl supports custom HTTP headers. If no custom HTTP headers are provided default User-Agent will be used, for example: TVirl/0.5.0.2 (Linux;Android 9) ExoPlayerLib/2.11.6.

Custom HTTP headers with EXTVLCOPT

TVirl supports #EXTVLCOPT tag with options:

  • http-user-agent
  • http-referrer
#EXTINF:-1,Channel 1
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
#EXTVLCOPT:http-referrer=https://example.com
http://example.com/01.m3u8

Custom HTTP headers embedded to media url

It's possible to add arbitary custom headers to media url:

  • headers block starts with |
  • the rest of headers block is similar to query part of urls:
    • TVirl url-decode whole block before parsing it
    • each key-value pair is separated using &
    • each key-value has syntax: <name>=<value>
  • " are trimmed from values if exist
#EXTINF:-1,Ch1
http://example.com/01|User-Agent=VLC

#EXTINF:-1,Ch2
http://example.com/02|X-Forwarded-For=1.1.1.1&User-Agent=Foo%2F3.0+%28compatible%3B+FMSc%2F1.0%29&Referer=%20&Seekable=0

#EXTINF:-1,Ch3
http://example.com/03|Referer=https://youtube.com

Catch-up

TVirl supports different catch-up types. Next attributes are used:

  • catchup, catchup-type with possible values: default|append|shift|flussonic|fs.
  • catchup-source is url or part of url to access catch-up with default or append type.
  • catchup-days, timeshift, tvg-rec with number of days service provides catch-up.

Catch-up: default, append

For default and append catch-up services TVirl uses catchup-source. catchup-source is added to stream url for append type.

#EXTINF: 0 catchup="default" catchup-source="http://example.com/archive/?start=${start}",Ch1
http://example.com/stream1.m3u8

#EXTINF:0 catchup="append" catchup-source="?start=${start}" catchup-days="3",Ch2
http://example.com/stream2.m3u8

TVirl supports next placeholders inside catchup-source:

  • ${timestamp}, {lutc}: current Unix epoch time (seconds since epoch)
  • ${start}, {utc}: program start time as Unix epoch time
  • ${offset}: program offset in seconds (now - start)
  • ${duration}, {duration}: program duration in seconds (program_end - program_start or now - program_start if program is not finished)
  • ${end}, {utcend}: program end time as Unix epoch time
  • {Y}, {m}, {d}, {H}, {M}, {S}: year (YYYY), month (01-12), day (01-31), hour (00-23), minute (00-59), second (00-59) of program start time

DRM

TVirl supports playback of DRM-protected (Widevine, PlayReady, ClearKey) streams. TVirl adopted syntax from KODI InputStream.Adaptive:

  • inputstream.adaptive.license_type = com.widevine.alpha|com.microsoft.playready|org.w3.clearkey|clearkey
  • inputstream.adaptive.license_key =
    • url to retrieve license (custom headers are supported)
    • kid:key for ClearKey. hex (32 base16 chars) or base64url (22 base64 chars).
    • json - full ClearKey license response (e.g. {"keys":[{"kty":"oct","k":"base64key1","kid":"base64key2"}],"type":"temporary"})
#EXTINF:-1,Ch1
#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha
#KODIPROP:inputstream.adaptive.license_key=http://example.com/01.mpd
https://example.com/01.mpd

#EXTINF:-1,Ch2
#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha
#KODIPROP:inputstream.adaptive.license_key=http://example.com/license|User-Agent=Mozilla/5.0 (Windows NT 10.0; WOW64)
https://example.com/02.mpd

#EXTINF:-1, Ch3
#KODIPROP:inputstream.adaptive.license_type=org.w3.clearkey
#KODIPROP:inputstream.adaptive.license_key=nrQFDeRLSAKTLifXUIPiZg:FmY0xnWCPCNaSpRG-tUuTQ
https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p_ClearKey.mpd

#EXTINF:-1, Ch4
#KODIPROP:inputstream.adaptive.license_type=clearkey
#KODIPROP:inputstream.adaptive.license_key=00112233445566778899aabbccddeeff:00112233445566778899aabbccddeeff
https://example.com/03.mpd

#EXTINF:-1, Ch5
#KODIPROP:inputstream.adaptive.license_type=org.w3.clearkey
#KODIPROP:inputstream.adaptive.license_key={"keys":[{"kty":"oct","k":"base64key1","kid":"base64key2"}],"type":"temporary"}
https://example.com/04.mpd

⚠️ You can see other examples around an internet when #KODIPROP is specified before #EXTINF tag. TVirl supports it, but it's considered invalid and breaks parsing of global tags from a M3U header.


Other attributes

Attribute: tvg-shift

It's possible to specify time correction (hours) for programs from EPG resource. tvg-shift can be specified globally or per-channel. This correction is applied on top of time-zone correction specified for EPG resource during initial playlist installation.

#EXTM3U url-tvg="http://example.com/jtv.zip" tvg-shift=2

#EXTINF:-1, Ch1
http://example.com/01

#EXTINF:-1 tvg-shift=-1, Ch2
http://example.com/02

⚠️ In most cases there is no need in any time zone correction if you are using XmlTv EPG, since TVirl performs automatic conversion to user's local time zone. But there are reasons when additional time correction make sense:

  • EPG is in JTV format and your local zone is different than time zone used to generate JTV. JTV always uses local time zone and if it's different from user's one it should be manually corrected.
  • Channel's live stream is re-stream from original one with some delay applied.

Attribute: tvg-lang, tvg-language

If EPG resource provides programs information (title, description) in multiple languages TVirl will prefer language which matches to the system settings. It's possible to force specific language on per-channel basis.

  • tvg-lang="<language_code>", where language_code is ISO-639-1 (2 letters) or ISO-639-3 (3 letters). For example: ru, eng, es
  • tvg-language="<Language_Name>", where language_name conforms to language names from ISO-639-3. Multiple language names are supported: English;Chinese
#EXTINF:-1 tvg-lang="es", Ch1
http://example.com/01

#EXTINF:-1 tvg-language="Russian;English", Ch2
http://example.com/02