Compare commits

..

No commits in common. "befe6e3a0a4da89fdd9bdd20c41aee659ccd5a76" and "22f3a6775f20fa1895533117f29733cd7e18f674" have entirely different histories.

12 changed files with 116403 additions and 118135 deletions

File diff suppressed because it is too large Load diff

229254
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

@ -64,8 +64,7 @@ async def main() -> None:
asyncio.create_task(embedhd.scrape(hdl_brwsr)),
# asyncio.create_task(ppv.scrape(xtrnl_brwsr)),
asyncio.create_task(roxie.scrape(hdl_brwsr)),
asyncio.create_task(streamhub.scrape(xtrnl_brwsr)),
asyncio.create_task(watchfooty.scrape(xtrnl_brwsr)),
# asyncio.create_task(streamhub.scrape(hdl_brwsr)),
]
httpx_tasks = [
@ -81,11 +80,14 @@ async def main() -> None:
asyncio.create_task(totalsportek.scrape()),
asyncio.create_task(tvapp.scrape()),
asyncio.create_task(webcast.scrape()),
asyncio.create_task(livetvsx.scrape()),
]
await asyncio.gather(*(pw_tasks + httpx_tasks))
# others
# await livetvsx.scrape(xtrnl_brwsr)
await watchfooty.scrape(xtrnl_brwsr)
finally:
await hdl_brwsr.close()

View file

