e
This commit is contained in:
parent
5a61e2a8d5
commit
00000d9db0
11 changed files with 809 additions and 162 deletions
75
EPG/fetch.py
75
EPG/fetch.py
|
|
@ -39,21 +39,21 @@ dummies = {
|
|||
"Golf.Dummy.us": live_img,
|
||||
"Live.Event.us": live_img,
|
||||
"MLB.Baseball.Dummy.us": None,
|
||||
"MLS.Soccer.Dummy.us": None,
|
||||
"NBA.Basketball.Dummy.us": None,
|
||||
"NFL.Dummy.us": None,
|
||||
"NHL.Hockey.Dummy.us": None,
|
||||
"PPV.EVENTS.Dummy.us": live_img,
|
||||
"Premier.League.Dummy.us": None,
|
||||
"Racing.Dummy.us": None,
|
||||
"Soccer.Dummy.us": live_img,
|
||||
"Sports.Dummy.us": live_img,
|
||||
"Tennis.Dummy.us": None,
|
||||
"UEFA.Champions.League.Dummy.us": None,
|
||||
"UFC.Fight.Pass.Dummy.us": live_img,
|
||||
"WNBA.dummy.us": None,
|
||||
}
|
||||
|
||||
replace_ids = {
|
||||
"NCAA Sports": {"old": "Sports.Dummy.us", "new": "NCAA.Sports.Dummy.us"},
|
||||
"UFC": {"old": "UFC.247.Dummy.us", "new": "UFC.Dummy.us"},
|
||||
}
|
||||
|
||||
|
||||
async def fetch_xml(url: str) -> ET.Element:
|
||||
try:
|
||||
|
|
@ -71,10 +71,60 @@ async def fetch_xml(url: str) -> ET.Element:
|
|||
raise SystemExit(f'Failed to decompress and parse XML from "{url}"\n{e}') from e
|
||||
|
||||
|
||||
def hijack_id(
|
||||
old: str,
|
||||
new: str,
|
||||
text: str,
|
||||
root: ET.Element,
|
||||
) -> None:
|
||||
|
||||
og_channel = root.find(f"./channel[@id='{old}']")
|
||||
|
||||
if og_channel is not None:
|
||||
new_channel = ET.Element(og_channel.tag, {**og_channel.attrib, "id": new})
|
||||
|
||||
display_name = og_channel.find("display-name")
|
||||
|
||||
if display_name is not None:
|
||||
new_channel.append(ET.Element("display-name", display_name.attrib))
|
||||
new_channel[-1].text = text
|
||||
|
||||
for child in og_channel:
|
||||
if child.tag == "display-name":
|
||||
continue
|
||||
|
||||
new_child = ET.Element(child.tag, child.attrib)
|
||||
new_child.text = child.text
|
||||
|
||||
root.remove(og_channel)
|
||||
|
||||
root.append(new_channel)
|
||||
|
||||
for program in root.findall(f"./programme[@channel='{old}']"):
|
||||
new_program = ET.Element(program.tag, {**program.attrib, "channel": new})
|
||||
|
||||
for child in program:
|
||||
new_child = ET.Element(child.tag, child.attrib)
|
||||
new_child.text = child.text
|
||||
new_program.append(new_child)
|
||||
|
||||
for tag_name in ["title", "desc", "sub-title"]:
|
||||
tag = new_program.find(tag_name)
|
||||
|
||||
if tag is not None:
|
||||
tag.text = text
|
||||
|
||||
root.remove(program)
|
||||
|
||||
root.append(new_program)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
tvg_ids: dict[str, str] = json.loads(tvg_ids_file.read_text(encoding="utf-8"))
|
||||
|
||||
tvg_ids |= dummies
|
||||
additions = dummies | {v["old"]: live_img for _, v in replace_ids.items()}
|
||||
|
||||
tvg_ids |= additions
|
||||
|
||||
root = ET.Element("tv")
|
||||
|
||||
|
|
@ -100,15 +150,20 @@ async def main() -> None:
|
|||
tvg_id = program.get("channel")
|
||||
|
||||
if tvg_id in tvg_ids:
|
||||
if (title_text := program.find("title").text) in [
|
||||
"NHL Hockey",
|
||||
"Live: NFL Football",
|
||||
] and (subtitle := program.find("sub-title")) is not None:
|
||||
title_text = program.find("title").text
|
||||
subtitle = program.find("sub-title")
|
||||
|
||||
if (
|
||||
title_text in ["NHL Hockey", "Live: NFL Football"]
|
||||
and subtitle is not None
|
||||
):
|
||||
program.find("title").text = f"{title_text} {subtitle.text}"
|
||||
|
||||
root.append(program)
|
||||
|
||||
for k, v in replace_ids.items():
|
||||
hijack_id(**v, text=k, root=root)
|
||||
|
||||
tree = ET.ElementTree(root)
|
||||
|
||||
tree.write(epg_file, encoding="utf-8", xml_declaration=True)
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ async def main() -> None:
|
|||
base_m3u8, tvg_chno = vanilla_fetch()
|
||||
|
||||
tasks = [
|
||||
asyncio.create_task(fstv.main(CLIENT)),
|
||||
asyncio.create_task(livetvsx.main(CLIENT)),
|
||||
asyncio.create_task(ppv.main(CLIENT)),
|
||||
asyncio.create_task(streambtw.main(CLIENT)),
|
||||
asyncio.create_task(streameast.main(CLIENT)),
|
||||
asyncio.create_task(tvpass.main(CLIENT)),
|
||||
asyncio.create_task(fstv.scrape(CLIENT)),
|
||||
asyncio.create_task(livetvsx.scrape(CLIENT)),
|
||||
asyncio.create_task(ppv.scrape(CLIENT)),
|
||||
asyncio.create_task(streambtw.scrape(CLIENT)),
|
||||
asyncio.create_task(streameast.scrape(CLIENT)),
|
||||
asyncio.create_task(tvpass.scrape(CLIENT)),
|
||||
]
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
|
|
|
|||
|
|
@ -66,11 +66,11 @@ async def get_m3u8_links(client: httpx.AsyncClient, url: str) -> list[str]:
|
|||
|
||||
html = re.sub(r"<!--.*?-->", "", r.text, flags=re.DOTALL)
|
||||
|
||||
tree = HTMLParser(html)
|
||||
soup = HTMLParser(html)
|
||||
|
||||
m3u8_links = []
|
||||
|
||||
for btn in tree.css("button[onclick]"):
|
||||
for btn in soup.css("button[onclick]"):
|
||||
onclick = btn.attributes.get("onclick", "")
|
||||
|
||||
if match := re.search(r"src\s*=\s*['\"](.*?)['\"]", onclick):
|
||||
|
|
@ -79,7 +79,7 @@ async def get_m3u8_links(client: httpx.AsyncClient, url: str) -> list[str]:
|
|||
if ".m3u8" in link:
|
||||
m3u8_links.append(link)
|
||||
|
||||
if iframe := tree.css_first("iframe#iframe"):
|
||||
if iframe := soup.css_first("iframe#iframe"):
|
||||
src = iframe.attributes.get("src", "")
|
||||
|
||||
if ".m3u8" in src and src not in m3u8_links:
|
||||
|
|
@ -91,7 +91,7 @@ async def get_m3u8_links(client: httpx.AsyncClient, url: str) -> list[str]:
|
|||
return m3u8_links
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
if not (base_url := await get_base(client, MIRRORS)):
|
||||
log.warning("No working ace mirrors")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ async def process_event(
|
|||
return match_name, unquote(src).split("link=")[-1]
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10800)
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10_800)
|
||||
cached_hrefs = {entry["href"] for entry in cached_urls.values()}
|
||||
cached_count = len(cached_urls)
|
||||
urls.update(cached_urls)
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ async def process_event(url: str, url_num: int) -> str | None:
|
|||
return
|
||||
else:
|
||||
log.warning(f"URL {url_num}) Browser Links tab not found")
|
||||
return
|
||||
|
||||
link_img = await page.query_selector(
|
||||
"tr:nth-child(2) > td:nth-child(1) td:nth-child(6) img"
|
||||
|
|
@ -165,7 +166,7 @@ async def process_event(url: str, url_num: int) -> str | None:
|
|||
wait_task = asyncio.create_task(got_one.wait())
|
||||
|
||||
try:
|
||||
await asyncio.wait_for(wait_task, timeout=1.5e1)
|
||||
await asyncio.wait_for(wait_task, timeout=15)
|
||||
except asyncio.TimeoutError:
|
||||
log.warning(f"URL {url_num}) Timed out waiting for M3U8.")
|
||||
return
|
||||
|
|
@ -272,8 +273,8 @@ async def get_events(
|
|||
return events
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10800)
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10_800)
|
||||
cached_count = len(cached_urls)
|
||||
urls.update(cached_urls)
|
||||
|
||||
|
|
@ -307,10 +308,15 @@ async def main(client: httpx.AsyncClient) -> None:
|
|||
|
||||
key = f"[{sport}: {event}] {title} (LTVSX)"
|
||||
|
||||
tvg_id, logo = league_info(sport)
|
||||
|
||||
if not tvg_id:
|
||||
tvg_id, logo = league_info(event)
|
||||
|
||||
entry = {
|
||||
"url": url,
|
||||
"logo": league_info(sport)["logo"],
|
||||
"id": league_info(sport)["id"],
|
||||
"logo": logo,
|
||||
"id": tvg_id or "Live.Event.us",
|
||||
"base": "https://livetv.sx/enx/",
|
||||
"timestamp": now.timestamp(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
|
|
@ -40,6 +36,50 @@ MIRRORS = [
|
|||
"https://freeppv.fun",
|
||||
]
|
||||
|
||||
NFL_TEAMS = {
|
||||
"Arizona Cardinals",
|
||||
"Atlanta Falcons",
|
||||
"Baltimore Ravens",
|
||||
"Buffalo Bills",
|
||||
"Carolina Panthers",
|
||||
"Chicago Bears",
|
||||
"Cincinnati Bengals",
|
||||
"Cleveland Browns",
|
||||
"Dallas Cowboys",
|
||||
"Denver Broncos",
|
||||
"Detroit Lions",
|
||||
"Green Bay Packers",
|
||||
"Houston Texans",
|
||||
"Indianapolis Colts",
|
||||
"Jacksonville Jaguars",
|
||||
"Kansas City Chiefs",
|
||||
"Las Vegas Raiders",
|
||||
"Los Angeles Chargers",
|
||||
"Los Angeles Rams",
|
||||
"Miami Dolphins",
|
||||
"Minnesota Vikings",
|
||||
"New England Patriots",
|
||||
"New Orleans Saints",
|
||||
"New York Giants",
|
||||
"New York Jets",
|
||||
"Philadelphia Eagles",
|
||||
"Pittsburgh Steelers",
|
||||
"San Francisco 49ers",
|
||||
"Seattle Seahawks",
|
||||
"Tampa Bay Buccaneers",
|
||||
"Tennessee Titans",
|
||||
"Washington Redskins",
|
||||
}
|
||||
|
||||
|
||||
def is_nfl(event: str) -> bool:
|
||||
try:
|
||||
t1, t2 = event.split(" vs. ")
|
||||
|
||||
return t1 in NFL_TEAMS or t2 in NFL_TEAMS
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
async def refresh_api_cache(
|
||||
client: httpx.AsyncClient, url: str
|
||||
|
|
@ -110,14 +150,12 @@ async def process_event(url: str, url_num: int) -> str | None:
|
|||
|
||||
async def get_events(
|
||||
client: httpx.AsyncClient,
|
||||
api_url: str,
|
||||
base_url: str,
|
||||
cached_keys: set[str],
|
||||
) -> list[dict[str, str]]:
|
||||
|
||||
events: list[dict[str, str]] = []
|
||||
|
||||
base_url = re.match(r"(https?://.+?)/", api_url)[1]
|
||||
|
||||
if not (
|
||||
api_data := load_cache(
|
||||
API_FILE,
|
||||
|
|
@ -126,8 +164,9 @@ async def get_events(
|
|||
per_entry=False,
|
||||
)
|
||||
):
|
||||
api_data = await refresh_api_cache(client, api_url)
|
||||
API_FILE.write_text(json.dumps(api_data, indent=2), encoding="utf-8")
|
||||
api_data = await refresh_api_cache(client, urljoin(base_url, "api/streams"))
|
||||
|
||||
write_cache(API_FILE, api_data)
|
||||
|
||||
for stream_group in api_data["streams"]:
|
||||
sport = stream_group["category"]
|
||||
|
|
@ -168,8 +207,8 @@ async def get_events(
|
|||
return events
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10800)
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10_800)
|
||||
cached_count = len(cached_urls)
|
||||
urls.update(cached_urls)
|
||||
|
||||
|
|
@ -184,7 +223,7 @@ async def main(client: httpx.AsyncClient) -> None:
|
|||
|
||||
events = await get_events(
|
||||
client,
|
||||
urljoin(base_url, "api/streams"),
|
||||
base_url,
|
||||
set(cached_urls.keys()),
|
||||
)
|
||||
|
||||
|
|
@ -200,6 +239,11 @@ async def main(client: httpx.AsyncClient) -> None:
|
|||
if url:
|
||||
sport, event = ev["sport"], ev["event"]
|
||||
|
||||
if sport == "American Football":
|
||||
tvg_id = "NFL.Dummy.us" if is_nfl(event) else "NCAA.Sports.Dummy.us"
|
||||
else:
|
||||
tvg_id = league_info(sport)[0]
|
||||
|
||||
key = f"[{sport}] {event} (PPV)"
|
||||
|
||||
entry = {
|
||||
|
|
@ -207,7 +251,7 @@ async def main(client: httpx.AsyncClient) -> None:
|
|||
"logo": ev["logo"],
|
||||
"base": base_url,
|
||||
"timestamp": now.timestamp(),
|
||||
"id": league_info(sport)["id"],
|
||||
"id": tvg_id or "Live.Event.us",
|
||||
}
|
||||
|
||||
urls[key] = cached_urls[key] = entry
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ async def get_events(client: httpx.AsyncClient) -> list[dict[str, str]]:
|
|||
return events
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
if cached := load_cache(CACHE_FILE, exp=86400, nearest_hr=True):
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
if cached := load_cache(CACHE_FILE, exp=86_400, nearest_hr=True):
|
||||
urls.update(cached)
|
||||
log.info(f"Collected {len(urls)} event(s) from cache")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ async def get_events(
|
|||
return events
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10800)
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
cached_urls = load_cache(CACHE_FILE, exp=10_800)
|
||||
cached_count = len(cached_urls)
|
||||
urls.update(cached_urls)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ async def fetch_m3u8(client: httpx.AsyncClient) -> list[str]:
|
|||
return r.text.splitlines()
|
||||
|
||||
|
||||
async def main(client: httpx.AsyncClient) -> None:
|
||||
if cached := load_cache(CACHE_FILE, exp=86400, nearest_hr=True):
|
||||
async def scrape(client: httpx.AsyncClient) -> None:
|
||||
if cached := load_cache(CACHE_FILE, exp=86_400, nearest_hr=True):
|
||||
urls.update(cached)
|
||||
log.info(f"Collected {len(urls)} event(s) from cache")
|
||||
return
|
||||
|
|
@ -52,8 +52,10 @@ async def main(client: httpx.AsyncClient) -> None:
|
|||
if url.endswith("/hd"):
|
||||
key = f"[{sport}] {tvg_name} (TVP)"
|
||||
|
||||
channel = url.split("/")[-2]
|
||||
|
||||
entry = {
|
||||
"url": f"http://origin.thetvapp.to/hls/{url.split('/')[-2]}/mono.m3u8",
|
||||
"url": f"http://origin.thetvapp.to/hls/{channel}/mono.m3u8",
|
||||
"logo": league_info(sport)["logo"],
|
||||
"id": league_info(sport)["id"],
|
||||
"base": "https://tvpass.org",
|
||||
|
|
|
|||
|
|
@ -22,42 +22,15 @@ LEAGUES: dict[str, dict[str, str]] = json.loads(
|
|||
leagues_file.read_text(encoding="utf-8")
|
||||
)
|
||||
|
||||
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"],
|
||||
"Moto GP": ["MotoGP"],
|
||||
"NCAA": ["CBB", "CFB", "NCAAB", "NCAAF"],
|
||||
"NFL": ["American Football", "USA NFL"],
|
||||
"Premier League": ["EPL"],
|
||||
"Primeira Liga": ["Liga Portugal"],
|
||||
"Racing": ["Motorsports", "Motorsport"],
|
||||
"Soccer": [
|
||||
"Eredivisie",
|
||||
"FA WSL",
|
||||
"Football",
|
||||
"Liga I",
|
||||
"Liga Profesional Argentina",
|
||||
"Ligue 2",
|
||||
"NWSL",
|
||||
"UEFA Europa League",
|
||||
"World Cup",
|
||||
"World Cup Qualifiers",
|
||||
],
|
||||
"UEFA Champions League": ["Champions League", "UCL"],
|
||||
"WNBA": ["NBA W"],
|
||||
}
|
||||
|
||||
for k, v in LEAGUES.items():
|
||||
if not v["logo"]:
|
||||
LEAGUES[k]["logo"] = live_img
|
||||
def league_info(name: str) -> tuple[str | None, str]:
|
||||
league_name_map: dict[str, tuple[str, str]] = {
|
||||
league_name: (tvg_id, league_data.get("logo"))
|
||||
for tvg_id, leagues in LEAGUES.items()
|
||||
for league_entry in leagues
|
||||
for league_name, league_data in league_entry.items()
|
||||
}
|
||||
|
||||
for base, aliases in alias_map.items():
|
||||
for alias in aliases:
|
||||
LEAGUES[alias] = LEAGUES[base]
|
||||
tvg_id, logo = league_name_map.get(name, (None, None))
|
||||
|
||||
|
||||
def league_info(name: str) -> dict:
|
||||
return LEAGUES.get(name, LEAGUES["default"])
|
||||
return tvg_id, logo or live_img
|
||||
|
|
|
|||
|
|
@ -1,81 +1,648 @@
|
|||
{
|
||||
"Basketball": { "id": "Basketball.Dummy.us", "logo": null },
|
||||
"Bundesliga": {
|
||||
"id": "Soccer.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2020/09/Bundesliga-Logo-500x313.png"
|
||||
},
|
||||
"F1": {
|
||||
"id": "Racing.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2021/06/F1-logo-500x281.png"
|
||||
},
|
||||
"Golf.Dummy.us": { "id": "Golf.Dummy.us", "logo": null },
|
||||
"La Liga": {
|
||||
"id": "Soccer.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2019/01/Spanish-La-Liga-Logo-500x281.png"
|
||||
},
|
||||
"Ligue 1": {
|
||||
"id": "Soccer.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2019/01/Ligue-1-Logo-500x281.png"
|
||||
},
|
||||
"Basketball.Dummy.us": [
|
||||
{
|
||||
"Basketball": {
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2024/04/Basketball-Emoji-1536x864.png",
|
||||
"names": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"Golf.Dummy.us": [
|
||||
{
|
||||
"Golf": {
|
||||
"logo": "https://i.gyazo.com/14a883f22796f631e6f97c34dbeb6ada.png",
|
||||
"names": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"MLB.Baseball.Dummy.us": [
|
||||
{
|
||||
"MLB": {
|
||||
"id": "MLB.Baseball.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/04/MLB-Logo-500x281.png"
|
||||
},
|
||||
"MLS": {
|
||||
"id": "MLS.Soccer.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/10/MLS-logo-500x393.png"
|
||||
},
|
||||
"Moto GP": {
|
||||
"id": "Racing.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2021/03/MotoGP-Logo-500x281.png"
|
||||
},
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/mlb.png",
|
||||
"names": [
|
||||
"Baseball",
|
||||
"Major League Baseball"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"NBA.Basketball.Dummy.us": [
|
||||
{
|
||||
"NBA": {
|
||||
"id": "NBA.Basketball.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2025/08/Jerry-West-the-NBA-Logo-500x281.png"
|
||||
},
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nba.png",
|
||||
"names": [
|
||||
"National Basketball Association"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"NCAA.Sports.Dummy.us": [
|
||||
{
|
||||
"NCAA": {
|
||||
"id": "Sports.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2021/12/NCAA-Logo-500x281.png"
|
||||
},
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2021/12/NCAA-Logo-500x281.png",
|
||||
"names": [
|
||||
"CBB",
|
||||
"CFB",
|
||||
"NCAAB",
|
||||
"NCAAF"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"NFL.Dummy.us": [
|
||||
{
|
||||
"NFL": {
|
||||
"id": "NFL.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/05/NFL-logo-500x338.png"
|
||||
},
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nfl.png",
|
||||
"names": [
|
||||
"American Football",
|
||||
"National Football League",
|
||||
"USA NFL"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"NHL.Hockey.Dummy.us": [
|
||||
{
|
||||
"NHL": {
|
||||
"id": "NHL.Hockey.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/05/NHL-Logo-500x333.png"
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nhl.png",
|
||||
"names": [
|
||||
"Hockey",
|
||||
"National Hockey League"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"PPV.EVENTS.Dummy.us": [
|
||||
{
|
||||
"Pay Per View": {
|
||||
"logo": null,
|
||||
"names": [
|
||||
"PPV",
|
||||
"Pay-Per-View",
|
||||
"PayPerView"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Pay-Per-View": { "id": "PPV.EVENTS.Dummy.us", "logo": null },
|
||||
{
|
||||
"Wrestling": {
|
||||
"logo": null,
|
||||
"names": [
|
||||
"AEW",
|
||||
"WWE"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"Racing.Dummy.us": [
|
||||
{
|
||||
"F1": {
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2021/06/F1-logo-500x281.png",
|
||||
"names": [
|
||||
"Formula 1",
|
||||
"Formula One"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Moto GP": {
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2021/03/MotoGP-Logo-500x281.png",
|
||||
"names": [
|
||||
"MotoGP"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Racing": {
|
||||
"logo": null,
|
||||
"names": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"Soccer.Dummy.us": [
|
||||
{
|
||||
"2. Bundesliga": {
|
||||
"logo": "https://i.gyazo.com/6c343e57acf501f4df3502d7ec646897.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"3. Liga": {
|
||||
"logo": "https://i.gyazo.com/9f4f2e8370377b6214b4103003196de7.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"AFC Champions League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2200.png&scale=crop&cquality=40&location=origin&w=500&h=500",
|
||||
"names": [
|
||||
"ACL",
|
||||
"ACL Elite",
|
||||
"Asian Champions League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Africa Cup of Nations": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/76.png",
|
||||
"names": [
|
||||
"AFCON"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Austria 2 Liga": {
|
||||
"logo": "https://i.gyazo.com/5d1464502b841fef6e5d78c8b0764b52.png",
|
||||
"names": [
|
||||
"Admiral 2. Liga"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Austria Bundesliga": {
|
||||
"logo": "https://i.gyazo.com/83d851fb1110f1e395690403f9cf01bb.webp",
|
||||
"names": [
|
||||
"Admiral Bundesliga",
|
||||
"Federal League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Bundesliga": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/10.png",
|
||||
"names": [
|
||||
"Bundeslig",
|
||||
"German Bundesliga"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"CAF Champions League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2391.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"CONCACAF Champions League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2298.png",
|
||||
"names": [
|
||||
"CONCACAF Champions Cup"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"CONCACAF Gold Cup": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/59.png",
|
||||
"names": [
|
||||
"Copa Oro CONCACAF"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Canadian Premier League": {
|
||||
"logo": "https://i.gyazo.com/f61986e2ccfbf88f7d753b4e7f2c9fdc.png",
|
||||
"names": [
|
||||
"CPL",
|
||||
"CanPL"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Championship": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/24.png",
|
||||
"names": [
|
||||
"English Championship",
|
||||
"English Football League Championship",
|
||||
"Sky Bet Championship"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Copa América": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/83.png",
|
||||
"names": [
|
||||
"CONMEBOL Copa America",
|
||||
"CONMEBOL Copa América",
|
||||
"Copa America",
|
||||
"South American Football Championship"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Copa Libertadores": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/58.png",
|
||||
"names": [
|
||||
"CONMEBOL Libertadores",
|
||||
"Copa Libertadores de America",
|
||||
"Copa Libertadores de América",
|
||||
"Libertadores"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Copa Sudamericana": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/1208.png",
|
||||
"names": [
|
||||
"CONMEBOL Sudamericana",
|
||||
"Copa CONMEBOL Sudamericana"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"EFL League One": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/25.png",
|
||||
"names": [
|
||||
"English Football League One",
|
||||
"League One",
|
||||
"Sky Bet League One"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"EFL League Two": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/26.png",
|
||||
"names": [
|
||||
"English Football League Two",
|
||||
"League Two",
|
||||
"Sky Bet League Two"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Ekstraklasa": {
|
||||
"logo": "https://i.gyazo.com/362e31efdd0dad03b00858f4fb0901b5.png",
|
||||
"names": [
|
||||
"PKO Bank Polski Ekstraklasa",
|
||||
"Poland Ekstraklasa"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Eredivisie": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/11.png",
|
||||
"names": [
|
||||
"VriendenLoterij Eredivisie"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"FIFA Club World Cup": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/1932.png",
|
||||
"names": [
|
||||
"FIFA CWC"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Fifa World Cup": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/4.png",
|
||||
"names": [
|
||||
"FIFA WC",
|
||||
"WC"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Fifa's Women World Cup": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/60.png",
|
||||
"names": [
|
||||
"FIFA Women WC"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Football": {
|
||||
"logo": "https://i.gyazo.com/1c4aa937f5ea01b0f29bb27adb59884c.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"Frauen Bundesliga": {
|
||||
"logo": "https://i.gyazo.com/d13d4c0330be96801aa4b2d8b83d3a8f.png",
|
||||
"names": [
|
||||
"Google Pixel Frauen-Bundesliga",
|
||||
"Women's Federal League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"J1 League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2199.png",
|
||||
"names": [
|
||||
"J.League",
|
||||
"Japanese J.League",
|
||||
"Meiji Yasuda J1 League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"K League 1": {
|
||||
"logo": "https://i.gyazo.com/721eba6c954e2015d999ead7a0bd5c69.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"La Liga": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/15.png",
|
||||
"names": [
|
||||
"Campeonato Nacional de Liga de Primera Division",
|
||||
"Campeonato Nacional de Liga de Primera División",
|
||||
"LALIGA",
|
||||
"Laliga",
|
||||
"Primera Division",
|
||||
"Primera División",
|
||||
"Spanish LALIGA",
|
||||
"Spanish La Liga"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"La Liga 2": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/107.png",
|
||||
"names": [
|
||||
"Campeonato Nacional de Liga de Segunda Division",
|
||||
"Campeonato Nacional de Liga de Segunda División",
|
||||
"LaLiga 2",
|
||||
"Segunda Division",
|
||||
"Segunda División",
|
||||
"Spanish LALIGA 2",
|
||||
"Spanish La Liga 2"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Liga I": {
|
||||
"logo": "https://i.gyazo.com/3fd4b38d5263ca391e45850eb58d11e6.png",
|
||||
"names": [
|
||||
"Romania Liga 1",
|
||||
"Romania Liga I",
|
||||
"Romanian Liga 1",
|
||||
"Romanian Liga I",
|
||||
"SuperLiga",
|
||||
"Superliga"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Liga MX": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/22.png",
|
||||
"names": [
|
||||
"Liga BBVA MX",
|
||||
"Liga Mayor",
|
||||
"Mexican Liga BBVA MX",
|
||||
"Primera Division de Mexico",
|
||||
"Primera División de México"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Liga Profesional Argentina": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/1.png",
|
||||
"names": [
|
||||
"Argentine Primera Division",
|
||||
"Argentine Primera División",
|
||||
"Liga Profesional de Futbol",
|
||||
"Liga Profesional de Fútbol",
|
||||
"Primera Division",
|
||||
"Primera División",
|
||||
"Torneo Betano"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Ligue 1": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/9.png",
|
||||
"names": [
|
||||
"France Ligue 1",
|
||||
"French Ligue 1"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Ligue 2": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/96.png",
|
||||
"names": [
|
||||
"France Ligue 2",
|
||||
"French Ligue 2"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"MLS": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/19.png",
|
||||
"names": [
|
||||
"Major League Soccer"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"NWSL": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2323.png",
|
||||
"names": [
|
||||
"NWSL Women",
|
||||
"National Women's Soccer League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Premier League": {
|
||||
"id": "Premier.League.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/05/Premier-League-logo-500x210.png"
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/23.png",
|
||||
"names": [
|
||||
"EPL",
|
||||
"English Premier League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Primeira Liga": {
|
||||
"id": "Soccer.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2022/01/Portuguese-Primeira-Liga-logo-500x281.png"
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/14.png",
|
||||
"names": [
|
||||
"Liga Portugal",
|
||||
"Portuguese Primeira Liga"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Primera A": {
|
||||
"id": "Soccer.Dummy.us",
|
||||
"logo": "https://b.fssta.com/uploads/application/soccer/competition-logos/ColombianPrimeraA.png"
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/1543.png",
|
||||
"names": [
|
||||
"Colombian Primera A"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Racing": { "id": "Racing.Dummy.us", "logo": null },
|
||||
{
|
||||
"Primera B": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2295.png",
|
||||
"names": [
|
||||
"Colombian Primera B"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Scottish Premiership": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/45.png",
|
||||
"names": [
|
||||
"Premiership",
|
||||
"SPFL"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Serbia Superliga": {
|
||||
"logo": "https://i.gyazo.com/0992f078dcacfef489477fc7bb1f5220.webp",
|
||||
"names": [
|
||||
"Mozzart SuperLiga",
|
||||
"Serbian Super League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Serie A": {
|
||||
"id": "Soccer.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2019/01/Italian-Serie-A-Logo-500x281.png"
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/12.png",
|
||||
"names": [
|
||||
"Italian Serie A"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Soccer": { "id": "Soccer.Dummy.us", "logo": null },
|
||||
"Tennis": { "id": "Tennis.Dummy.us", "logo": null },
|
||||
{
|
||||
"Serie B": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/99.png",
|
||||
"names": [
|
||||
"Italian Serie B"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Soccer": {
|
||||
"logo": "https://i.gyazo.com/1c4aa937f5ea01b0f29bb27adb59884c.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"Super League Greece": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/98.png",
|
||||
"names": [
|
||||
"A1 Ethniki Katigoria",
|
||||
"Greece Super League",
|
||||
"Greek Super League",
|
||||
"Super League 1"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Süper Lig": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/18.png",
|
||||
"names": [
|
||||
"Super Lig",
|
||||
"SuperLig",
|
||||
"SüperLig",
|
||||
"Turkish Super Lig"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Turkey 1 Lig": {
|
||||
"logo": "https://i.gyazo.com/730673f84223a85c9b9ae66123907bba.png",
|
||||
"names": [
|
||||
"TFF 1. Lig",
|
||||
"Trendyol 1. Lig"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"UEFA Champions League": {
|
||||
"id": "UEFA.Champions.League.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2022/01/UEFA-Champions-League-logo-500x281.png"
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2.png",
|
||||
"names": [
|
||||
"Champions League",
|
||||
"UCL"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"UEFA Conference League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/20296.png",
|
||||
"names": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"UEFA Europa League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2310.png",
|
||||
"names": [
|
||||
"Europa League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"UEFA European Championship": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/74.png",
|
||||
"names": [
|
||||
"Euros",
|
||||
"UEFA Euros"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"UEFA Super Cup": {
|
||||
"logo": "https://i.gyazo.com/3b786181aba130321b85c0e2f9604652.png",
|
||||
"names": [
|
||||
"European Super Cup"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"UEFA Women's Champions League": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2408.png",
|
||||
"names": [
|
||||
"UCL Women",
|
||||
"UEFA Women",
|
||||
"Women's Champions League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"WSL": {
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/2314.png",
|
||||
"names": [
|
||||
"Barclay's Women's Super League",
|
||||
"English Women's Super League",
|
||||
"FA WSL",
|
||||
"Women's Super League"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"World Cup Qualifiers": {
|
||||
"logo": "https://i.gyazo.com/1c4aa937f5ea01b0f29bb27adb59884c.png",
|
||||
"names": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"Tennis.Dummy.us": [
|
||||
{
|
||||
"Tennis": {
|
||||
"logo": "https://i.gyazo.com/b5e83afc3a75dacfb831abe975fd3821.png",
|
||||
"names": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"UFC.247.Dummy.us": [
|
||||
{
|
||||
"UFC": {
|
||||
"id": "UFC.Fight.Pass.Dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/06/Logo-UFC-500x313.png"
|
||||
},
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2017/06/Logo-UFC-500x313.png",
|
||||
"names": [
|
||||
"UFC Fight Night"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"WNBA.dummy.us": [
|
||||
{
|
||||
"WNBA": {
|
||||
"id": "WNBA.dummy.us",
|
||||
"logo": "https://1000logos.net/wp-content/uploads/2018/09/logo-wnba-500x287.png"
|
||||
},
|
||||
"default": { "id": "Live.Event.us", "logo": null }
|
||||
"logo": "https://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/wnba.png",
|
||||
"names": [
|
||||
"NBA W",
|
||||
"Women's National Basketball Association"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue