Compare commits

...

32 commits

Author SHA1 Message Date
GitHub Actions Bot
1394bf91d0 update M3U8 2026-05-30 19:31:33 -04:00
GitHub Actions Bot
18f772b592 update M3U8 2026-05-30 19:03:26 -04:00
GitHub Actions Bot
8131d48b66 update M3U8 2026-05-30 18:31:37 -04:00
GitHub Actions Bot
2ff72522eb update M3U8 2026-05-30 18:00:42 -04:00
GitHub Actions Bot
39b652ea9d update M3U8 2026-05-30 17:31:10 -04:00
GitHub Actions Bot
a089dbadd2 update M3U8 2026-05-30 17:00:39 -04:00
GitHub Actions Bot
bd4c419ce5 update M3U8 2026-05-30 16:30:54 -04:00
GitHub Actions Bot
146f7846c7 update M3U8 2026-05-30 16:01:19 -04:00
GitHub Actions Bot
1e522b342c update EPG 2026-05-30 19:55:58 +00:00
GitHub Actions Bot
b3d1359cf6 update M3U8 2026-05-30 15:31:15 -04:00
GitHub Actions Bot
8acec8d46a update M3U8 2026-05-30 15:00:38 -04:00
GitHub Actions Bot
cfbe356d02 update M3U8 2026-05-30 14:31:09 -04:00
GitHub Actions Bot
7b65635d6c update M3U8 2026-05-30 14:00:44 -04:00
GitHub Actions Bot
8d15c3e082 update M3U8 2026-05-30 13:33:19 -04:00
GitHub Actions Bot
f890bcce9b update M3U8 2026-05-30 13:01:05 -04:00
GitHub Actions Bot
5e43b764af update M3U8 2026-05-30 12:15:00 -04:00
GitHub Actions Bot
bdf10dbe32 update M3U8 2026-05-30 12:00:36 -04:00
GitHub Actions Bot
f0a761a0cf health log 2026-05-30 15:45:14 +00:00
GitHub Actions Bot
e4da2cc648 update M3U8 2026-05-30 11:00:51 -04:00
GitHub Actions Bot
707fc15210 update M3U8 2026-05-30 10:01:18 -04:00
GitHub Actions Bot
9e4fe555f0 update M3U8 2026-05-30 09:00:35 -04:00
GitHub Actions Bot
a4342768aa update M3U8 2026-05-30 08:03:02 -04:00
GitHub Actions Bot
27ac770b69 health log 2026-05-30 10:22:50 +00:00
GitHub Actions Bot
1a1c6d40f4 update EPG 2026-05-30 06:05:09 +00:00
GitHub Actions Bot
dcd991345e update M3U8 2026-05-29 23:31:03 -04:00
GitHub Actions Bot
8ed63a6a48 update M3U8 2026-05-29 23:00:32 -04:00
GitHub Actions Bot
bbcb036f9b update M3U8 2026-05-29 22:31:06 -04:00
GitHub Actions Bot
3018367f2e update M3U8 2026-05-29 22:01:39 -04:00
GitHub Actions Bot
9f466cad28 update M3U8 2026-05-29 21:31:11 -04:00
GitHub Actions Bot
6174ed9712 update M3U8 2026-05-29 21:02:36 -04:00
GitHub Actions Bot
f93e44ebb2 update M3U8 2026-05-29 20:31:25 -04:00
GitHub Actions Bot
0f7b278311 update M3U8 2026-05-29 20:00:39 -04:00
7 changed files with 116624 additions and 117366 deletions

File diff suppressed because it is too large Load diff

