Skip to main content

用于处理 IPTV 的 M3U 播放列表的库(AKA m3u_plus)

项目描述

IPyTV

用于解析 M3U Plus 格式的 IPTV 播放列表的 python3 库。

下载 下载 下载

M3U Plus 和 IPTV

M3U Plus 格式是在 Internet 上分发 IPTV 播放列表的事实标准。

IPTV 播放列表M3U Plus 播放列表这两个术语通常可以互换使用,但在此存储库中,M3U Plus指的是数据格式,而IPTV 播放列表指的是 M3U Plus 格式的播放列表。

M3U Plus 源于extended M3U8 格式,它只支持 2 个标签(#EXTM3U#EXTINF)。

#EXTM3U和标签的语法#EXTINF已被修改以包含额外的属性(例如,徽标、组、语言)。不幸的是,这破坏了与原始 M3U8 标准的向后兼容性(如这里详细解释的)。

该库是从头开始创建的,仅用于解析和处理 M3U Plus 格式。它不完全支持常规 M3U8 播放列表(仅解析基本频道属性)。

支持的标签

仅支持#EXTM3U,#EXTINF和纯 url 行(即它们被解析并且它们的值作为IPTVChannel对象的属性可用)。

#EXTINF在行及其相关的 url 行之间找到的所有标签都作为extras通道添加,但不执行任何解析(即,它们被视为纯字符串)。

在下面的示例中,该#EXTVLCOPT行没有被解析,而是按原样复制:

#EXTINF:-1 tvg-id="" tvg-name="hello" tvg-country="IT" tvg-url="" group-title="Greetings",Hello!
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0 
https://my-website.com/hello

安装

这个库需要 Python 3(和相关的pip安装程序)。

请注意:该库使用了在使用IDLE环境multiprocessing.Pool时需要小心的类 。

要在系统范围内安装库,请运行:

pip install m3u-ipytv

要在虚拟环境中安装它,请运行:

python -m venv .venv
.venv/bin/activate
pip install m3u-ipytv

用法

模块

该库包括几个模块,每个模块都有一个特定的能力领域:

  • 渠道
    • 与播放列表中的频道处理相关的所有内容。
  • 医生
    • 修复 M3U 文件中常见错误的函数集合。
  • 例外
    • 库抛出的所有异常。
  • m3u
    • 与 M3U 文件相关的常量和函数。
  • 播放列表
    • 与加载和处理 M3U 播放列表相关的所有内容。

加载 IPTV 播放列表

从一个文件

使用playlist.loadf(file)功能:

from ipytv import playlist
file = "~/Documents/my_playlist.m3u"
pl = playlist.loadf(file)
print(pl.length())

从一个 URL

使用playlist.loadu(url)功能:

from ipytv import playlist
url = "https://iptv-org.github.io/iptv/categories/classic.m3u"
pl = playlist.loadu(url)
print(pl.length())

从一个字符串

使用playlist.loads(string)功能:

from ipytv import playlist
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 = playlist.loads(string)
print(pl.length())

从一个数组(即一个列表)

使用playlist.loada(array)功能:

from ipytv import playlist
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 = playlist.loada(array)
print(pl.length())

M3UPlaylist 类

上面的每个加载函数都返回一个M3UPlaylist类的对象。

此类模拟播放列表(基本上是频道列表)的概念,并提供与播放列表本身及其频道进行交互的方法。

播放列表中有两个主要属性,它们是:

  1. 属性
  2. 频道

这些属性是什么以及如何访问它们将在接下来的段落中描述。

访问播放列表的属性

行中指定的键值对#EXTM3U被视为播放列表范围的属性(即它们适用于播放列表本身或播放列表中的每个频道)。

例如x-tvg-url下面的部分:

#EXTM3U x-tvg-url="http://myown.link:80/luke/220311/22311"

这些属性,以字典的形式,可以通过以下 get_attributes()方法访问:

from ipytv import playlist
url = "https://iptv-org.github.io/iptv/categories/kids.m3u"
pl = playlist.loadu(url)
attributes = pl.get_attributes()
for k, v in attributes.items():
    print(f'"{k}": "{v}"')

或者,当事先知道属性的名称时,可以通过以下方式检索其值:

from ipytv import playlist
url = "https://iptv-org.github.io/iptv/categories/kids.m3u"
pl = playlist.loadu(url)
attributes = pl.get_attributes()
tvg_url = pl.get_attribute("x-tvg-url")
print(f"x-tvg-url: {tvg_url}")

也可以使用以下方法添加、修改和删除属性:

from ipytv.playlist import M3UPlaylist
pl = M3UPlaylist()
attribute_name = 'tvg-shift'
# Add the 'tvg-shift' attribute and set it to 1
pl.add_attribute(attribute_name, "1")
# Update the 'tvg-shift' attribute to -2
pl.update_attribute(attribute_name, "-2")
# Completely remove the 'tvg-shift' attribute
value_before_deletion = pl.remove_attribute(attribute_name)

还有一种方法允许以字典的形式一次添加多个属性(而不是单个属性):

pl.add_attributes({})

访问播放列表的频道

该类M3UPlaylist基本上是具有一些商品功能的频道列表。可以使用以下方法之一访问播放列表中的频道。

个别

通过使用get_channel(index)方法:

from ipytv import playlist
url = "https://iptv-org.github.io/iptv/categories/classic.m3u"
pl = playlist.loadu(url)
# Let's retrieve the first channel in the list
channel = pl.get_channel(0)
print(f'channel \"{channel.name}\": {channel.url}')
# The next line will throw IndexOutOfBoundsException
channel = pl.get_channel(-1)

迭代地

通过循环M3UPlaylist对象中的通道:

from ipytv import playlist
url = "https://iptv-org.github.io/iptv/categories/classic.m3u"
pl = playlist.loadu(url)
for channel in pl:
    print(f'channel \"{channel.name}\": {channel.url}')

低级

在所有前两种访问方法都不够用的情况下,可以通过以下get_channels()方法访问内部频道列表:

from ipytv import playlist

url = "https://iptv-org.github.io/iptv/categories/classic.m3u"
pl = playlist.loadu(url)
chan_list = pl.get_channels()
ten_channels = chan_list[:10] 

也可以使用以下方法添加、修改和删除通道:

from ipytv.playlist import M3UPlaylist
from ipytv.channel import IPTVChannel
pl = M3UPlaylist()
channel = IPTVChannel()
# Add a channel to the end of the list (last index)
pl.append_channel(channel)
# Insert a channel in the specified position (all succeeding channels are
# shifted right by 1 position)
pl.insert_channel(0, channel)
new_channel = IPTVChannel()
# Replace the second channel of the playlist with a new channel
pl.update_channel(1, new_channel)
# Remove the channel at the specified position (all succeeding channels are
# shifted left by 1 position)
old_channel = pl.remove_channel(0)

还有两种方法可以添加频道列表(而不是单个频道):

pl.append_channels([])
pl.insert_channels([])

访问通道的属性

M3UPlaylist 对象的get_channels()方法返回一个对象列表 IPTVChannel

一个IPTVChannel对象有 3 个基本属性(urlnameduration和两个可选字段:(attributes字典)和extras (列表)。

例如:

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"
    },
    extras=['#EXTVLCOPT:http-user-agent=Lavf53.32.100']
)
print(channel.name)
print(channel.attributes[IPTVAttr.GROUP_TITLE.value])
print(channel.extras[0])

IPTVAttr枚举类包含 IPTV 播放列表中常见的属性名称。

doctor模块_

来自 Internet 的 IPTV 播放列表通常包含许多格式错误。这个模块想要解决一些常见的错误。

该模块包含三个类,每个类都有自己的范围:

  1. M3UDoctor
    • 它包含修复 m3u 文件中的错误的方法(即无法将 m3u 文件加载为播放列表的错误)。
  2. IPTVChannelDoctor
  • 它包含修复通道中的错误(即#EXTINF 行的属性中的错误)的方法。
  1. M3UPlaylistDoctor
  • 它将修复应用于IPTVChannelDoctor播放列表中的所有频道。

上述所有类都提供了一种名为的公共静态方法sanitize(),该方法负责应用所有不同的修复程序。它可以按如下方式使用:

from ipytv.doctor import M3UDoctor, M3UPlaylistDoctor
from ipytv import playlist
with open('my-broken-playlist.m3u', encoding='utf-8') as in_file:
    content = in_file.readlines()
    fixed_content = M3UDoctor.sanitize(content)
    pl = playlist.loada(fixed_content)
    fixed_pl = M3UPlaylistDoctor.sanitize(pl)
    with open('my-fixed-playlist.m3u', 'w', encoding='utf-8') as out_file:
        content = fixed_pl.to_m3u_plus_playlist()
        out_file.write(content)

日志记录

IPyTV 支持 python 的标准日志系统

要启用 IPyTV 的日志记录,请将日志记录配置添加到您的应用程序:

import logging
from ipytv import playlist
logging.basicConfig(level=logging.INFO)
pl = playlist.loadu("https://iptv-org.github.io/iptv/categories/classic.m3u")

格式注意事项

#EXTM3UM3U Plus 格式引入的和标签扩展#EXTINF破坏了与 M3U8 格式的兼容性。

这是标准#EXTINF行的样子:

#EXTINF:-1,Rai 1

格式非常简单:

#EXTINF:<duration>,[<title>]

让我们分解一下:

  1. #EXTINF:标签_
  2. 内容的持续时间(整数或浮点数,有符号或无符号)
  3. 逗号字符
  4. 标题

这是#EXTINFM3U Plus 格式中的一行的样子:

#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

如果我们将其分解,我们会看到第 3 点和第 4 点已被添加(并且它们破坏了之前对#EXTINF标记的定义):

  1. #EXTINF:标签_
  2. 内容的持续时间(整数或浮点数,有符号或无符号)
  3. 空间
  4. 可变长度、空格分隔的属性列表
  5. 逗号字符
  6. 标题

第 4 点中的属性采用attribute="value"格式,其中value 也可能包含非转义逗号(这确实使解析逻辑复杂化)。

值得注意的是,M3U8 RFC 文档指定了 属性列表的格式,但 M3U Plus 的实现不符合标准。

总而言之,M3U Plus 格式及其怪癖和特质很难被人类阅读,也很难被计算机解析。这是一种丑陋的格式,但它太普遍而无法被忽略,并且 Python 缺乏解析库。

有趣的是,VLC 程序员是这样命名 M3U Plus 格式的 IPTV 播放列表的解析函数的:

static void parseEXTINFIptvDiots(...)

只是说... :sweat_smile:

执照

该项目根据 MIT 许可条款获得许可。

有关详细信息,请参阅LICENSE.txt

下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

m3u-ipytv-0.1.3.tar.gz (19.1 kB 查看哈希

已上传 source