This commit is contained in:
doms9 2025-09-19 02:05:40 -04:00
parent 00000d94a2
commit 00000d9a95
12 changed files with 160 additions and 55 deletions

View file

@ -11,6 +11,7 @@ tvg_ids_file = Path(__file__).parent / "TVG-IDs.json"
epg_file = Path(__file__).parent / "TV.xml" epg_file = Path(__file__).parent / "TV.xml"
epg_urls = [ epg_urls = [
"https://epgshare01.online/epgshare01/epg_ripper_CA1.xml.gz", "https://epgshare01.online/epgshare01/epg_ripper_CA1.xml.gz",
"https://epgshare01.online/epgshare01/epg_ripper_DUMMY_CHANNELS.xml.gz",
"https://epgshare01.online/epgshare01/epg_ripper_ES1.xml.gz", "https://epgshare01.online/epgshare01/epg_ripper_ES1.xml.gz",
"https://epgshare01.online/epgshare01/epg_ripper_FANDUEL1.xml.gz", "https://epgshare01.online/epgshare01/epg_ripper_FANDUEL1.xml.gz",
"https://epgshare01.online/epgshare01/epg_ripper_MY1.xml.gz", "https://epgshare01.online/epgshare01/epg_ripper_MY1.xml.gz",

View file

@ -5,7 +5,7 @@ from urllib.parse import urljoin
import httpx import httpx
from selectolax.parser import HTMLParser, Node from selectolax.parser import HTMLParser, Node
from .utils import LOGOS, get_base, get_logger from .utils import get_base, get_logger, league_info
log = get_logger(__name__) log = get_logger(__name__)
@ -109,11 +109,16 @@ async def main(client: httpx.AsyncClient) -> None:
for i, link in enumerate(m3u8_urls, start=1): for i, link in enumerate(m3u8_urls, start=1):
sport, event = item["sport"], item["event"] sport, event = item["sport"], item["event"]
urls[f"[{sport}] {event} (S{i})"] = { key = f"[{sport}] {event} (S{i})"
entry = {
"url": link, "url": link,
"logo": LOGOS.get(sport, LOGOS["default"]), "logo": league_info(sport)["logo"],
"tvg-id": league_info(sport)["id"],
} }
urls[key] = entry
log.info(f"Collected {len(urls)} events") log.info(f"Collected {len(urls)} events")

View file

@ -5,9 +5,9 @@ import httpx
from selectolax.parser import HTMLParser from selectolax.parser import HTMLParser
from .utils import ( from .utils import (
LOGOS,
get_base, get_base,
get_logger, get_logger,
league_info,
load_cache, load_cache,
now, now,
safe_process_event, safe_process_event,
@ -76,7 +76,6 @@ async def get_events(
{ {
"sport": event_name, "sport": event_name,
"link": urljoin(base_url, href), "link": urljoin(base_url, href),
"logo": LOGOS.get(event_name, LOGOS["default"]),
"href": href, "href": href,
} }
) )
@ -152,17 +151,18 @@ async def main(client: httpx.AsyncClient) -> None:
) )
if url: if url:
sport = ev["sport"]
key = ( key = (
f"[{ev['sport']}] {match_name} (FSTV)" f"[{sport}] {match_name} (FSTV)" if match_name else f"[{sport}] (FSTV)"
if match_name
else f"[{ev['sport']}] (FSTV)"
) )
entry = { entry = {
"url": url, "url": url,
"logo": ev["logo"], "logo": league_info(sport)["logo"],
"base": base_url, "base": base_url,
"timestamp": now.timestamp(), "timestamp": now.timestamp(),
"tvg-id": league_info(sport)["id"],
"href": ev["href"], "href": ev["href"],
} }

View file

@ -10,10 +10,10 @@ import httpx
from playwright.async_api import async_playwright from playwright.async_api import async_playwright
from .utils import ( from .utils import (
LOGOS,
TZ, TZ,
capture_req, capture_req,
get_logger, get_logger,
league_info,
load_cache, load_cache,
new_browser, new_browser,
now, now,
@ -38,8 +38,6 @@ CERT_FILE = Path(__file__).parent / "caches" / "cached-cert.pem"
CACHE_FILE = Path(__file__).parent / "caches" / "livetvsx.json" CACHE_FILE = Path(__file__).parent / "caches" / "livetvsx.json"
exist_sprts = set(LOGOS.keys())
async def write_to_cert( async def write_to_cert(
client: httpx.AsyncClient, client: httpx.AsyncClient,
@ -260,10 +258,6 @@ async def get_events(
elem.clear() elem.clear()
continue continue
if exist_sprts & {sport, event}:
elem.clear()
continue
events.append( events.append(
{ {
"sport": sport, "sport": sport,
@ -298,13 +292,8 @@ async def main(client: httpx.AsyncClient) -> None:
log.info(f"Processing {len(events)} new URL(s)") log.info(f"Processing {len(events)} new URL(s)")
for i, ev in enumerate(events, start=1): for i, ev in enumerate(events, start=1):
sport = ev["sport"]
event = ev["event"]
title = ev["title"]
link = ev["link"] link = ev["link"]
key = f"[{sport}: {event}] {title} (LTVSX)"
url = await safe_process_event( url = await safe_process_event(
lambda: process_event(link, url_num=i), lambda: process_event(link, url_num=i),
url_num=i, url_num=i,
@ -312,9 +301,16 @@ async def main(client: httpx.AsyncClient) -> None:
) )
if url: if url:
sport = ev["sport"]
event = ev["event"]
title = ev["title"]
key = f"[{sport}: {event}] {title} (LTVSX)"
entry = { entry = {
"url": url, "url": url,
"logo": LOGOS.get(sport, LOGOS["default"]), "logo": league_info(sport)["logo"],
"tvg-id": league_info(sport)["id"],
"base": "https://livetv.sx/enx/", "base": "https://livetv.sx/enx/",
"timestamp": now.timestamp(), "timestamp": now.timestamp(),
} }

View file

@ -12,11 +12,11 @@ import httpx
from playwright.async_api import async_playwright from playwright.async_api import async_playwright
from .utils import ( from .utils import (
LOGOS,
TZ, TZ,
capture_req, capture_req,
get_base, get_base,
get_logger, get_logger,
league_info,
load_cache, load_cache,
new_browser, new_browser,
now, now,
@ -140,7 +140,7 @@ async def get_events(
event["name"], event["name"],
event["starts_at"], event["starts_at"],
event["ends_at"], event["ends_at"],
event.get("poster", LOGOS["default"]), event["poster"],
event["uri_name"], event["uri_name"],
) )
@ -198,13 +198,16 @@ async def main(client: httpx.AsyncClient) -> None:
) )
if url: if url:
key = f"[{ev['sport']}] {ev['event']} (PPV)" sport, event = ev["sport"], ev["event"]
key = f"[{sport}] {event} (PPV)"
entry = { entry = {
"url": url, "url": url,
"logo": ev["logo"], "logo": ev["logo"],
"base": base_url, "base": base_url,
"timestamp": now.timestamp(), "timestamp": now.timestamp(),
"tvg-id": league_info(sport)["id"],
} }
urls[key] = cached_urls[key] = entry urls[key] = cached_urls[key] = entry

View file

@ -5,7 +5,14 @@ from urllib.parse import urljoin
import httpx import httpx
from selectolax.parser import HTMLParser from selectolax.parser import HTMLParser
from .utils import get_logger, load_cache, now, safe_process_event, write_cache from .utils import (
get_logger,
league_info,
load_cache,
now,
safe_process_event,
write_cache,
)
log = get_logger(__name__) log = get_logger(__name__)
@ -97,13 +104,16 @@ async def main(client: httpx.AsyncClient) -> None:
) )
if url: if url:
key = f"[{ev['sport']}] {ev['event']} (SBTW)" sport, event = ev["sport"], ev["event"]
key = f"[{sport}] {event} (SBTW)"
entry = { entry = {
"url": url, "url": url,
"logo": ev["logo"], "logo": ev["logo"] or league_info(sport)["logo"],
"base": BASE_URL, "base": BASE_URL,
"timestamp": now.timestamp(), "timestamp": now.timestamp(),
"tvg-id": league_info(sport)["id"],
} }
urls[key] = entry urls[key] = entry

View file

@ -9,11 +9,11 @@ from playwright.async_api import async_playwright
from selectolax.parser import HTMLParser from selectolax.parser import HTMLParser
from .utils import ( from .utils import (
LOGOS,
TZ, TZ,
capture_req, capture_req,
get_base, get_base,
get_logger, get_logger,
league_info,
load_cache, load_cache,
new_browser, new_browser,
now, now,
@ -146,7 +146,6 @@ async def get_events(
"sport": sport, "sport": sport,
"event": name, "event": name,
"link": href, "link": href,
"logo": LOGOS.get(sport, LOGOS["default"]),
} }
) )
@ -183,13 +182,16 @@ async def main(client: httpx.AsyncClient) -> None:
) )
if url: if url:
key = f"[{ev['sport']}] {ev['event']} (SEAST)" sport, event = ev["sport"], ev["event"]
key = f"[{sport}] {event} (SEAST)"
entry = { entry = {
"url": url, "url": url,
"logo": ev["logo"], "logo": league_info(sport)["logo"],
"base": base_url, "base": base_url,
"timestamp": now.timestamp(), "timestamp": now.timestamp(),
"tvg-id": league_info(sport)["id"],
} }
urls[key] = cached_urls[key] = entry urls[key] = cached_urls[key] = entry

View file

@ -3,7 +3,7 @@ from pathlib import Path
import httpx import httpx
from .utils import LOGOS, get_logger, load_cache, now, write_cache from .utils import get_logger, league_info, load_cache, now, write_cache
log = get_logger(__name__) log = get_logger(__name__)
@ -54,7 +54,8 @@ async def main(client: httpx.AsyncClient) -> None:
entry = { entry = {
"url": f"http://origin.thetvapp.to/hls/{url.split('/')[-2]}/mono.m3u8", "url": f"http://origin.thetvapp.to/hls/{url.split('/')[-2]}/mono.m3u8",
"logo": LOGOS.get(sport, LOGOS["default"]), "logo": league_info(sport)["logo"],
"tvg-id": league_info(sport)["id"],
"base": "https://tvpass.org", "base": "https://tvpass.org",
"timestamp": now.timestamp(), "timestamp": now.timestamp(),
} }

View file

@ -1,16 +1,16 @@
from .cache import load_cache, write_cache from .cache import load_cache, write_cache
from .config import LOGOS, TZ, UA, now from .config import TZ, UA, league_info, now
from .logger import get_logger from .logger import get_logger
from .network import CLIENT, capture_req, get_base, new_browser, safe_process_event from .network import CLIENT, capture_req, get_base, new_browser, safe_process_event
__all__ = [ __all__ = [
"CLIENT", "CLIENT",
"LOGOS",
"TZ", "TZ",
"UA", "UA",
"capture_req", "capture_req",
"get_base", "get_base",
"get_logger", "get_logger",
"league_info",
"load_cache", "load_cache",
"new_browser", "new_browser",
"now", "now",

View file

@ -45,4 +45,6 @@ def load_cache(
def write_cache(file: Path, data: dict) -> None: def write_cache(file: Path, data: dict) -> None:
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text(json.dumps(data, indent=2), encoding="utf-8") file.write_text(json.dumps(data, indent=2), encoding="utf-8")

View file

@ -12,33 +12,118 @@ UA = (
"Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0" "Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0"
) )
LOGOS = { LEAGUES: dict[str, dict[str, str]] = {
"Bundesliga": "https://1000logos.net/wp-content/uploads/2020/09/Bundesliga-Logo-500x313.png", "Basketball": {
"La Liga": "https://1000logos.net/wp-content/uploads/2019/01/Spanish-La-Liga-Logo-500x281.png", "logo": "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png",
"Ligue 1": "https://1000logos.net/wp-content/uploads/2019/01/Ligue-1-Logo-500x281.png", "id": "Basketball.Dummy.us",
"MLB": "https://1000logos.net/wp-content/uploads/2017/04/MLB-Logo-500x281.png", },
"MLS": "https://1000logos.net/wp-content/uploads/2017/10/MLS-logo-500x393.png", "Bundesliga": {
"NBA": "https://1000logos.net/wp-content/uploads/2025/08/Jerry-West-the-NBA-Logo-500x281.png", "logo": "https://1000logos.net/wp-content/uploads/2020/09/Bundesliga-Logo-500x313.png",
"NCAA": "https://1000logos.net/wp-content/uploads/2021/12/NCAA-Logo-500x281.png", "id": "Soccer.Dummy.us",
"NFL": "https://1000logos.net/wp-content/uploads/2017/05/NFL-logo-500x338.png", },
"NHL": "https://1000logos.net/wp-content/uploads/2017/05/NHL-Logo-500x333.png", "F1": {
"Premier League": "https://1000logos.net/wp-content/uploads/2017/05/Premier-League-logo-500x210.png", "logo": "https://1000logos.net/wp-content/uploads/2021/06/F1-logo-500x281.png",
"Primera A": "https://b.fssta.com/uploads/application/soccer/competition-logos/ColombianPrimeraA.png", "id": "Racing.Dummy.us",
"Primeira Liga": "https://1000logos.net/wp-content/uploads/2022/01/Portuguese-Primeira-Liga-logo-500x281.png", },
"Serie A": " https://1000logos.net/wp-content/uploads/2019/01/Italian-Serie-A-Logo-500x281.png", "La Liga": {
"UEFA Champions League": "https://1000logos.net/wp-content/uploads/2022/01/UEFA-Champions-League-logo-500x281.png", "logo": "https://1000logos.net/wp-content/uploads/2019/01/Spanish-La-Liga-Logo-500x281.png",
"WNBA": "https://1000logos.net/wp-content/uploads/2018/09/logo-wnba-500x287.png", "id": "Soccer.Dummy.us",
"default": "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png", },
"Ligue 1": {
"logo": "https://1000logos.net/wp-content/uploads/2019/01/Ligue-1-Logo-500x281.png",
"id": "Soccer.Dummy.us",
},
"MLB": {
"logo": "https://1000logos.net/wp-content/uploads/2017/04/MLB-Logo-500x281.png",
"id": "MLB.Baseball.Dummy.us",
},
"MLS": {
"logo": "https://1000logos.net/wp-content/uploads/2017/10/MLS-logo-500x393.png",
"id": "MLS.Soccer.Dummy.us",
},
"Moto GP": {
"logo": "https://1000logos.net/wp-content/uploads/2021/03/MotoGP-Logo-500x281.png",
"id": "Racing.Dummy.us",
},
"NBA": {
"logo": "https://1000logos.net/wp-content/uploads/2025/08/Jerry-West-the-NBA-Logo-500x281.png",
"id": "NBA.Basketball.Dummy.us",
},
"NCAA": {
"logo": "https://1000logos.net/wp-content/uploads/2021/12/NCAA-Logo-500x281.png",
"id": "Sports.Dummy.us",
},
"NFL": {
"logo": "https://1000logos.net/wp-content/uploads/2017/05/NFL-logo-500x338.png",
"id": "NFL.Dummy.us",
},
"NHL": {
"logo": "https://1000logos.net/wp-content/uploads/2017/05/NHL-Logo-500x333.png",
"id": "NHL.Hockey.Dummy.us",
},
"Pay-Per-View": {
"logo": "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png",
"id": "PPV.EVENTS.Dummy.us",
},
"Premier League": {
"logo": "https://1000logos.net/wp-content/uploads/2017/05/Premier-League-logo-500x210.png",
"id": "Premier.League.Dummy.us",
},
"Primera A": {
"logo": "https://b.fssta.com/uploads/application/soccer/competition-logos/ColombianPrimeraA.png",
"id": "Soccer.Dummy.us",
},
"Primeira Liga": {
"logo": "https://1000logos.net/wp-content/uploads/2022/01/Portuguese-Primeira-Liga-logo-500x281.png",
"id": "Soccer.Dummy.us",
},
"Serie A": {
"logo": "https://1000logos.net/wp-content/uploads/2019/01/Italian-Serie-A-Logo-500x281.png",
"id": "Soccer.Dummy.us",
},
"Soccer": {
"logo": "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png",
"id": "Soccer.Dummy.us",
},
"UEFA Champions League": {
"logo": "https://1000logos.net/wp-content/uploads/2022/01/UEFA-Champions-League-logo-500x281.png",
"id": "UEFA.Champions.League.Dummy.us",
},
"UFC": {
"logo": "https://1000logos.net/wp-content/uploads/2017/06/Logo-UFC-500x313.png",
"id": "UFC.Fight.Pass.Dummy.us",
},
"WNBA": {
"logo": "https://1000logos.net/wp-content/uploads/2018/09/logo-wnba-500x287.png",
"id": "WNBA.dummy.us",
},
"default": {
"logo": "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png",
"id": "Live.Event.us",
},
} }
alias_map = { alias_map = {
"Bundesliga": ["German Bundesliga", "Bundeslig"],
"F1": ["Formula 1", "Formula One"],
"La Liga": ["Spanish La Liga", "Laliga"],
"MLB": ["Major League Baseball", "Baseball"],
"MLS": ["Major League Soccer"], "MLS": ["Major League Soccer"],
"Moto GP": ["MotoGP"],
"NCAA": ["CBB", "CFB", "NCAAB", "NCAAF"], "NCAA": ["CBB", "CFB", "NCAAB", "NCAAF"],
"NFL": ["American Football", "USA NFL"],
"Premier League": ["EPL"], "Premier League": ["EPL"],
"Primeira Liga": ["Liga Portugal"],
"Soccer": ["Football", "World Cup", "World Cup Qualifiers", "UEFA Europa League"],
"UEFA Champions League": ["Champions League", "UCL"], "UEFA Champions League": ["Champions League", "UCL"],
"WNBA": ["NBA W"], "WNBA": ["NBA W"],
} }
for base, aliases in alias_map.items(): for base, aliases in alias_map.items():
for alias in aliases: for alias in aliases:
LOGOS[alias] = LOGOS[base] LEAGUES[alias] = LEAGUES[base]
def league_info(name: str) -> dict:
return LEAGUES.get(name, LEAGUES["default"])

View file

@ -39,7 +39,7 @@ async def get_base(client: httpx.AsyncClient, mirrors: list[str]) -> str | None:
async def safe_process_event( async def safe_process_event(
fn: Callable, fn: Callable,
url_num: int, url_num: int,
timeout: int | float = 20, timeout: int | float = 15,
log: logging.Logger | None = None, log: logging.Logger | None = None,
) -> Any | None: ) -> Any | None: