Initial commit
This commit is contained in:
commit
72ce4f37fe
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.venv
|
||||||
|
bin
|
||||||
|
include
|
||||||
|
lib
|
||||||
|
__pycache__
|
||||||
|
pyvenv.cfg
|
||||||
|
.DS_Store
|
44
README.md
Normal file
44
README.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
## M3U Category Matcher
|
||||||
|
|
||||||
|
Do you have IPTV provider who doesn't add categories to channels, but uses channels for it?
|
||||||
|
This script will attach channel-like categories to channels under them.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
You have these 5 channels:
|
||||||
|
1. ### GENERAL ###
|
||||||
|
2. TV1 HD
|
||||||
|
3. TV2 HD
|
||||||
|
4. ### MUSIC ###
|
||||||
|
5. METAL LIVE TV HD
|
||||||
|
|
||||||
|
For example, if you provided `\#\#\# (.*) \#\#\#` regex:
|
||||||
|
This script will __remove__ channel with no. 1. and 5., then __attach__ categories:
|
||||||
|
- GENERAL (matched group from regex!) to channels 2, 3,
|
||||||
|
- MUSIC to channel 5.
|
||||||
|
|
||||||
|
### NOTE!
|
||||||
|
This script is in BETA phase. Please report any bugs!
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
- argparse
|
||||||
|
- pathlib
|
||||||
|
- re
|
||||||
|
- [ipytv](https://github.com/Beer4Ever83/ipytv)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
```bash
|
||||||
|
python3 <path-to-script> -i "<m3u path>" -r "<regex to match>" (-v)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Result
|
||||||
|
When everything is done, file is **OVERWRITTEN**!
|
||||||
|
|
||||||
|
### Example usage
|
||||||
|
```bash
|
||||||
|
python3 <path-to-script> -i "m3u_list.m3u" -r "\#\#\# (.*) \#\#\#"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available parameters
|
||||||
|
- -i/--input - absolute path to m3u+ file
|
||||||
|
- -r/--regex - regular expression used to match categories in channel names
|
||||||
|
- -v/--verbose - enable verbose mode
|
80
__main__.py
Normal file
80
__main__.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
from ipytv import playlist as tv_playlist
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
def parse_arguments():
|
||||||
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument("-r", "--regex", dest="regex", help="Regex to match the categories", required=True)
|
||||||
|
parser.add_argument("-i", "--input", dest="input", help="Path to m3u+ file", required=True, type=Path)
|
||||||
|
parser.add_argument("-v", "--verbose", dest="verbose", help="Enable verbose mode", action="store_true")
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
def debug(message: str):
|
||||||
|
global verbose
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print("[M3U-CATEGORY-MATCHER:DEBUG] " + message)
|
||||||
|
|
||||||
|
def process(arguments):
|
||||||
|
debug("Processing...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
playlist = tv_playlist.loadf(str(arguments.input))
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print("Your playlist is not UTF-8 encoded, or has invalid characters. Please convert it to UTF-8.")
|
||||||
|
exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print("Something went wrong while loading playlist.")
|
||||||
|
print(e)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
debug("Playlist loaded.")
|
||||||
|
debug("Matching categories...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
regex = re.compile(arguments.regex)
|
||||||
|
except re.error:
|
||||||
|
print("Invalid regex provided.")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if regex.groups != 1:
|
||||||
|
print("Regex must have exactly one group to match.")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Example:
|
||||||
|
# Regex: ### ([a-zA-Z0-9]+) ###
|
||||||
|
# Channel 1 name: "### Movies ###"
|
||||||
|
# Channel 2 name: "1 HD"
|
||||||
|
# Channel 3 name: "2 HD"
|
||||||
|
# Channel 4 name: "### News ###"
|
||||||
|
# Channel 5 name: "3 HD"
|
||||||
|
# Add category "Movies" to channels: 2., 3.
|
||||||
|
# Add category "News" to channel 5.
|
||||||
|
|
||||||
|
current_category = None
|
||||||
|
for index, channel in enumerate(playlist):
|
||||||
|
match = regex.match(channel.name)
|
||||||
|
if match:
|
||||||
|
playlist.remove_channel(index)
|
||||||
|
current_category = channel.name
|
||||||
|
|
||||||
|
debug(f"Category matched: {current_category}")
|
||||||
|
elif current_category:
|
||||||
|
debug(f"Adding category {current_category} to channel {channel.name}")
|
||||||
|
channel.attributes["group-title"] = current_category
|
||||||
|
|
||||||
|
# save playlist
|
||||||
|
debug("Saving playlist...")
|
||||||
|
with open(arguments.input, "w+", encoding="utf-8") as f:
|
||||||
|
f.write(playlist.to_m3u_plus_playlist())
|
||||||
|
|
||||||
|
print("All done!")
|
||||||
|
print("Thanks for using this script!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
arguments = parse_arguments()
|
||||||
|
verbose = arguments.verbose
|
||||||
|
|
||||||
|
process(arguments)
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
m3u-ipytv
|
Loading…
Reference in New Issue
Block a user