@ -1,7 +1,9 @@
import asyncio
import re
from functools import partial
from selectolax.parser import HTMLParser
import feedparser
from playwright.async_api import Browser, Page, TimeoutError
from .utils import Cache, Time, get_logger, leagues, network
@ -9,119 +11,192 @@ log = get_logger(__name__)
urls: dict[str, dict[str, str | float]] = {}
TAG = "LTVSX"
TAG = "LIVETVSX"
CACHE_FILE = Cache(TAG, exp=10_800)
BASE_URL = "https://livetv.sx/export/webmasters.php"
XML_CACHE = Cache(f"{TAG}-xml", exp=28_000)
BASE_URL = "https://cdn.livetv872.me/rss/upcoming_en.xml"
VALID_SPORTS = [
"MLB. Preseason",
"MLB",
"Basketball",
"Football",
"Ice Hockey",
"Wrestling",
]
async def process_event(url: str, url_num: int) -> tuple[str | None, str | None]:
nones = None, None
def fix_url(s: str) -> str | None:
pattern = re.compile(r"eventinfo\/(\d*)", re.I)
if not (ev_data_1 := await network.request(url, log=log)):
log.warning(f"URL {url_num}) Failed to load url. (EVD1)")
return nones
if not (match := pattern.search(s)):
return
soup_1 = HTMLParser(ev_data_1.content)
elif not (event_id := match[1]).isalnum():
return
for a_elem in soup_1.css("a"):
if not (src_title := a_elem.attributes.get("title")) or (
"aliez" not in src_title.lower()
):
continue
return f"https://cdn.livetv872.me/cache/links/en.{event_id}.html"
href = a_elem.attributes["href"]
event_url = href if href.startswith("http") else f"https:{href}"
break
async def process_event(
url: str,
url_num: int,
page: Page,
) -> str | None:
else:
log.warning(f"URL {url_num}) No valid sources found.")
return nones
captured: list[str] = []
if not (ev_data_2 := await network.request(event_url, log=log)):
log.warning(f"URL {url_num}) Failed to load url. (EVD2)")
return nones
got_one = asyncio.Event()
soup_2 = HTMLParser(ev_data_2.content)
ifr_1 = soup_2.css_first("tr > td > iframe")
if not ifr_1 or not (ifr_1_src := ifr_1.attributes.get("src")):
log.warning(f"URL {url_num}) No iframe element found.")
return nones
ifr_1_src = "".join(
(ifr_1_src if ifr_1_src.startswith("http") else f"https:{ifr_1_src}").split()
handler = partial(
network.capture_req,
captured=captured,
got_one=got_one,
)
if not (ev_data_3 := await network.request(ifr_1_src, log=log)):
log.warning(f"URL {url_num}) Failed to load url. (EVD3)")
return nones
page.on("request", handler)
pattern = re.compile(r'pl\.init\((\'|\")([^"]*)(\'|\")\)', re.I)
if not (match := pattern.search(ev_data_3.text)):
log.warning(f"URL {url_num}) No M3U8 source found.")
return nones
log.info(f"URL {url_num}) Captured M3U8")
m3u: str = match[2] if match[2].startswith("http") else f"https:{match[2]}"
return m3u, ifr_1_src
async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
events = []
php_data = await network.unvd_client.get(BASE_URL, params={"lang": "en"})
if php_data.status_code != 200:
log.warning("Failed to get php data.")
return events
soup = HTMLParser(php_data.content)
if not (table := soup.css_first("table.tbl")):
return events
for row in table.css("tr > td"):
if not (event_tbl := row.css_first("table")):
continue
sport_elem = event_tbl.css_first(".spr")
league_elem = event_tbl.css_first(".cmp")
link_elem = event_tbl.css_first("a.title")
event_id_elem = row.css_first("div[id^='el']")
if not (league_elem and sport_elem and link_elem and event_id_elem):
continue
elif not (event_id := event_id_elem.attributes.get("id")):
continue
sport = sport_elem.text(strip=True)
league = league_elem.text(strip=True)
event_name = link_elem.text(strip=True)
if f"[{sport} - {league}] {event_name} ({TAG})" in cached_keys:
continue
events.append(
{
"sport": sport,
"league": league,
"event": event_name,
"link": f"https://cdn.livetv872.me/cache/links/en.{event_id[2:]}.html",
}
try:
resp = await page.goto(
url,
wait_until="domcontentloaded",
timeout=10_000,
)
if not resp or resp.status != 200:
log.warning(
f"URL {url_num}) Status Code: {resp.status if resp else 'None'}"
)
return
try:
event_a = page.locator('a[title*="Aliez"]').first
href = await event_a.get_attribute("href", timeout=1_250)
except TimeoutError:
log.warning(f"URL {url_num}) No valid sources found.")
return
event_url = href if href.startswith("http") else f"https:{href}"
await page.goto(
event_url,
wait_until="domcontentloaded",
timeout=5_000,
)
wait_task = asyncio.create_task(got_one.wait())
try:
await asyncio.wait_for(wait_task, timeout=6)
except asyncio.TimeoutError:
log.warning(f"URL {url_num}) Timed out waiting for M3U8.")
return
finally:
if not wait_task.done():
wait_task.cancel()
try:
await wait_task
except asyncio.CancelledError:
pass
if captured:
log.info(f"URL {url_num}) Captured M3U8")
return captured[0]
log.warning(f"URL {url_num}) No M3U8 captured after waiting.")
return
except Exception as e:
log.warning(f"URL {url_num}) {e}")
return
finally:
page.remove_listener("request", handler)
async def refresh_xml_cache(now_ts: float) -> dict[str, dict[str, str | float]]:
log.info("Refreshing XML cache")
events = {}
if not (xml_data := await network.request(BASE_URL, log=log)):
return events
feed = feedparser.parse(xml_data.content)
for entry in feed.entries:
if not (date := entry.get("published")):
continue
if (not (link := entry.get("link"))) or (not (fixed_link := fix_url(link))):
continue
if not (title := entry.get("title")):
continue
if not (sport_sum := entry.get("summary")):
continue
sprt = sport_sum.split(".", 1)
sport, league = sprt[0], "".join(sprt[1:]).strip()
event_dt = Time.from_str(date)
if (key := f"[{sport} - {league}] {title} ({TAG})") in events:
continue
events[key] = {
"sport": sport,
"league": league,
"event": title,
"link": fixed_link,
"event_ts": event_dt.timestamp(),
"timestamp": now_ts,
}
return events
async def scrape() -> None:
async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
now = Time.clean(Time.now())
if not (events := XML_CACHE.load()):
events = await refresh_xml_cache(now.timestamp())
XML_CACHE.write(events)
start_ts = now.delta(hours=-1).timestamp()
end_ts = now.delta(minutes=5).timestamp()
live = []
for k, v in events.items():
if k in cached_keys:
continue
if (
v["sport"] not in VALID_SPORTS
and v["league"] not in VALID_SPORTS
and v["event"].lower() != "olympic games"
):
continue
if not start_ts <= v["event_ts"] <= end_ts:
continue
live.append(v)
return live
async def scrape(browser: Browser) -> None:
cached_urls = CACHE_FILE.load()
valid_urls = {k: v for k, v in cached_urls.items() if v["url"]}
@ -137,47 +212,50 @@ async def scrape() -> None:
if events := await get_events(cached_urls.keys()):
log.info(f"Processing {len(events)} new URL(s)")
now = Time.clean(Time.now())
async with network.event_context(browser, ignore_https=True) as context:
for i, ev in enumerate(events, start=1):
async with network.event_page(context) as page:
handler = partial(
process_event,
url=(link := ev["link"]),
url_num=i,
page=page,
)
for i, ev in enumerate(events, start=1):
handler = partial(
process_event,
url=(link := ev["link"]),
url_num=i,
)
url = await network.safe_process(
handler,
url_num=i,
semaphore=network.PW_S,
log=log,
timeout=20,
)
url, iframe = await network.safe_process(
handler,
url_num=i,
semaphore=network.HTTP_S,
log=log,
)
sport, league, event, ts = (
ev["sport"],
ev["league"],
ev["event"],
ev["event_ts"],
)
sport, league, event = (
ev["sport"],
ev["league"],
ev["event"],
)
key = f"[{sport} - {league}] {event} ({TAG})"
key = f"[{sport} - {league}] {event} ({TAG})"
tvg_id, logo = leagues.get_tvg_info(sport, event)
tvg_id, logo = leagues.get_tvg_info(sport, event)
entry = {
"url": url,
"logo": logo,
"base": "https://livetv.sx/enx/",
"timestamp": ts,
"id": tvg_id or "Live.Event.us",
"link": link,
}
entry = {
"url": url,
"logo": logo,
"base": iframe,
"timestamp": now.timestamp(),
"id": tvg_id or "Live.Event.us",
"link": link,
}
cached_urls[key] = entry
cached_urls[key] = entry
if url:
valid_count += 1
if url:
valid_count += 1
urls[key] = entry
urls[key] = entry
log.info(f"Collected and cached {valid_count - cached_count} new event(s)")

View file

@ -163,7 +163,7 @@ async def scrape() -> None:
url = await network.safe_process(
handler,
url_num=i,
semaphore=network.HTTP_S,
semaphore=network.PW_S,
log=log,
)

View file

@ -117,7 +117,7 @@ async def scrape() -> None:
url = await network.safe_process(
handler,
url_num=i,
semaphore=network.HTTP_S,
semaphore=network.PW_S,
log=log,
)

View file

@ -13,7 +13,9 @@ urls: dict[str, dict[str, str | float]] = {}
TAG = "STRMHUB"
CACHE_FILE = Cache(TAG, exp=28_800)
CACHE_FILE = Cache(TAG, exp=10_800)
HTML_FILE = Cache(f"{TAG}-html", exp=19_800)
BASE_URL = "https://livesports4u.net"
@ -114,78 +116,116 @@ async def process_event(
page.remove_listener("request", handler)
async def get_events() -> list[dict[str, str]]:
now = Time.clean(Time.now())
async def refresh_html_cache(
date: str,
sport_id: str,
ts: float,
) -> dict[str, dict[str, str | float]]:
tasks = [
network.request(
events = {}
if not (
html_data := await network.request(
urljoin(BASE_URL, f"events/{date}"),
params={"sport_id": sport_id},
log=log,
)
for date in [now.date(), now.delta(days=1).date()]
for sport_id in SPORT_ENDPOINTS
]
results = await asyncio.gather(*tasks)
events = []
if not (soups := [HTMLParser(html.content) for html in results if html]):
):
return events
for soup in soups:
for section in soup.css(".events-section"):
if not (sport_node := section.css_first(".section-titlte")):
soup = HTMLParser(html_data.content)
for section in soup.css(".events-section"):
if not (sport_node := section.css_first(".section-titlte")):
continue
sport = sport_node.text(strip=True)
for event in section.css(".section-event"):
event_name = "Live Event"
if teams := event.css_first(".event-competitors"):
home, away = teams.text(strip=True).split("vs.")
event_name = f"{away} vs {home}"
if not (event_button := event.css_first(".event-button a")) or not (
href := event_button.attributes.get("href")
):
continue
sport = sport_node.text(strip=True)
event_date = event.css_first(".event-countdown").attributes.get(
"data-start"
)
for event in section.css(".section-event"):
event_name = "Live Event"
event_dt = Time.from_str(event_date, timezone="UTC")
if teams := event.css_first(".event-competitors"):
home, away = teams.text(strip=True).split("vs.")
key = f"[{sport}] {event_name} ({TAG})"
event_name = f"{away} vs {home}"
if not (event_button := event.css_first(".event-button a")) or not (
href := event_button.attributes.get("href")
):
continue
event_date = event.css_first(".event-countdown").attributes.get(
"data-start"
)
event_dt = Time.from_str(event_date, timezone="UTC")
if event_dt.date() != now.date():
continue
events.append(
{
"sport": sport,
"event": event_name,
"link": href,
"timestamp": now.timestamp(),
}
)
events[key] = {
"sport": sport,
"event": event_name,
"link": href,
"event_ts": event_dt.timestamp(),
"timestamp": ts,
}
return events
async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
now = Time.clean(Time.now())
if not (events := HTML_FILE.load()):
log.info("Refreshing HTML cache")
tasks = [
refresh_html_cache(
date,
sport_id,
now.timestamp(),
)
for date in [now.date(), now.delta(days=1).date()]
for sport_id in SPORT_ENDPOINTS
]
results = await asyncio.gather(*tasks)
events = {k: v for data in results for k, v in data.items()}
HTML_FILE.write(events)
live = []
start_ts = now.delta(minutes=-30).timestamp()
end_ts = now.delta(minutes=30).timestamp()
for k, v in events.items():
if k in cached_keys:
continue
if not start_ts <= v["event_ts"] <= end_ts:
continue
live.append(v)
return live
async def scrape(browser: Browser) -> None:
if cached_urls := CACHE_FILE.load():
urls.update({k: v for k, v in cached_urls.items() if v["url"]})
cached_urls = CACHE_FILE.load()
log.info(f"Loaded {len(urls)} event(s) from cache")
valid_urls = {k: v for k, v in cached_urls.items() if v["url"]}
return
valid_count = cached_count = len(valid_urls)
urls.update(valid_urls)
log.info(f"Loaded {cached_count} event(s) from cache")
log.info(f'Scraping from "{BASE_URL}"')
if events := await get_events():
if events := await get_events(cached_urls.keys()):
log.info(f"Processing {len(events)} new URL(s)")
async with network.event_context(browser) as context:
@ -209,7 +249,7 @@ async def scrape(browser: Browser) -> None:
sport, event, ts = (
ev["sport"],
ev["event"],
ev["timestamp"],
ev["event_ts"],
)
key = f"[{sport}] {event} ({TAG})"
@ -228,11 +268,13 @@ async def scrape(browser: Browser) -> None:
cached_urls[key] = entry
if url:
valid_count += 1
entry["url"] = url.split("?st")[0]
urls[key] = entry
log.info(f"Collected and cached {len(urls)} new event(s)")
log.info(f"Collected and cached {valid_count - cached_count} new event(s)")
else:
log.info("No new events found")

View file

@ -2,6 +2,7 @@ import asyncio
import re
from functools import partial
from itertools import chain
from typing import Any
from urllib.parse import urljoin
from selectolax.parser import HTMLParser
@ -14,7 +15,9 @@ urls: dict[str, dict[str, str | float]] = {}
TAG = "STRMSGATE"
CACHE_FILE = Cache(TAG, exp=28_800)
CACHE_FILE = Cache(TAG, exp=10_800)
API_FILE = Cache(f"{TAG}-api", exp=19_800)
BASE_URL = "https://streamsgates.io"
@ -82,17 +85,36 @@ async def process_event(url: str, url_num: int) -> tuple[str | None, str | None]
return match[3], ifr_src
async def get_events() -> list[dict[str, str]]:
now = Time.clean(Time.now())
async def refresh_api_cache(now_ts: float) -> list[dict[str, Any]]:
tasks = [network.request(url, log=log) for url in SPORT_URLS]
results = await asyncio.gather(*tasks)
if not (data := [*chain.from_iterable(r.json() for r in results if r)]):
return [{"timestamp": now_ts}]
for ev in data:
ev["ts"] = ev.pop("timestamp")
data[-1]["timestamp"] = now_ts
return data
async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
now = Time.clean(Time.now())
if not (api_data := API_FILE.load(per_entry=False, index=-1)):
log.info("Refreshing API cache")
api_data = await refresh_api_cache(now.timestamp())
API_FILE.write(api_data)
events = []
if not (api_data := [*chain.from_iterable(r.json() for r in results if r)]):
return events
start_dt = now.delta(hours=-2.5)
end_dt = now.delta(minutes=30)
for stream_group in api_data:
date = stream_group.get("time")
@ -101,30 +123,34 @@ async def get_events() -> list[dict[str, str]]:
t1, t2 = stream_group.get("away"), stream_group.get("home")
if not (date and sport):
continue
event_dt = Time.from_str(date, timezone="UTC")
if event_dt.date() != now.date():
continue
if not (streams := stream_group.get("streams")) or not (
url := streams[0].get("url")
):
continue
if not (t1 and t2):
continue
event = get_event(t1, t2)
if not (date and sport):
continue
if f"[{sport}] {event} ({TAG})" in cached_keys:
continue
event_dt = Time.from_str(date, timezone="UTC")
if not start_dt <= event_dt <= end_dt:
continue
if not (streams := stream_group.get("streams")):
continue
if not (url := streams[0].get("url")):
continue
events.append(
{
"sport": sport,
"event": event,
"link": url,
"timestamp": now.timestamp(),
"timestamp": event_dt.timestamp(),
}
)
@ -132,16 +158,19 @@ async def get_events() -> list[dict[str, str]]:
async def scrape() -> None:
if cached_urls := CACHE_FILE.load():
urls.update({k: v for k, v in cached_urls.items() if v["url"]})
cached_urls = CACHE_FILE.load()
log.info(f"Loaded {len(urls)} event(s) from cache")
valid_urls = {k: v for k, v in cached_urls.items() if v["url"]}
return
valid_count = cached_count = len(valid_urls)
urls.update(valid_urls)
log.info(f"Loaded {cached_count} event(s) from cache")
log.info(f'Scraping from "{BASE_URL}"')
if events := await get_events():
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):
@ -154,7 +183,7 @@ async def scrape() -> None:
url, iframe = await network.safe_process(
handler,
url_num=i,
semaphore=network.HTTP_S,
semaphore=network.PW_S,
log=log,
)
@ -180,11 +209,11 @@ async def scrape() -> None:
cached_urls[key] = entry
if url:
entry["url"] = url.split("?st")[0]
valid_count += 1
urls[key] = entry
log.info(f"Collected and cached {len(urls)} new event(s)")
log.info(f"Collected and cached {valid_count - cached_count} new event(s)")
else:
log.info("No new events found")

View file

@ -38,16 +38,12 @@ class Network:
PW_S = asyncio.Semaphore(3)
def __init__(self) -> None:
client_params = {
"timeout": httpx.Timeout(5.0),
"follow_redirects": True,
"headers": {"User-Agent": Network.UA},
"http2": True,
}
self.client = httpx.AsyncClient(**client_params)
self.unvd_client = httpx.AsyncClient(**client_params, verify=False)
self.client = httpx.AsyncClient(
timeout=httpx.Timeout(5.0),
follow_redirects=True,
headers={"User-Agent": Network.UA},
http2=True,
)
async def request(
self,

View file

@ -157,7 +157,7 @@ async def scrape() -> None:
url = await network.safe_process(
handler,
url_num=i,
semaphore=network.HTTP_S,
semaphore=network.PW_S,
log=log,
)

View file

@ -1,89 +1,20 @@
## Base Log @ 2026-04-22 15:48 UTC
## Base Log @ 2026-04-21 16:32 UTC
### ✅ Working Streams: 81<br>❌ Dead Streams: 80
### ✅ Working Streams: 150<br>❌ Dead Streams: 11
| Channel | Error (Code) | Link |
| ------- | ------------ | ---- |
| Aspire | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/150605.ts` |
| C-SPAN | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/14804.ts` |
| CBS Sports Network | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/267357.ts` |
| CNBC | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2295.ts` |
| CW | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/171820.ts` |
| Cleo TV | HTTP Error (401) | `http://supersonictv.live:8080/317136/Kennzack1218/86101` |
| Comedy TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/199482.ts` |
| Cozi TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/8392.ts` |
| Discovery Family Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2300.ts` |
| Discovery Life | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/201208.ts` |
| Discovery Science | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2301.ts` |
| Disney | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2303.ts` |
| ESPN News | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2312.ts` |
| ESPN2 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/41918.ts` |
| FDSN Detroit | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/6463.ts` |
| FDSN Florida | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/296662.ts` |
| FDSN Midwest | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/58557.ts` |
| FDSN Ohio | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/296675.ts` |
| FDSN Oklahoma | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/6452.ts` |
| FDSN North | HTTP Error (444) | `http://mytvstream.net:8080/live/5AGbfz/324331/20928.m3u8` |
| FDSN SoCal | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/296681.ts` |
| FDSN South | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/277374.ts` |
| FDSN Southeast | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/82301.ts` |
| FDSN Southwest | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/296685.ts` |
| FDSN Sun | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2325.ts` |
| FDSN West | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/3367.ts` |
| FDSN Wisconsin | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/295668.ts` |
| FX Movie Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/39873.ts` |
| FYI TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/9234.ts` |
| Fox News | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/1611.ts` |
| Fox Sports 1 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/756.ts` |
| Fox Sports 2 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/757.ts` |
| Freeform TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2329.ts` |
| Game Show Network | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/466.ts` |
| Golf Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/5845.ts` |
| Grit TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/15086.ts` |
| HBO Family | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/760.ts` |
| Hallmark Family | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/304609.ts` |
| Hallmark Mystery | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/3388.ts` |
| History Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/761.ts` |
| INSP | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/30900.ts` |
| ION TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/147661.ts` |
| Investigation Discovery | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/8557.ts` |
| Lifetime | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/4667.ts` |
| MLB Network | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2342.ts` |
| MSNBC | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/406.ts` |
| Marquee Sports Network | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/150609.ts` |
| MotorTrend TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/272264.ts` |
| NBA TV | HTTP Error (404) | `http://212.102.60.231/NBA_TV/index.m3u8` |
| NBC Sports Bay Area | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/45785.ts` |
| NBC Sports Boston | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/35132.ts` |
| NBC Sports California | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/16116.ts` |
| NBC Sports Philadelphia | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/35472.ts` |
| NFL RedZone | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2369.ts` |
| NHL Network | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2348.ts` |
| National Geographic | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/749.ts` |
| NewsNation | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/6296.ts` |
| Nick Jr | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/14835.ts` |
| Ovation | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/194336.ts` |
| Oxygen | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/6378.ts` |
| Pop TV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/305494.ts` |
| Premier Sports 1 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/1097.ts` |
| Premier Sports 2 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/4723.ts` |
| Showtime Extreme | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/12036.ts` |
| Sky Sports News | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/304775.ts` |
| Smithsonian Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/8585.ts` |
| Sony Movie Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/5831.ts` |
| SportsNet New York | HTTP Error (404) | `http://212.102.60.231/SNY/index.m3u8` |
| SportsNet Pittsburgh | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/59945.ts` |
| Sportsnet 360 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/3377.ts` |
| Sportsnet East | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/1720.ts` |
| Sportsnet One | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/3378.ts` |
| TLC | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2362.ts` |
| TSN1 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/770.ts` |
| TSN2 | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/771.ts` |
| TV Land | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2364.ts` |
| TV One | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/13010.ts` |
| The Weather Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/2361.ts` |
| USA East | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/3390.ts` |
| Willow Cricket | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/296763.ts` |
| getTV | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/194187.ts` |
| NBC Sports Bay Area | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/45785.ts` |
| Smithsonian Channel | HTTP Error (404) | `http://iptvtree.net:8080/live/7e4b0dbd/1dd755dc3f/8585.ts` |
---
#### Base Channels URL
```