Compare commits

..

No commits in common. "17c574615d11f620d342c75fb3d49885fb38ba50" and "8df77c1f139f20513cf7cdc20fd50f8301386918" have entirely different histories.

11 changed files with 103873 additions and 101652 deletions

File diff suppressed because it is too large Load diff

200834
M3U8/TV.xml

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,7 @@
http://41.205.93.154/AandE/index.m3u8 http://41.205.93.154/AandE/index.m3u8
#EXTINF:-1 tvg-chno="2" tvg-id="ABC.National.Feed.us2" tvg-name="ABC" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s10003_dark_360w_270h.png" group-title="TV",ABC #EXTINF:-1 tvg-chno="2" tvg-id="ABC.National.Feed.us2" tvg-name="ABC" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s10003_dark_360w_270h.png" group-title="TV",ABC
http://stream.cammonitorplus.net/1762/index.m3u8?token=MnE3ZWg1YkgxdFdWZlo2c2hLMkltWnJhcFo1OHhxcXVyb2pKazZXaWxZRERxNEduaVp1UnBxU2VlWmF0ZnRlRGxaMm1zNStDbnJOOXFZMlhtcStybmc9PQ== http://stream.cammonitorplus.net/1790/index.m3u8?token=MnE3ZWg1YkgxdFdWZlo2c2hLMkltWnJhcFo1OHhxcXVyb2pKazZXaWxZRERxNEduaVp1UnBxU2VlWmF0ZnRlRGxaMm1zNStDbnJOOXFZMlhtcStybmc9PQ==
#EXTINF:-1 tvg-chno="3" tvg-id="ACC.Network.us2" tvg-name="ACC Network" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s111871_dark_360w_270h.png" group-title="TV",ACC Network #EXTINF:-1 tvg-chno="3" tvg-id="ACC.Network.us2" tvg-name="ACC Network" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s111871_dark_360w_270h.png" group-title="TV",ACC Network
http://23.239.31.26:8989/accnetwork/index.m3u8 http://23.239.31.26:8989/accnetwork/index.m3u8

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
import asyncio import asyncio
import re
from functools import partial from functools import partial
import feedparser import feedparser
from playwright.async_api import Browser, Page, TimeoutError from playwright.async_api import Browser, Page
from .utils import Cache, Time, get_logger, leagues, network from .utils import Cache, Time, get_logger, leagues, network
@ -25,30 +24,15 @@ VALID_SPORTS = [
"Basketball", "Basketball",
"Football", "Football",
"Ice Hockey", "Ice Hockey",
"Wrestling",
] ]
def fix_url(s: str) -> str | None:
pattern = re.compile(r"eventinfo\/(\d*)", re.I)
if not (match := pattern.search(s)):
return
elif not (event_id := match[1]).isalnum():
return
return f"https://cdn.livetv872.me/cache/links/en.{event_id}.html"
async def process_event( async def process_event(
url: str, url: str,
url_num: int, url_num: int,
page: Page, page: Page,
) -> str | None: ) -> str | None:
event_id_pattern = re.compile(r"&c=(\d*)", re.I)
captured: list[str] = [] captured: list[str] = []
got_one = asyncio.Event() got_one = asyncio.Event()
@ -62,33 +46,40 @@ async def process_event(
page.on("request", handler) page.on("request", handler)
try: try:
resp = await page.goto( await page.goto(
url, url,
wait_until="domcontentloaded", wait_until="domcontentloaded",
timeout=10_000, timeout=10_000,
) )
if resp.status != 200: await page.wait_for_timeout(1_500)
log.warning(f"URL {url_num}) Status Code: {resp.status}")
return
try: buttons = await page.query_selector_all(".lnktbj a[href*='webplayer']")
event_a = page.locator('a[title*="Aliez"]').first
href = await event_a.get_attribute("href", timeout=1_250) labels = await page.eval_on_selector_all(
except TimeoutError: ".lnktyt span",
"elements => elements.map(el => el.textContent.trim().toLowerCase())",
)
for btn, label in zip(buttons, labels):
if label in ["web", "youtube"]:
continue
if not (href := await btn.get_attribute("href")):
continue
break
else:
log.warning(f"URL {url_num}) No valid sources found.") log.warning(f"URL {url_num}) No valid sources found.")
return return
if (match := event_id_pattern.search(href)) and ( href = href if href.startswith("http") else f"https:{href}"
event_id := match[1]
).isalnum(): href.replace("livetv.sx", "livetv873.me")
event_url = f"https://emb.apl392.me/player/live.php?id={event_id}"
else:
event_url = href if href.startswith("http") else f"https:{href}"
await page.goto( await page.goto(
event_url, href,
wait_until="domcontentloaded", wait_until="domcontentloaded",
timeout=5_000, timeout=5_000,
) )
@ -139,7 +130,7 @@ async def refresh_xml_cache(now_ts: float) -> dict[str, dict[str, str | float]]:
if not (date := entry.get("published")): if not (date := entry.get("published")):
continue continue
if (not (link := entry.get("link"))) or (not (fixed_link := fix_url(link))): if not (link := entry.get("link")):
continue continue
if not (title := entry.get("title")): if not (title := entry.get("title")):
@ -160,7 +151,7 @@ async def refresh_xml_cache(now_ts: float) -> dict[str, dict[str, str | float]]:
"sport": sport, "sport": sport,
"league": league, "league": league,
"event": title, "event": title,
"link": fixed_link, "link": link.replace("livetv.sx", "livetv873.me"),
"event_ts": event_dt.timestamp(), "event_ts": event_dt.timestamp(),
"timestamp": now_ts, "timestamp": now_ts,
} }

