|
|
import re |
|
|
import requests |
|
|
import gradio as gr |
|
|
from pathlib import Path |
|
|
import random |
|
|
import string |
|
|
|
|
|
def _random_name(ext=".m3u", length=3): |
|
|
|
|
|
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length)) + ext |
|
|
|
|
|
def _to_raw_github(url: str) -> str: |
|
|
if "github.com" in url and "/blob/" in url: |
|
|
return url.replace("github.com", "raw.githubusercontent.com").replace("/blob/", "/") |
|
|
return url |
|
|
|
|
|
def _clean_parenthetical(text: str) -> str: |
|
|
m = re.search(r"\(([^)]*)\)", text) |
|
|
if not m: |
|
|
return text |
|
|
inside = m.group(1) |
|
|
parts = [p.strip() for p in inside.split(" / ")] |
|
|
mt_seg = None |
|
|
for p in parts: |
|
|
if re.search(r"\bMT\b", p): |
|
|
mt_seg = p |
|
|
break |
|
|
if not mt_seg: |
|
|
return text |
|
|
mt_seg_clean = mt_seg.replace(",", "") |
|
|
start, end = m.span() |
|
|
return text[:start] + f"({mt_seg_clean})" + text[end:] |
|
|
|
|
|
def _filter_text(content: str) -> str: |
|
|
out_lines = [] |
|
|
for line in content.splitlines(): |
|
|
if "(" in line and " / " in line and "MT" in line: |
|
|
out_lines.append(_clean_parenthetical(line)) |
|
|
else: |
|
|
out_lines.append(line) |
|
|
return "\n".join(out_lines) |
|
|
|
|
|
def filter_from_url(url: str): |
|
|
if not url or not url.strip(): |
|
|
return "Please paste a URL." |
|
|
url = _to_raw_github(url.strip()) |
|
|
try: |
|
|
r = requests.get(url, timeout=20) |
|
|
except Exception as e: |
|
|
return f"Error fetching file: {e}" |
|
|
if r.status_code != 200: |
|
|
return f"Error fetching file: HTTP {r.status_code}" |
|
|
|
|
|
filtered = _filter_text(r.text) |
|
|
out_path = Path("/tmp") / _random_name() |
|
|
out_path.write_text(filtered, encoding="utf-8") |
|
|
return str(out_path) |
|
|
|
|
|
def filter_from_file(file_obj): |
|
|
if file_obj is None: |
|
|
return "Please upload a file." |
|
|
text = Path(file_obj.name).read_text(encoding="utf-8", errors="ignore") |
|
|
filtered = _filter_text(text) |
|
|
out_path = Path("/tmp") / _random_name() |
|
|
out_path.write_text(filtered, encoding="utf-8") |
|
|
return str(out_path) |
|
|
|
|
|
with gr.Blocks(title="M3U Cleaner") as demo: |
|
|
gr.Markdown("### removes commas in short random name like `a9z`.") |
|
|
|
|
|
with gr.Tab("From URL"): |
|
|
url_in = gr.Textbox(label="M3U URL", placeholder="https://…/file.m3u8") |
|
|
url_btn = gr.Button("Clean") |
|
|
url_out = gr.File(label="Download filtered M3U") |
|
|
url_btn.click(filter_from_url, inputs=url_in, outputs=url_out) |
|
|
|
|
|
with gr.Tab("From File"): |
|
|
file_in = gr.File(label="Upload .m3u or .m3u8") |
|
|
file_btn = gr.Button("Clean") |
|
|
file_out = gr.File(label="Download filtered M3U") |
|
|
file_btn.click(filter_from_file, inputs=file_in, outputs=file_out) |
|
|
|
|
|
demo.queue() |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |
|
|
|