A library for handling M3U playlists for IPTV (AKA m3u_plus)
Project description
IPyTV
A python3 library to parse IPTV playlists in the M3U Plus format.
M3U Plus and IPTV
The M3U Plus format is a de facto standard for distributing IPTV playlists on the Internet.
The terms IPTV playlist and M3U Plus playlist are generally used interchangeably, but in this repository M3U Plus refers to the data format, while IPTV Playlist refers to playlists in M3U Plus format.
M3U Plus stems from the extended M3U8
format, of which it supports only 2 tags (#EXTM3U
and #EXTINF
).
The syntax of the #EXTM3U
and #EXTINF
tags has been modified to include
extra attributes (e.g., logo, group, language). Unfortunately this has broken
the backward compatibility with the original M3U8 standard (as explained in
detail here).
This library has been created from scratch to parse and handle the M3U Plus format only. It does not fully support regular M3U8 playlists.
Installation
This library requires Python 3 (and the related pip
installer).
PLEASE NOTE: the library makes use of the multiprocessing.Pool
class
that requires some care when working with the
IDLE environment.
To install the library system-wide, run:
pip install m3u-ipytv
To install it within a virtual environment, run:
python -m venv .venv
source .venv/bin/activate
pip install m3u-ipytv
Usage
Load an IPTV Playlist from a file
import ipytv
file = "~/Documents/my_playlist.m3u"
pl = ipytv.playlist.M3UPlaylist.loadf(file)
print(len(pl.list))
Load an IPTV Playlist from a URL
import ipytv
url = "https://iptv-org.github.io/iptv/categories/classic.m3u"
pl = ipytv.playlist.M3UPlaylist.loadu(url)
print(len(pl.list))
Other loading methods
M3U Playlists can be loaded as a string as well as an array with the following methods
String:
import ipytv
string = """#EXTM3U
#EXTINF:-1 tvg-id="Rai 1" tvg-name="Rai 1" group-title="RAI",Rai 1
http://myown.link:80/luke/210274/78482"""
pl = ipytv.playlist.M3UPlaylist.loads(string)
Array (i.e. a List):
import ipytv
array = [
'#EXTM3U',
'#EXTINF:-1 tvg-id="Rai 1" tvg-name="Rai 1" group-title="RAI",Rai 1',
'http://myown.link:80/luke/210274/78482'
]
pl = ipytv.playlist.M3UPlaylist.loada(array)
Access the global properties of a playlist
Attributes that are specified in the #EXTM3U
row are considered to be valid
playlist-wide.
These can be accessed via the attributes
dictionary of a playlist:
import ipytv
url = "https://iptv-org.github.io/iptv/categories/kids.m3u"
pl = ipytv.playlist.M3UPlaylist.loadu(url)
for a in pl.attributes:
print(f'"{a}": "{pl.attributes[a]}"')
Access the channels in the playlist
Once loaded, the channels in a playlist can be accessed by using the
list
property:
import ipytv
url = "https://iptv-org.github.io/iptv/categories/classic.m3u"
pl = ipytv.playlist.M3UPlaylist.loadu(url)
for channel in pl.list:
print(f'channel \"{channel.name}\": {channel.url}')
Access the properties of a channel
The list
property of an M3UPlaylist object contains a list of IPTVChannel
objects.
An IPTVChannel
object has 3 basic properties (url
, name
and
duration
) and an optional attributes
dictionary.
For example:
from ipytv.channel import IPTVAttr, IPTVChannel
channel = IPTVChannel(
url="http://myown.link:80/luke/210274/78482",
name="Rai 1",
duration="-1",
attributes={
IPTVAttr.TVG_ID.value: "Rai 1",
IPTVAttr.TVG_NAME.value: "Rai 1",
IPTVAttr.TVG_LOGO.value: "https://static.epg.best/it/RaiUno.it.png",
IPTVAttr.GROUP_TITLE.value: "RAI"
}
)
print(channel.name)
print(channel.attributes[IPTVAttr.GROUP_TITLE.value])
The IPTVAttr
enum class contains tags that are commonly found in IPTV
Playlists.
Logging
IPyTV supports python's standard logging system.
To enable IPyTV's logging, add a logging configuration to your application:
import logging
import ipytv
logging.basicConfig(level=logging.DEBUG)
pl = ipytv.M3UPlaylist.loadu("https://iptv-org.github.io/iptv/categories/classic.m3u")
Format considerations
The extensions to the #EXTM3U
and #EXTINF
tags introduced by the M3U Plus
format have broken the compatibility with the M3U8 format.
This is what a standard #EXTINF
row should look like:
#EXTINF:-1,Rai 1
The format is pretty straightforward:
#EXTINF:<duration>,[<title>]
Let's break it down:
- the
#EXTINF:
tag - the duration of the content (as an integer or float, signed or not)
- a comma character
- a title
This is what an #EXTINF
row in the M3U Plus format looks like:
#EXTINF:-1 tvg-id="Rai 1" tvg-name="Rai 1" tvg-logo="https://static.epg.best/it/RaiUno.it.png" group-title="RAI",Rai 1
If we break it down, we see that points 3. and 4. have been added (and they
break the previous definition for the #EXTINF
tag):
- the
#EXTINF:
tag - the duration of the content (as an integer or float, signed or not)
- a space
- a variable-length, space-separated list of attributes
- a comma character
- a title
The attributes in point 4 are in the attribute="value"
format, where value
may also contain non-escaped commas (and this really complicates the parsing
logic).
It's worth noting that the M3U8 RFC document specifies how attribute lists should be formatted, but the M3U Plus implementation doesn't comply with the standard.
In conclusion, the M3U Plus format with its quirks and idiosyncrasies is hard to read for humans and hard to parse for computers. It's an ugly format, but it's too widespread to be ignored and for Python to lack a parsing library.
On a funny note, this is how the VLC programmers named the parsing function for the IPTV playlists in the M3U Plus format:
static void parseEXTINFIptvDiots(...)
Just saying... :sweat_smile:
License
This project is licensed under the terms of the MIT license.
See LICENSE.txt for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.