View file

@ -19,17 +19,12 @@ BASE_URL = "https://pixelsport.tv"
async def get_api_data(page: Page) -> dict[str, list[dict, str, str]]: async def get_api_data(page: Page) -> dict[str, list[dict, str, str]]:
try: try:
resp = await page.goto( await page.goto(
url := urljoin(BASE_URL, "backend/livetv/events"), url := urljoin(BASE_URL, "backend/livetv/events"),
wait_until="domcontentloaded", wait_until="domcontentloaded",
timeout=6_000, timeout=6_000,
) )
if resp.status != 200:
log.warning(f"{url} Status Code: {resp.status}")
return {}
raw_json = await page.locator("pre").inner_text(timeout=5_000) raw_json = await page.locator("pre").inner_text(timeout=5_000)
except Exception as e: except Exception as e:
log.error(f'Failed to fetch "{url}": {e}') log.error(f'Failed to fetch "{url}": {e}')

View file

@ -93,16 +93,12 @@ async def process_event(
page.on("request", handler) page.on("request", handler)
try: try:
resp = await page.goto( await page.goto(
url, url,
wait_until="domcontentloaded", wait_until="domcontentloaded",
timeout=6_000, timeout=6_000,
) )
if resp.status != 200:
log.warning(f"URL {url_num}) Status Code: {resp.status}")
return
try: try:
if btn := await page.wait_for_selector( if btn := await page.wait_for_selector(
"button.streambutton:nth-of-type(1)", "button.streambutton:nth-of-type(1)",

View file

@ -54,7 +54,7 @@ def get_logger(name: str | None = None) -> logging.Logger:
LOG_DIR / "fetch.log", LOG_DIR / "fetch.log",
when="midnight", when="midnight",
interval=1, interval=1,
backupCount=1, backupCount=3,
encoding="utf-8", encoding="utf-8",
utc=False, utc=False,
) )

View file

@ -250,17 +250,12 @@ class Network:
page.on("request", handler) page.on("request", handler)
try: try:
resp = await page.goto( await page.goto(
url, url,
wait_until="domcontentloaded", wait_until="domcontentloaded",
timeout=6_000, timeout=6_000,
) )
if resp.status != 200:
log.warning(f"URL {url_num}) Status Code: {resp.status}")
return
wait_task = asyncio.create_task(got_one.wait()) wait_task = asyncio.create_task(got_one.wait())
try: try:

View file

@ -89,16 +89,12 @@ async def process_event(
page.on("request", handler) page.on("request", handler)
try: try:
resp = await page.goto( await page.goto(
url, url,
wait_until="domcontentloaded", wait_until="domcontentloaded",
timeout=8_000, timeout=8_000,
) )
if resp.status != 200:
log.warning(f"URL {url_num}) Status Code: {resp.status}")
return
await page.wait_for_timeout(2_000) await page.wait_for_timeout(2_000)
try: try:

View file

@ -1,10 +1,12 @@
## Base Log @ 2026-03-03 09:07 UTC ## Base Log @ 2026-03-02 09:06 UTC
### ✅ Working Streams: 160<br>❌ Dead Streams: 1 ### ✅ Working Streams: 158<br>❌ Dead Streams: 3
| Channel | Error (Code) | Link | | Channel | Error (Code) | Link |
| ------- | ------------ | ---- | | ------- | ------------ | ---- |
| CMT | HTTP Error (404) | `http://23.237.104.106:8080/USA_CMT/index.m3u8` |
| Golf Channel | HTTP Error (000) | `http://hardcoremedia.xyz/live/rabdsbmz/3731346838/258721.ts` | | Golf Channel | HTTP Error (000) | `http://hardcoremedia.xyz/live/rabdsbmz/3731346838/258721.ts` |
| NBC Sports California | HTTP Error (403) | `http://hardcoremedia.xyz/live/rabdsbmz/3731346838/136474.ts` |
--- ---
#### Base Channels URL #### Base Channels URL
``` ```