diff --git a/M3U8/fetch.py b/M3U8/fetch.py index 52cc3faf..49103aba 100644 --- a/M3U8/fetch.py +++ b/M3U8/fetch.py @@ -22,6 +22,7 @@ from scrapers import ( tvapp, watchfooty, webcast, + xyzstream, ) from scrapers.utils import get_logger, network @@ -76,6 +77,7 @@ async def main() -> None: # asyncio.create_task(totalsportek.scrape()), asyncio.create_task(tvapp.scrape()), asyncio.create_task(webcast.scrape()), + asyncio.create_task(xyzstream.scrape()), ] await asyncio.gather(*(pw_tasks + httpx_tasks)) @@ -109,6 +111,7 @@ async def main() -> None: | tvapp.urls | watchfooty.urls | webcast.urls + | xyzstream.urls ) live_events: list[str] = [] diff --git a/M3U8/scrapers/totalsportek.py b/M3U8/scrapers/totalsportek.py index 16612d98..adc2fa42 100644 --- a/M3U8/scrapers/totalsportek.py +++ b/M3U8/scrapers/totalsportek.py @@ -16,8 +16,8 @@ TAG = "TSPRTK" CACHE_FILE = Cache(TAG, exp=19_800) BASES = { - "TSPRTK1": "https://live.totalsportek.fyi", - "TSPRTK3": "https://live3.totalsportek.fyi", + "TSPRTK1": "https://live.totalsportek.rodeo", + "TSPRTK3": "https://live3.totalsportek.rodeo", } @@ -69,7 +69,7 @@ async def process_ts3(ifr_src: str, url_num: int) -> str | None: log.warning(f"URL {url_num}) Failed to load iframe source. (IFR2)") return - valid_m3u8 = re.compile(r'currentStreamUrl\s+=\s+"([^"]*)"', re.I) + valid_m3u8 = re.compile(r'StreamUrl\s+=\s+"([^"]*)"', re.I) if not (match := valid_m3u8.search(ifr_2_src_data.text)): log.warning(f"URL {url_num}) No Clappr source found.") diff --git a/M3U8/scrapers/xyzstream.py b/M3U8/scrapers/xyzstream.py new file mode 100644 index 00000000..b61c1679 --- /dev/null +++ b/M3U8/scrapers/xyzstream.py @@ -0,0 +1,74 @@ +from .utils import Cache, Time, get_logger, leagues, network + +log = get_logger(__name__) + +urls: dict[str, dict[str, str | float]] = {} + +TAG = "XYZSTRM" + +CACHE_FILE = Cache(TAG, exp=28_800) + +API_URL = "https://blog.xyzstreams.shop:2053/api/scoreboard" + + +async def get_events() -> dict[str, dict[str, str | float]]: + events = {} + + if not (r := await network.request(API_URL, log=log)): + return events + + now = Time.clean(Time.now()) + + api_data: list[dict[str, str | dict]] = r.json() + + sport = "Live Event" + + for event_info in api_data: + away_team: str = event_info.get("away", {}).get("name") + home_team: str = event_info.get("home", {}).get("name") + event_date: str = event_info.get("gameDate") + + if not (event_date and away_team and home_team): + continue + + event_dt = Time.fromisoformat(event_date) + + if event_dt.date() != now.date(): + continue + + if not (feeds := event_info.get("feeds")): + continue + + event_name = f"{away_team} vs {home_team}" + + for i, feed in enumerate(feeds.values(), start=1): + key = f"[{sport}] {event_name} {i} ({TAG})" + + tvg_id, logo = leagues.get_tvg_info(sport, event_name) + + events[key] = { + "url": feed, + "logo": logo, + "base": "", + "timestamp": now.timestamp(), + "id": tvg_id or "Live.Event.us", + } + + return events + + +async def scrape() -> None: + if cached := CACHE_FILE.load(): + urls.update(cached) + + log.info(f"Loaded {len(urls)} event(s) from cache") + + return + + log.info('Scraping from "https://xyzstreams.shop"') + + urls.update(await get_events() or {}) + + log.info(f"Collected and cached {len(urls)} new event(s)") + + CACHE_FILE.write(urls)