proxytv


Nameproxytv JSON
Version 1.0.2 PyPI version JSON
download
home_pagehttps://github.com/NIKDISSV-Forever/ProxyTVRobot
Summaryproxytv.ru IPTV Channels Parser and Robot (Like ProxyBot)
upload_time2023-03-29 09:13:52
maintainer
docs_urlNone
authorNikita (NIKDISSV)
requires_python>=3.8
licenseMIT
keywords proxybot iptv proxytv.ru tv free
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # proxytv

Robot for https://proxytv.ru/ (ProxyBot)

> pip install [proxytv](https://pypi.org/project/proxytv)

> python -m proxytv --help

```
usage: proxytv [-h] [-f] [-t] [-q QUERY] [-cd COOLDOWN] [-x PROXY] [-chf CHANNEL_FILTERS] [-pl [PL ...]] [-o OUTPUT]

options:
  -h, --help            show this help message and exit
  -f, --forever         Run the script again every cooldown seconds.
  -t, --threading       Send and parse the request for each playlist in a separate thread. (Default: True)
  -q QUERY, --query QUERY
                        Send only one request with the specified text. For example: "ch: HD" or "pl: aist"
  -cd COOLDOWN, --cooldown COOLDOWN
                        Cooldown in seconds. (Default: 1)
  -x PROXY, --proxy PROXY
                        Proxy <protocol>://<ip>
  -chf CHANNEL_FILTERS, --channel-filters CHANNEL_FILTERS
                        Filters for received channels
  -pl [PL ...]          Playlist name(s)
  -o OUTPUT, --output OUTPUT
                        Output .m3u(8) file. (Default: <stdout>)
```

---

Если запустить без доп. аргументов, будут получены все каналы, всех плейлистов (plist)
И записаны в файл output, по умолчание выведет результат в формате m3u в консоль.

Аругмент -pl: список плейлистов по которым будет происходить поиск, по умолчанию все доступные.

# Код

```python
from .extinf import *
from .search import *
from .static import *


class Robot:
   """A class describing a parser robot. Designed for inheritance."""

   __slots__ = ('end_extinf', 'plist', 'PLIST_LEN', 'search_engine', 'pl_number', 'output')
   sort_key = None  # sort channels

   def __init__(self, forever: bool = True, cooldown: SupportsFloat = 0.,
                search: Srch = None, output=None, except_types=(Exception,)):
      """Runs the order of actions, if forever is true then it does it forever."""
      ...

   def post_init(self):
      """Execute after initialization."""
      pass

   def run(self, except_types: tuple[BaseException] = None, *, cooldown: int | float = None, forever: bool = None):
      """
      Run self.loop()
      Skip exceptions from `except_types`
      repeat if `forever` every `cooldown` seconds
      """
      if except_types is None:
         except_types = self.except_types
      if cooldown is None:
         cooldown = self.cooldown
      if forever is None:
         forever = self.forever
      ...

   def loop(self):
      self.on_start()
      self.during()
      self.on_end()

   def on_start(self):
      """Initial actions."""
      self.plist = self.search_engine.plist()
      self.PLIST_LEN = len(self.plist)
      self.end_extinf = Extinf()
      self.pl_number = 1

   def search_pl(self, pl_name: str):
      pl = self.search_engine.pl(pl_name)
      print(f'Pl: {pl_name} ({self.pl_number}/{self.PLIST_LEN}) Channels: {len(pl)}')
      self.end_extinf += pl
      self.pl_number += 1

   def during(self):
      """Actions in the middle of the process."""
      for pl_name in self.plist:
         self.search_pl(pl_name)

   def on_end(self):
      """Sort by self.sort_key function and save"""
      self.end_extinf.data.sort(key=self.sort_key)
      ch_count = len(self.end_extinf)
      print(f"Saving {ch_count} channel{'' if ch_count == 1 else 's'}")
      self.upload(save_extinf(self.end_extinf, self.output))

   def upload(self, fn: str):
      """Used to upload files to a remote host, used in on_end."""
      pass


class RobotThreading(Robot):
   """An example of implementing your own robot, with multithreading"""
   __slots__ = ('end_extinf', 'pl_number')

   def during(self):
      """Creates threads to search for each playlist."""
      with ThreadPool() as pool:
         pool.map(self.search_pl, self.plist)
```

Классы для наследования, при написании более сложных роботов.

# Фильтры

Аргумент `--channel-filters` принимает файл с фильтрами в формате регулярного выражения,
применяемого к выходному m3u формату

Существуют некоторое упрощения для более быстрого составления файла фильтров.
Напомню, выходной m3u формат выглядит примерно так:

```m3u
#EXTINF:-1 tvch-id="40025" group-title="ДЕТСКИЕ",DISNEY CHANNEL-40025
http://93.158.224.2:4022/udp/239.3.100.85:4321
```

Каждая строка в файле фильтров представляет собой фильтр в особом формате.

Чтобы канал прошёл фильтрацию, необходимо чтобы как минимум один фильтр к нему подошёл.

1. <kbd>\\</kbd> в начале строки всегда обрезается

2. Чтобы фильтровать IP адреса (вторую строку), фильтр должен начинаться со знака <kbd>:</kbd>

3. Чтобы проверить на присутствие подстроки в строке, фильтр должен начинаться с <kbd>#</kbd>

4. Или любое регулярное выражение (при использовании <kbd>#</kbd> регулярное выражение не применяется, строка
   экранируется), если строка начинается с <kbd>:</kbd>, регулярное выражение по-прежнему проверяется, но уже на IP
5. Все филтры не чувствительны к регистру (``re.IGNORECASE``)

---

Было:

```regexp
\:-1
```

Стало:

```regexp
:-1
```

---

```regexp
:.+:4022.+
```

Найти все IP с портом 1234

[http://93.158.224.2:<kbd>4022</kbd>/udp/239.3.100.85:4321](http://93.158.224.2:4022/udp/239.3.100.85:4321)

---

```regexp
:#:4321
```

```regexp
:.*:4321.*
```

[http://93.158.224.2:4022/udp/239.3.100.85<kbd>:4321</kbd>](http://93.158.224.2:4022/udp/239.3.100.85:4321)

---

```regexp
#group-title="ДЕТСКИЕ"
```

```regexp
.*group-title="ДЕТСКИЕ".*
```

Найти все каналы в группе детских

#EXTINF:-1 tvch-id="40025" <kbd>group-title="ДЕТСКИЕ"</kbd>,DISNEY CHANNEL-40025

---

```regexp
#HD
```

```regexp
.*HD.*
```

``Тоже что и -q "ch:HD" аргумет``

#EXTINF:-1 tvch-id="46046" group-title="ИНФ/РАЗВЛЕКАТЕЛЬНЫЕ",РОССИЯ 1 <kbd>HD</kbd>-46046

---
**Пример составления нужного плейлиста:**

filters.txt

```regexp
#NICKELODEON HD
#CARTOON NETWORK
#Рен ТВ
#ТНТ HD
#Пятница
#Россия 24
```

> python -m proxytv -chf filters.txt -f -cd 120 -o tv.m3u8

Каждые 2 минуты будет обновляться файл tv.m3u8 с перечисленными выше каналами.

---

_Вопросы задавайте на GitHub, на почту или загляните в исходный код, там всё прозрачно._

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/NIKDISSV-Forever/ProxyTVRobot",
    "name": "proxytv",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "ProxyBot,IPTV,proxytv.ru,TV,free",
    "author": "Nikita (NIKDISSV)",
    "author_email": "nikdissv@proton.me",
    "download_url": "https://files.pythonhosted.org/packages/bb/95/505aaebd31d91693ca17ac0ce1e6111b17f25cd3b2b742fa407c0d21cbad/proxytv-1.0.2.tar.gz",
    "platform": null,
    "description": "# proxytv\r\n\r\nRobot for https://proxytv.ru/ (ProxyBot)\r\n\r\n> pip install [proxytv](https://pypi.org/project/proxytv)\r\n\r\n> python -m proxytv --help\r\n\r\n```\r\nusage: proxytv [-h] [-f] [-t] [-q QUERY] [-cd COOLDOWN] [-x PROXY] [-chf CHANNEL_FILTERS] [-pl [PL ...]] [-o OUTPUT]\r\n\r\noptions:\r\n  -h, --help            show this help message and exit\r\n  -f, --forever         Run the script again every cooldown seconds.\r\n  -t, --threading       Send and parse the request for each playlist in a separate thread. (Default: True)\r\n  -q QUERY, --query QUERY\r\n                        Send only one request with the specified text. For example: \"ch: HD\" or \"pl: aist\"\r\n  -cd COOLDOWN, --cooldown COOLDOWN\r\n                        Cooldown in seconds. (Default: 1)\r\n  -x PROXY, --proxy PROXY\r\n                        Proxy <protocol>://<ip>\r\n  -chf CHANNEL_FILTERS, --channel-filters CHANNEL_FILTERS\r\n                        Filters for received channels\r\n  -pl [PL ...]          Playlist name(s)\r\n  -o OUTPUT, --output OUTPUT\r\n                        Output .m3u(8) file. (Default: <stdout>)\r\n```\r\n\r\n---\r\n\r\n\u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0431\u0435\u0437 \u0434\u043e\u043f. \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u0432\u0441\u0435 \u043a\u0430\u043d\u0430\u043b\u044b, \u0432\u0441\u0435\u0445 \u043f\u043b\u0435\u0439\u043b\u0438\u0441\u0442\u043e\u0432 (plist)\r\n\u0418 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u0444\u0430\u0439\u043b output, \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435 \u0432\u044b\u0432\u0435\u0434\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 m3u \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c.\r\n\r\n\u0410\u0440\u0443\u0433\u043c\u0435\u043d\u0442 -pl: \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043b\u0435\u0439\u043b\u0438\u0441\u0442\u043e\u0432 \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a, \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435.\r\n\r\n# \u041a\u043e\u0434\r\n\r\n```python\r\nfrom .extinf import *\r\nfrom .search import *\r\nfrom .static import *\r\n\r\n\r\nclass Robot:\r\n   \"\"\"A class describing a parser robot. Designed for inheritance.\"\"\"\r\n\r\n   __slots__ = ('end_extinf', 'plist', 'PLIST_LEN', 'search_engine', 'pl_number', 'output')\r\n   sort_key = None  # sort channels\r\n\r\n   def __init__(self, forever: bool = True, cooldown: SupportsFloat = 0.,\r\n                search: Srch = None, output=None, except_types=(Exception,)):\r\n      \"\"\"Runs the order of actions, if forever is true then it does it forever.\"\"\"\r\n      ...\r\n\r\n   def post_init(self):\r\n      \"\"\"Execute after initialization.\"\"\"\r\n      pass\r\n\r\n   def run(self, except_types: tuple[BaseException] = None, *, cooldown: int | float = None, forever: bool = None):\r\n      \"\"\"\r\n      Run self.loop()\r\n      Skip exceptions from `except_types`\r\n      repeat if `forever` every `cooldown` seconds\r\n      \"\"\"\r\n      if except_types is None:\r\n         except_types = self.except_types\r\n      if cooldown is None:\r\n         cooldown = self.cooldown\r\n      if forever is None:\r\n         forever = self.forever\r\n      ...\r\n\r\n   def loop(self):\r\n      self.on_start()\r\n      self.during()\r\n      self.on_end()\r\n\r\n   def on_start(self):\r\n      \"\"\"Initial actions.\"\"\"\r\n      self.plist = self.search_engine.plist()\r\n      self.PLIST_LEN = len(self.plist)\r\n      self.end_extinf = Extinf()\r\n      self.pl_number = 1\r\n\r\n   def search_pl(self, pl_name: str):\r\n      pl = self.search_engine.pl(pl_name)\r\n      print(f'Pl: {pl_name} ({self.pl_number}/{self.PLIST_LEN}) Channels: {len(pl)}')\r\n      self.end_extinf += pl\r\n      self.pl_number += 1\r\n\r\n   def during(self):\r\n      \"\"\"Actions in the middle of the process.\"\"\"\r\n      for pl_name in self.plist:\r\n         self.search_pl(pl_name)\r\n\r\n   def on_end(self):\r\n      \"\"\"Sort by self.sort_key function and save\"\"\"\r\n      self.end_extinf.data.sort(key=self.sort_key)\r\n      ch_count = len(self.end_extinf)\r\n      print(f\"Saving {ch_count} channel{'' if ch_count == 1 else 's'}\")\r\n      self.upload(save_extinf(self.end_extinf, self.output))\r\n\r\n   def upload(self, fn: str):\r\n      \"\"\"Used to upload files to a remote host, used in on_end.\"\"\"\r\n      pass\r\n\r\n\r\nclass RobotThreading(Robot):\r\n   \"\"\"An example of implementing your own robot, with multithreading\"\"\"\r\n   __slots__ = ('end_extinf', 'pl_number')\r\n\r\n   def during(self):\r\n      \"\"\"Creates threads to search for each playlist.\"\"\"\r\n      with ThreadPool() as pool:\r\n         pool.map(self.search_pl, self.plist)\r\n```\r\n\r\n\u041a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0440\u043e\u0431\u043e\u0442\u043e\u0432.\r\n\r\n# \u0424\u0438\u043b\u044c\u0442\u0440\u044b\r\n\r\n\u0410\u0440\u0433\u0443\u043c\u0435\u043d\u0442 `--channel-filters` \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0444\u0430\u0439\u043b \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f,\r\n\u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u043a \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u043c\u0443 m3u \u0444\u043e\u0440\u043c\u0430\u0442\u0443\r\n\r\n\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.\r\n\u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 m3u \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:\r\n\r\n```m3u\r\n#EXTINF:-1 tvch-id=\"40025\" group-title=\"\u0414\u0415\u0422\u0421\u041a\u0418\u0415\",DISNEY CHANNEL-40025\r\nhttp://93.158.224.2:4022/udp/239.3.100.85:4321\r\n```\r\n\r\n\u041a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0444\u0438\u043b\u044c\u0442\u0440 \u0432 \u043e\u0441\u043e\u0431\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435.\r\n\r\n\u0427\u0442\u043e\u0431\u044b \u043a\u0430\u043d\u0430\u043b \u043f\u0440\u043e\u0448\u0451\u043b \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0434\u0438\u043d \u0444\u0438\u043b\u044c\u0442\u0440 \u043a \u043d\u0435\u043c\u0443 \u043f\u043e\u0434\u043e\u0448\u0451\u043b.\r\n\r\n1. <kbd>\\\\</kbd> \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0431\u0440\u0435\u0437\u0430\u0435\u0442\u0441\u044f\r\n\r\n2. \u0427\u0442\u043e\u0431\u044b \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c IP \u0430\u0434\u0440\u0435\u0441\u0430 (\u0432\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443), \u0444\u0438\u043b\u044c\u0442\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441\u043e \u0437\u043d\u0430\u043a\u0430 <kbd>:</kbd>\r\n\r\n3. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435, \u0444\u0438\u043b\u044c\u0442\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 <kbd>#</kbd>\r\n\r\n4. \u0418\u043b\u0438 \u043b\u044e\u0431\u043e\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 (\u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <kbd>#</kbd> \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0441\u0442\u0440\u043e\u043a\u0430\r\n   \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f), \u0435\u0441\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 <kbd>:</kbd>, \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u043d\u043e \u0443\u0436\u0435 \u043d\u0430 IP\r\n5. \u0412\u0441\u0435 \u0444\u0438\u043b\u0442\u0440\u044b \u043d\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b \u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0443 (``re.IGNORECASE``)\r\n\r\n---\r\n\r\n\u0411\u044b\u043b\u043e:\r\n\r\n```regexp\r\n\\:-1\r\n```\r\n\r\n\u0421\u0442\u0430\u043b\u043e:\r\n\r\n```regexp\r\n:-1\r\n```\r\n\r\n---\r\n\r\n```regexp\r\n:.+:4022.+\r\n```\r\n\r\n\u041d\u0430\u0439\u0442\u0438 \u0432\u0441\u0435 IP \u0441 \u043f\u043e\u0440\u0442\u043e\u043c 1234\r\n\r\n[http://93.158.224.2:<kbd>4022</kbd>/udp/239.3.100.85:4321](http://93.158.224.2:4022/udp/239.3.100.85:4321)\r\n\r\n---\r\n\r\n```regexp\r\n:#:4321\r\n```\r\n\r\n```regexp\r\n:.*:4321.*\r\n```\r\n\r\n[http://93.158.224.2:4022/udp/239.3.100.85<kbd>:4321</kbd>](http://93.158.224.2:4022/udp/239.3.100.85:4321)\r\n\r\n---\r\n\r\n```regexp\r\n#group-title=\"\u0414\u0415\u0422\u0421\u041a\u0418\u0415\"\r\n```\r\n\r\n```regexp\r\n.*group-title=\"\u0414\u0415\u0422\u0421\u041a\u0418\u0415\".*\r\n```\r\n\r\n\u041d\u0430\u0439\u0442\u0438 \u0432\u0441\u0435 \u043a\u0430\u043d\u0430\u043b\u044b \u0432 \u0433\u0440\u0443\u043f\u043f\u0435 \u0434\u0435\u0442\u0441\u043a\u0438\u0445\r\n\r\n#EXTINF:-1 tvch-id=\"40025\" <kbd>group-title=\"\u0414\u0415\u0422\u0421\u041a\u0418\u0415\"</kbd>,DISNEY CHANNEL-40025\r\n\r\n---\r\n\r\n```regexp\r\n#HD\r\n```\r\n\r\n```regexp\r\n.*HD.*\r\n```\r\n\r\n``\u0422\u043e\u0436\u0435 \u0447\u0442\u043e \u0438 -q \"ch:HD\" \u0430\u0440\u0433\u0443\u043c\u0435\u0442``\r\n\r\n#EXTINF:-1 tvch-id=\"46046\" group-title=\"\u0418\u041d\u0424/\u0420\u0410\u0417\u0412\u041b\u0415\u041a\u0410\u0422\u0415\u041b\u042c\u041d\u042b\u0415\",\u0420\u041e\u0421\u0421\u0418\u042f 1 <kbd>HD</kbd>-46046\r\n\r\n---\r\n**\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u043f\u043b\u0435\u0439\u043b\u0438\u0441\u0442\u0430:**\r\n\r\nfilters.txt\r\n\r\n```regexp\r\n#NICKELODEON HD\r\n#CARTOON NETWORK\r\n#\u0420\u0435\u043d \u0422\u0412\r\n#\u0422\u041d\u0422 HD\r\n#\u041f\u044f\u0442\u043d\u0438\u0446\u0430\r\n#\u0420\u043e\u0441\u0441\u0438\u044f 24\r\n```\r\n\r\n> python -m proxytv -chf filters.txt -f -cd 120 -o tv.m3u8\r\n\r\n\u041a\u0430\u0436\u0434\u044b\u0435 2 \u043c\u0438\u043d\u0443\u0442\u044b \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0444\u0430\u0439\u043b tv.m3u8 \u0441 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u044b\u0448\u0435 \u043a\u0430\u043d\u0430\u043b\u0430\u043c\u0438.\r\n\r\n---\r\n\r\n_\u0412\u043e\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430 GitHub, \u043d\u0430 \u043f\u043e\u0447\u0442\u0443 \u0438\u043b\u0438 \u0437\u0430\u0433\u043b\u044f\u043d\u0438\u0442\u0435 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434, \u0442\u0430\u043c \u0432\u0441\u0451 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e._\r\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "proxytv.ru IPTV Channels Parser and Robot (Like ProxyBot)",
    "version": "1.0.2",
    "split_keywords": [
        "proxybot",
        "iptv",
        "proxytv.ru",
        "tv",
        "free"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2e10c5ed1e9f237d5c387c4cfc43d92b20f66bce1ae6f4821395d5e93fae24e9",
                "md5": "3b9bc3bdea9eabba3803bcca25dcfa24",
                "sha256": "665e2867dc88818d63b467bdf3b12bf34bb6786f27a519b095ecb962a20aafee"
            },
            "downloads": -1,
            "filename": "proxytv-1.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3b9bc3bdea9eabba3803bcca25dcfa24",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 12724,
            "upload_time": "2023-03-29T09:13:51",
            "upload_time_iso_8601": "2023-03-29T09:13:51.009968Z",
            "url": "https://files.pythonhosted.org/packages/2e/10/c5ed1e9f237d5c387c4cfc43d92b20f66bce1ae6f4821395d5e93fae24e9/proxytv-1.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bb95505aaebd31d91693ca17ac0ce1e6111b17f25cd3b2b742fa407c0d21cbad",
                "md5": "be5bac02339f9f3aba3505b8857004e5",
                "sha256": "b6ac2b18c4dc4a5d9dd4db1a5b39b0a71b685fe12db1cbfd1789d16556e729f8"
            },
            "downloads": -1,
            "filename": "proxytv-1.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "be5bac02339f9f3aba3505b8857004e5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 13229,
            "upload_time": "2023-03-29T09:13:52",
            "upload_time_iso_8601": "2023-03-29T09:13:52.497316Z",
            "url": "https://files.pythonhosted.org/packages/bb/95/505aaebd31d91693ca17ac0ce1e6111b17f25cd3b2b742fa407c0d21cbad/proxytv-1.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-03-29 09:13:52",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "NIKDISSV-Forever",
    "github_project": "ProxyTVRobot",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "proxytv"
}
        
Elapsed time: 0.64970s