229607
M3U8/TV.xml

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,6 @@ from scrapers import (
footfast,
fsports,
istreameast,
mainportal,
ovogoal,
roxie,
shark,
@ -68,8 +67,7 @@ async def main() -> None:
httpx_tasks = [
asyncio.create_task(fawa.scrape()),
asyncio.create_task(istreameast.scrape()),
# asyncio.create_task(mainportal.scrape()),
# asyncio.create_task(ovogoal.scrape()),
asyncio.create_task(ovogoal.scrape()),
asyncio.create_task(shark.scrape()),
asyncio.create_task(streamcenter.scrape()),
asyncio.create_task(streamsgate.scrape()),
@ -100,7 +98,6 @@ async def main() -> None:
| footfast.urls
| fsports.urls
| istreameast.urls
| mainportal.urls
| ovogoal.urls
| roxie.urls
| shark.urls

View file

@ -1,191 +0,0 @@
import asyncio
import json
import re
from functools import partial
from urllib.parse import urljoin
from .utils import Cache, Time, get_logger, leagues, network
log = get_logger(__name__)
urls: dict[str, dict[str, str | float]] = {}
TAG = "MP66"
CACHE_FILE = Cache(TAG, exp=10_800)
API_URLS = {
sport: f"https://api.{sport.lower()}24all.ir"
for sport in [
"MLB",
# "NBA",
# "NFL",
"NHL",
]
}
BASE_URLS = {sport: url.replace("api.", "") for sport, url in API_URLS.items()}
async def process_event(
sport: str,
flavor_id: str,
media_id: int,
url_num: int,
) -> str | None:
r = await network.client.post(
urljoin(API_URLS[sport], "api/v2/generate_stream_info"),
headers={"Referer": BASE_URLS[sport]},
json={"flavor_id": flavor_id, "media_event_id": media_id},
)
if r.status_code != 200:
log.warning(f"URL {url_num}) Failed to create post request.")
return
data: dict[str, str] = r.json()
if not (m3u8_url := data.get("url")):
log.warning(f"URL {url_num}) No M3U8 found")
return
log.info(f"URL {url_num}) Captured M3U8")
return m3u8_url
async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
tasks = [network.request(url, log=log) for url in BASE_URLS.values()]
results = await asyncio.gather(*tasks)
events = []
if not (html_data := [(html.text, html.url) for html in results if html]):
return events
now = Time.clean(Time.now())
stateshot_ptrn = re.compile(r"var\s+stateshot\s+=\s+(.*);", re.I)
start_dt = now.delta(hours=-1)
end_dt = now.delta(minutes=1)
for content, url in html_data:
sport = next((k for k, v in BASE_URLS.items() if v == url), "Live Event")
if not (match := stateshot_ptrn.search(content)):
continue
data: dict = json.loads(f"{match[1]}")
teams = data.get("teams", {})
flavors = data.get("flavors", {})
media_events = data.get("media_events", {})
team_identifier: dict[int, str] = {t.get("id"): t.get("name") for t in teams}
event_to_flavor_id: dict[int, str] = {
event_id: flavor["id"]
for flavor in flavors
for event_id in flavor.get("media_event_ids", [])
}
parsed_media_events: dict[int, int] = {
x.get("game_id"): x.get("id") for x in media_events
}
for game in data.get("games", {}):
game_id = game["id"]
event_dt = Time.fromisoformat(game["datetime"]).to_tz("EST")
if not start_dt <= event_dt <= end_dt:
continue
away = team_identifier.get(game["away_team_id"])
home = team_identifier.get(game["home_team_id"])
if f"[{sport}] {(event_name:=f"{away} vs {home}")} ({TAG})" in cached_keys:
continue
media_id = parsed_media_events.get(game_id, 0)
if (flavor_id := event_to_flavor_id.get(media_id)) and (
flavor_id.lower().startswith("free.live")
):
events.append(
{
"sport": sport,
"event": event_name,
"timestamp": event_dt.timestamp(),
"flavor_id": flavor_id,
"media_id": media_id,
}
)
return events
async def scrape() -> None:
cached_urls = CACHE_FILE.load()
valid_urls = {k: v for k, v in cached_urls.items() if v["url"]}
valid_count = cached_count = len(valid_urls)
urls.update(valid_urls)
log.info(f"Loaded {cached_count} event(s) from cache")
log.info('Scraping from "https://mainportal66.com"')
if events := await get_events(cached_urls.keys()):
log.info(f"Processing {len(events)} new URL(s)")
for i, ev in enumerate(events, start=1):
handler = partial(
process_event,
sport=(sport := ev["sport"]),
flavor_id=ev["flavor_id"],
media_id=ev["media_id"],
url_num=i,
)
url = await network.safe_process(
handler,
url_num=i,
semaphore=network.HTTP_S,
log=log,
)
event, ts = ev["event"], ev["timestamp"]
key = f"[{sport}] {event} ({TAG})"
tvg_id, logo = leagues.get_tvg_info(sport, event)
entry = {
"url": url,
"logo": logo,
"base": BASE_URLS[sport],
"timestamp": ts,
"id": tvg_id or "Live.Event.us",
}
cached_urls[key] = entry
if url:
valid_count += 1
urls[key] = entry
log.info(f"Collected and cached {valid_count - cached_count} new event(s)")
else:
log.info("No new events found")
CACHE_FILE.write(cached_urls)

View file

@ -8,13 +8,21 @@ TAG = "XYZSTRM"
CACHE_FILE = Cache(TAG, exp=28_800)
BASE_URL = "https://xyzstreams.shop"
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)):
if not (
r := await network.request(
API_URL,
headers={"Referer": BASE_URL},
log=log,
)
):
return events
now = Time.clean(Time.now())
@ -49,7 +57,7 @@ async def get_events() -> dict[str, dict[str, str | float]]:
events[key] = {
"url": feed,
"logo": logo,
"base": "https://xyzstreams.shop",
"base": BASE_URL,
"timestamp": now.timestamp(),
"id": tvg_id or "Live.Event.us",
}
@ -65,7 +73,7 @@ async def scrape() -> None:
return
log.info('Scraping from "https://xyzstreams.shop"')
log.info(f'Scraping from "{BASE_URL}"')
urls.update(await get_events() or {})

View file

@ -1,15 +1,16 @@
## Base Log @ 2026-05-29 22:13 UTC
## Base Log @ 2026-05-30 15:45 UTC
### ✅ Working Streams: 149<br>❌ Dead Streams: 8
### ✅ Working Streams: 148<br>❌ Dead Streams: 9
| Channel | Error (Code) | Link |
| ------- | ------------ | ---- |
| FDSN Detroit | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/317.ts` |
| FDSN North | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/320.ts` |
| FDSN Ohio | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/1207.ts` |
| FDSN SoCal | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/665.ts` |
| FDSN South | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/319.ts` |
| FDSN Southeast | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/872.ts` |
| FDSN Sun | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/322.ts` |
| FDSN West | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/1633.ts` |
| FDSN Wisconsin | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/1621.ts` |
| Lifetime | HTTP Error (403) | `http://cdn1host.online:2999/live/bongus/35zqYxrbg0/148.ts` |
| MSNBC | HTTP Error (404) | `http://41.205.93.154:80/MSNBC/index.m3u8` |
---