mirror of
https://github.com/doms9/iptv.git
synced 2026-03-11 11:57:38 +01:00
Compare commits
41 commits
90ec2f586d
...
19731cc7c4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19731cc7c4 | ||
|
|
a8c83675b2 | ||
|
|
58c317904d | ||
|
|
0baef6611e | ||
|
|
bfde140286 | ||
|
|
a2b377565a | ||
|
|
0be3f34fc5 | ||
|
|
00000d9844 | ||
|
|
3875d181cd | ||
|
|
ad3ba8e34d | ||
|
|
00000d968d | ||
|
|
53686dcc16 | ||
|
|
00000d947f | ||
|
|
6f01743391 | ||
|
|
efe30de3e6 | ||
|
|
8a84ae350e | ||
|
|
13ab3b4d8c | ||
|
|
032d32825e | ||
|
|
51ca28fed2 | ||
|
|
00000d9d0f | ||
|
|
38357e05f4 | ||
|
|
47364423ae | ||
|
|
c9299aca00 | ||
|
|
10b509e86b | ||
|
|
de35a7c753 | ||
|
|
67ac4e9522 | ||
|
|
a570a49311 | ||
|
|
83a634c044 | ||
|
|
d13f34befd | ||
|
|
a65f6aa7d0 | ||
|
|
d1aed35616 | ||
|
|
1259360fd1 | ||
|
|
9f8c54952e | ||
|
|
97f83a149f | ||
|
|
67b1a30621 | ||
|
|
43b1d23f4c | ||
|
|
06d8992887 | ||
|
|
d5acde16f9 | ||
|
|
9e2f2a1790 | ||
|
|
12e9ea57fc | ||
|
|
e084124cd6 |
12 changed files with 107745 additions and 101218 deletions
2021
M3U8/TV.m3u8
2021
M3U8/TV.m3u8
File diff suppressed because it is too large
Load diff
204573
M3U8/TV.xml
204573
M3U8/TV.xml
File diff suppressed because one or more lines are too long
|
|
@ -28,10 +28,12 @@ http://fl1.moveonjoy.com/Aspire/index.m3u8
|
||||||
http://fl1.moveonjoy.com/BBC_AMERICA/index.m3u8
|
http://fl1.moveonjoy.com/BBC_AMERICA/index.m3u8
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="10" tvg-id="BBC.News.(North.America).HD.us2" tvg-name="BBC World News" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s89542_dark_360w_270h.png" group-title="TV",BBC World News
|
#EXTINF:-1 tvg-chno="10" tvg-id="BBC.News.(North.America).HD.us2" tvg-name="BBC World News" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s89542_dark_360w_270h.png" group-title="TV",BBC World News
|
||||||
http://fl1.moveonjoy.com/BBC_WORLD_NEWS/index.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/1723
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="11" tvg-id="BET.HD.us2" tvg-name="BET" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s10051_dark_360w_270h.png" group-title="TV",BET
|
#EXTINF:-1 tvg-chno="11" tvg-id="BET.HD.us2" tvg-name="BET" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s10051_dark_360w_270h.png" group-title="TV",BET
|
||||||
https://streamer1.nexgen.bz/BET/index.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/2071
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="12" tvg-id="Big.Ten.Network.HD.us2" tvg-name="Big Ten Network" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s56783_dark_360w_270h.png" group-title="TV",Big Ten Network
|
#EXTINF:-1 tvg-chno="12" tvg-id="Big.Ten.Network.HD.us2" tvg-name="Big Ten Network" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s56783_dark_360w_270h.png" group-title="TV",Big Ten Network
|
||||||
http://23.237.104.106:8080/USA_BTN/index.m3u8
|
http://23.237.104.106:8080/USA_BTN/index.m3u8
|
||||||
|
|
@ -148,7 +150,8 @@ http://mytvstream.net:8080/live/A1Jay5/362586/66795.m3u8
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/58827.m3u8
|
http://mytvstream.net:8080/live/A1Jay5/362586/58827.m3u8
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="50" tvg-id="FanDuel.Sports.Network.Ohio.(Cleveland).HDTV.us" tvg-name="FDSN Ohio" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s49691_dark_360w_270h.png" group-title="TV",FDSN Ohio
|
#EXTINF:-1 tvg-chno="50" tvg-id="FanDuel.Sports.Network.Ohio.(Cleveland).HDTV.us" tvg-name="FDSN Ohio" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s49691_dark_360w_270h.png" group-title="TV",FDSN Ohio
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/17752.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/222126
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="51" tvg-id="FanDuel.Sports.Network.Oklahoma.24/7.HDTV.(Tulsa).us" tvg-name="FDSN Oklahoma" tvg-logo="https://i.gyazo.com/80ad6fd142cd67f06eef58d9ce5aa72b.png" group-title="TV",FDSN Oklahoma
|
#EXTINF:-1 tvg-chno="51" tvg-id="FanDuel.Sports.Network.Oklahoma.24/7.HDTV.(Tulsa).us" tvg-name="FDSN Oklahoma" tvg-logo="https://i.gyazo.com/80ad6fd142cd67f06eef58d9ce5aa72b.png" group-title="TV",FDSN Oklahoma
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/20934.m3u8
|
http://mytvstream.net:8080/live/A1Jay5/362586/20934.m3u8
|
||||||
|
|
@ -157,13 +160,16 @@ http://mytvstream.net:8080/live/A1Jay5/362586/20934.m3u8
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/221151.m3u8
|
http://mytvstream.net:8080/live/A1Jay5/362586/221151.m3u8
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="53" tvg-id="FanDuel.Sports.Network.Southeast.HDTV.(Mont./Birm./Dothan/Mobile.AL).us" tvg-name="FDSN Southeast" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s20789_dark_360w_270h.png" group-title="TV",FDSN Southeast
|
#EXTINF:-1 tvg-chno="53" tvg-id="FanDuel.Sports.Network.Southeast.HDTV.(Mont./Birm./Dothan/Mobile.AL).us" tvg-name="FDSN Southeast" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s20789_dark_360w_270h.png" group-title="TV",FDSN Southeast
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/2213.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/222130
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="54" tvg-id="FanDuel.Sports.Network.Southwest.HDTV.24/7.(Main).us" tvg-name="FDSN Southwest" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s59629_dark_360w_270h.png" group-title="TV",FDSN Southwest
|
#EXTINF:-1 tvg-chno="54" tvg-id="FanDuel.Sports.Network.Southwest.HDTV.24/7.(Main).us" tvg-name="FDSN Southwest" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s59629_dark_360w_270h.png" group-title="TV",FDSN Southwest
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/21843.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/220452
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="55" tvg-id="FanDuel.Sports.Network.Sun.South.24/7.HDTV.(South.Marlins,.Rays,.Heat).us" tvg-name="FDSN Sun" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s61084_dark_360w_270h.png" group-title="TV",FDSN Sun
|
#EXTINF:-1 tvg-chno="55" tvg-id="FanDuel.Sports.Network.Sun.South.24/7.HDTV.(South.Marlins,.Rays,.Heat).us" tvg-name="FDSN Sun" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s61084_dark_360w_270h.png" group-title="TV",FDSN Sun
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/104917.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/222132
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="56" tvg-id="FanDuel.Sports.Network.West.HDTV.us" tvg-name="FDSN West" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s59627_dark_360w_270h.png" group-title="TV",FDSN West
|
#EXTINF:-1 tvg-chno="56" tvg-id="FanDuel.Sports.Network.West.HDTV.us" tvg-name="FDSN West" tvg-logo="https://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s59627_dark_360w_270h.png" group-title="TV",FDSN West
|
||||||
http://mytvstream.net:8080/live/A1Jay5/362586/20932.m3u8
|
http://mytvstream.net:8080/live/A1Jay5/362586/20932.m3u8
|
||||||
|
|
@ -211,7 +217,8 @@ https://fl1.moveonjoy.com/FXX/index.m3u8
|
||||||
http://fl1.moveonjoy.com/FYI/index.m3u8
|
http://fl1.moveonjoy.com/FYI/index.m3u8
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="71" tvg-id="Game.Show.Network.HD.us2" tvg-name="Game Show Network" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s14909_dark_360w_270h.png" group-title="TV",Game Show Network
|
#EXTINF:-1 tvg-chno="71" tvg-id="Game.Show.Network.HD.us2" tvg-name="Game Show Network" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s14909_dark_360w_270h.png" group-title="TV",Game Show Network
|
||||||
https://streamer1.nexgen.bz/GSN/index.m3u8
|
#EXTVLCOPT:http-user-agent=curl/8.5.0
|
||||||
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/1948
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="72" tvg-id="get.us2" tvg-name="getTV" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s82563_dark_360w_270h.png" group-title="TV",getTV
|
#EXTINF:-1 tvg-chno="72" tvg-id="get.us2" tvg-name="getTV" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s82563_dark_360w_270h.png" group-title="TV",getTV
|
||||||
http://fl1.moveonjoy.com/GET_TV/index.m3u8
|
http://fl1.moveonjoy.com/GET_TV/index.m3u8
|
||||||
|
|
@ -235,7 +242,7 @@ https://fl1.moveonjoy.com/HALLMARK_MOVIES_MYSTERIES/index.m3u8
|
||||||
http://fl1.moveonjoy.com/HBO/index.m3u8
|
http://fl1.moveonjoy.com/HBO/index.m3u8
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="79" tvg-id="HBO2.HD.us2" tvg-name="HBO 2" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s68140_dark_360w_270h.png" group-title="TV",HBO 2
|
#EXTINF:-1 tvg-chno="79" tvg-id="HBO2.HD.us2" tvg-name="HBO 2" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s68140_dark_360w_270h.png" group-title="TV",HBO 2
|
||||||
http://fl1.moveonjoy.com/HBO_2/index.m3u8
|
http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/2071
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="80" tvg-id="HBO.Comedy.HD.us2" tvg-name="HBO Comedy" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s59839_dark_360w_270h.png" group-title="TV",HBO Comedy
|
#EXTINF:-1 tvg-chno="80" tvg-id="HBO.Comedy.HD.us2" tvg-name="HBO Comedy" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s59839_dark_360w_270h.png" group-title="TV",HBO Comedy
|
||||||
http://fl1.moveonjoy.com/HBO_COMEDY/index.m3u8
|
http://fl1.moveonjoy.com/HBO_COMEDY/index.m3u8
|
||||||
|
|
@ -436,4 +443,4 @@ http://hardcoremedia.xyz:80/NW3Vk7xXwW/8375773282/129973
|
||||||
https://fl1.moveonjoy.com/VICELAND/index.m3u8
|
https://fl1.moveonjoy.com/VICELAND/index.m3u8
|
||||||
|
|
||||||
#EXTINF:-1 tvg-chno="146" tvg-id="Yes.Network.us2" tvg-name="YES Network" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s30017_dark_360w_270h.png" group-title="TV",YES Network
|
#EXTINF:-1 tvg-chno="146" tvg-id="Yes.Network.us2" tvg-name="YES Network" tvg-logo="http://schedulesdirect-api20141201-logos.s3.dualstack.us-east-1.amazonaws.com/stationLogos/s30017_dark_360w_270h.png" group-title="TV",YES Network
|
||||||
https://fl1.moveonjoy.com/YES_NETWORK/index.m3u8
|
https://fl1.moveonjoy.com/YES_NETWORK/index.m3u8
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ BASE_M3U8 = Path(__file__).parent / "base.m3u8"
|
||||||
|
|
||||||
EPG_FILE = Path(__file__).parent / "TV.xml"
|
EPG_FILE = Path(__file__).parent / "TV.xml"
|
||||||
|
|
||||||
EPG_URLS = [
|
LIVE_IMG = "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png"
|
||||||
|
|
||||||
|
EPG_URLS = {
|
||||||
"https://epgshare01.online/epgshare01/epg_ripper_CA2.xml.gz",
|
"https://epgshare01.online/epgshare01/epg_ripper_CA2.xml.gz",
|
||||||
"https://epgshare01.online/epgshare01/epg_ripper_DUMMY_CHANNELS.xml.gz",
|
"https://epgshare01.online/epgshare01/epg_ripper_DUMMY_CHANNELS.xml.gz",
|
||||||
"https://epgshare01.online/epgshare01/epg_ripper_FANDUEL1.xml.gz",
|
"https://epgshare01.online/epgshare01/epg_ripper_FANDUEL1.xml.gz",
|
||||||
|
|
@ -22,9 +24,7 @@ EPG_URLS = [
|
||||||
"https://epgshare01.online/epgshare01/epg_ripper_US2.xml.gz",
|
"https://epgshare01.online/epgshare01/epg_ripper_US2.xml.gz",
|
||||||
"https://epgshare01.online/epgshare01/epg_ripper_US_LOCALS1.xml.gz",
|
"https://epgshare01.online/epgshare01/epg_ripper_US_LOCALS1.xml.gz",
|
||||||
"https://i.mjh.nz/Roku/all.xml.gz",
|
"https://i.mjh.nz/Roku/all.xml.gz",
|
||||||
]
|
}
|
||||||
|
|
||||||
LIVE_IMG = "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png"
|
|
||||||
|
|
||||||
DUMMIES = {
|
DUMMIES = {
|
||||||
"Basketball.Dummy.us": LIVE_IMG,
|
"Basketball.Dummy.us": LIVE_IMG,
|
||||||
|
|
@ -48,39 +48,47 @@ REPLACE_IDs = {
|
||||||
|
|
||||||
|
|
||||||
def get_tvg_ids() -> dict[str, str]:
|
def get_tvg_ids() -> dict[str, str]:
|
||||||
base_m3u8 = BASE_M3U8.read_text(encoding="utf-8").splitlines()
|
tvg: dict[str, str] = {}
|
||||||
|
|
||||||
tvg = {}
|
for line in BASE_M3U8.read_text(encoding="utf-8").splitlines():
|
||||||
|
if not line.startswith("#EXTINF"):
|
||||||
|
continue
|
||||||
|
|
||||||
for line in base_m3u8:
|
tvg_id = re.search(r'tvg-id="([^"]*)"', line)
|
||||||
if line.startswith("#EXTINF"):
|
tvg_logo = re.search(r'tvg-logo="([^"]*)"', line)
|
||||||
tvg_id = re.search(r'tvg-id="([^"]*)"', line)[1]
|
|
||||||
tvg_logo = re.search(r'tvg-logo="([^"]*)"', line)[1]
|
|
||||||
|
|
||||||
tvg[tvg_id] = tvg_logo
|
if tvg_id:
|
||||||
|
tvg[tvg_id[1]] = tvg_logo[1] if tvg_logo else None
|
||||||
|
|
||||||
|
tvg |= DUMMIES
|
||||||
|
|
||||||
|
tvg |= {v["old"]: LIVE_IMG for v in REPLACE_IDs.values()}
|
||||||
|
|
||||||
return tvg
|
return tvg
|
||||||
|
|
||||||
|
|
||||||
async def fetch_xml(url: str) -> ET.Element | None:
|
async def fetch_xml(url: str) -> ET.Element | None:
|
||||||
if not (html_data := await network.request(url, log=log)):
|
if not (xml_data := await network.request(url, log=log)):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
decompressed_data = gzip.decompress(html_data.content)
|
log.info(f'Parsing XML from "{url}"')
|
||||||
|
|
||||||
return ET.fromstring(decompressed_data)
|
data = gzip.decompress(xml_data.content)
|
||||||
|
|
||||||
|
return ET.fromstring(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f'Failed to decompress and parse XML from "{url}": {e}')
|
log.error(f'Failed to parse from "{url}": {e}')
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def hijack_id(
|
def hijack_id(
|
||||||
|
root: ET.Element,
|
||||||
|
*,
|
||||||
old: str,
|
old: str,
|
||||||
new: str,
|
new: str,
|
||||||
text: str,
|
text: str,
|
||||||
root: ET.Element,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
og_channel = root.find(f"./channel[@id='{old}']")
|
og_channel = root.find(f"./channel[@id='{old}']")
|
||||||
|
|
@ -90,7 +98,7 @@ def hijack_id(
|
||||||
|
|
||||||
display_name = og_channel.find("display-name")
|
display_name = og_channel.find("display-name")
|
||||||
|
|
||||||
if display_name is not None:
|
if (display_name := og_channel.find("display-name")) is not None:
|
||||||
new_channel.append(ET.Element("display-name", display_name.attrib))
|
new_channel.append(ET.Element("display-name", display_name.attrib))
|
||||||
new_channel[-1].text = text
|
new_channel[-1].text = text
|
||||||
|
|
||||||
|
|
@ -114,9 +122,7 @@ def hijack_id(
|
||||||
new_program.append(new_child)
|
new_program.append(new_child)
|
||||||
|
|
||||||
for tag_name in ["title", "desc", "sub-title"]:
|
for tag_name in ["title", "desc", "sub-title"]:
|
||||||
tag = new_program.find(tag_name)
|
if (tag := new_program.find(tag_name)) is not None:
|
||||||
|
|
||||||
if tag is not None:
|
|
||||||
tag.text = text
|
tag.text = text
|
||||||
|
|
||||||
root.remove(program)
|
root.remove(program)
|
||||||
|
|
@ -129,48 +135,60 @@ async def main() -> None:
|
||||||
|
|
||||||
tvg_ids = get_tvg_ids()
|
tvg_ids = get_tvg_ids()
|
||||||
|
|
||||||
tvg_ids |= DUMMIES | {v["old"]: LIVE_IMG for v in REPLACE_IDs.values()}
|
parsed_tvg_ids: set[str] = set()
|
||||||
|
|
||||||
root = ET.Element("tv")
|
root = ET.Element("tv")
|
||||||
|
|
||||||
tasks = [fetch_xml(url) for url in EPG_URLS]
|
epgs = await asyncio.gather(*(fetch_xml(url) for url in EPG_URLS))
|
||||||
|
|
||||||
results = await asyncio.gather(*tasks)
|
|
||||||
|
|
||||||
for epg_data in results:
|
|
||||||
if epg_data is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
for epg_data in (epg for epg in epgs if epg is not None):
|
||||||
for channel in epg_data.findall("channel"):
|
for channel in epg_data.findall("channel"):
|
||||||
if (channel_id := channel.get("id")) in tvg_ids:
|
if (channel_id := channel.get("id")) not in tvg_ids:
|
||||||
for icon_tag in channel.findall("icon"):
|
continue
|
||||||
if logo := tvg_ids.get(channel_id):
|
|
||||||
icon_tag.set("src", logo)
|
|
||||||
|
|
||||||
if (url_tag := channel.find("url")) is not None:
|
parsed_tvg_ids.add(channel_id)
|
||||||
channel.remove(url_tag)
|
|
||||||
|
|
||||||
root.append(channel)
|
for icon_tag in channel.findall("icon"):
|
||||||
|
if logo := tvg_ids.get(channel_id):
|
||||||
|
icon_tag.set("src", logo)
|
||||||
|
|
||||||
|
if (url_tag := channel.find("url")) is not None:
|
||||||
|
channel.remove(url_tag)
|
||||||
|
|
||||||
|
root.append(channel)
|
||||||
|
|
||||||
for program in epg_data.findall("programme"):
|
for program in epg_data.findall("programme"):
|
||||||
if program.get("channel") in tvg_ids:
|
if program.get("channel") not in tvg_ids:
|
||||||
title_text = program.find("title").text
|
continue
|
||||||
subtitle = program.find("sub-title")
|
|
||||||
|
|
||||||
if (
|
title_text = program.find("title").text
|
||||||
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)
|
subtitle = program.find("sub-title")
|
||||||
|
|
||||||
for k, v in REPLACE_IDs.items():
|
if (
|
||||||
hijack_id(**v, text=k, root=root)
|
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 title, ids in REPLACE_IDs.items():
|
||||||
|
hijack_id(root, **ids, text=title)
|
||||||
|
|
||||||
|
if missing_ids := set(tvg_ids) - parsed_tvg_ids:
|
||||||
|
log.warning(f"Missed {len(missing_ids)} TVG ID(s)")
|
||||||
|
|
||||||
|
for channel_id in missing_ids:
|
||||||
|
log.warning(f"Missing: {channel_id}")
|
||||||
|
|
||||||
tree = ET.ElementTree(root)
|
tree = ET.ElementTree(root)
|
||||||
|
|
||||||
tree.write(EPG_FILE, encoding="utf-8", xml_declaration=True)
|
tree.write(
|
||||||
|
EPG_FILE,
|
||||||
|
encoding="utf-8",
|
||||||
|
xml_declaration=True,
|
||||||
|
)
|
||||||
|
|
||||||
log.info(f"EPG saved to {EPG_FILE.resolve()}")
|
log.info(f"EPG saved to {EPG_FILE.resolve()}")
|
||||||
|
|
||||||
|
|
|
||||||
1998
M3U8/events.m3u8
1998
M3U8/events.m3u8
File diff suppressed because it is too large
Load diff
|
|
@ -21,6 +21,7 @@ from scrapers import (
|
||||||
streamfree,
|
streamfree,
|
||||||
streamhub,
|
streamhub,
|
||||||
streamsgate,
|
streamsgate,
|
||||||
|
totalsportek,
|
||||||
tvpass,
|
tvpass,
|
||||||
watchfooty,
|
watchfooty,
|
||||||
webcast,
|
webcast,
|
||||||
|
|
@ -70,6 +71,7 @@ async def main() -> None:
|
||||||
asyncio.create_task(streamcenter.scrape(xtrnl_brwsr)),
|
asyncio.create_task(streamcenter.scrape(xtrnl_brwsr)),
|
||||||
# asyncio.create_task(streamhub.scrape(xtrnl_brwsr)),
|
# asyncio.create_task(streamhub.scrape(xtrnl_brwsr)),
|
||||||
asyncio.create_task(streamsgate.scrape(xtrnl_brwsr)),
|
asyncio.create_task(streamsgate.scrape(xtrnl_brwsr)),
|
||||||
|
asyncio.create_task(totalsportek.scrape(hdl_brwsr)),
|
||||||
asyncio.create_task(webcast.scrape(hdl_brwsr)),
|
asyncio.create_task(webcast.scrape(hdl_brwsr)),
|
||||||
asyncio.create_task(watchfooty.scrape(xtrnl_brwsr)),
|
asyncio.create_task(watchfooty.scrape(xtrnl_brwsr)),
|
||||||
]
|
]
|
||||||
|
|
@ -80,10 +82,10 @@ async def main() -> None:
|
||||||
asyncio.create_task(pawa.scrape()),
|
asyncio.create_task(pawa.scrape()),
|
||||||
asyncio.create_task(roxie.scrape()),
|
asyncio.create_task(roxie.scrape()),
|
||||||
asyncio.create_task(shark.scrape()),
|
asyncio.create_task(shark.scrape()),
|
||||||
asyncio.create_task(streambtw.scrape()),
|
# asyncio.create_task(streambtw.scrape()),
|
||||||
asyncio.create_task(streamfree.scrape()),
|
asyncio.create_task(streamfree.scrape()),
|
||||||
asyncio.create_task(tvpass.scrape()),
|
asyncio.create_task(tvpass.scrape()),
|
||||||
asyncio.create_task(xstreameast.scrape()),
|
# asyncio.create_task(xstreameast.scrape()),
|
||||||
]
|
]
|
||||||
|
|
||||||
await asyncio.gather(*(pw_tasks + httpx_tasks))
|
await asyncio.gather(*(pw_tasks + httpx_tasks))
|
||||||
|
|
@ -112,6 +114,7 @@ async def main() -> None:
|
||||||
| streamfree.urls
|
| streamfree.urls
|
||||||
| streamhub.urls
|
| streamhub.urls
|
||||||
| streamsgate.urls
|
| streamsgate.urls
|
||||||
|
| totalsportek.urls
|
||||||
| tvpass.urls
|
| tvpass.urls
|
||||||
| watchfooty.urls
|
| watchfooty.urls
|
||||||
| webcast.urls
|
| webcast.urls
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ log = get_logger(__name__)
|
||||||
|
|
||||||
urls: dict[str, dict[str, str | float]] = {}
|
urls: dict[str, dict[str, str | float]] = {}
|
||||||
|
|
||||||
TAG = "LTVSX"
|
TAG = "LIVETVSX"
|
||||||
|
|
||||||
XML_CACHE = Cache(f"{TAG}-xml", exp=28_000)
|
|
||||||
|
|
||||||
CACHE_FILE = Cache(TAG, exp=10_800)
|
CACHE_FILE = Cache(TAG, exp=10_800)
|
||||||
|
|
||||||
|
XML_CACHE = Cache(f"{TAG}-xml", exp=28_000)
|
||||||
|
|
||||||
BASE_URL = "https://cdn.livetv861.me/rss/upcoming_en.xml"
|
BASE_URL = "https://cdn.livetv861.me/rss/upcoming_en.xml"
|
||||||
|
|
||||||
VALID_SPORTS = {"NBA", "NHL", "NFL", "NCAA", "MLB"}
|
VALID_SPORTS = {"NBA", "NHL", "NFL", "NCAA", "MLB"}
|
||||||
|
|
@ -160,8 +160,8 @@ async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
|
||||||
|
|
||||||
live = []
|
live = []
|
||||||
|
|
||||||
start_ts = now.delta(minutes=-30).timestamp()
|
start_ts = now.delta(hours=-1).timestamp()
|
||||||
end_ts = now.delta(minutes=30).timestamp()
|
end_ts = now.delta(minutes=5).timestamp()
|
||||||
|
|
||||||
for k, v in events.items():
|
for k, v in events.items():
|
||||||
if k in cached_keys:
|
if k in cached_keys:
|
||||||
|
|
@ -193,7 +193,7 @@ async def scrape(browser: Browser) -> None:
|
||||||
log.info(f"Processing {len(events)} new URL(s)")
|
log.info(f"Processing {len(events)} new URL(s)")
|
||||||
|
|
||||||
if events:
|
if events:
|
||||||
async with network.event_context(browser) as context:
|
async with network.event_context(browser, ignore_https=True) as context:
|
||||||
for i, ev in enumerate(events, start=1):
|
for i, ev in enumerate(events, start=1):
|
||||||
async with network.event_page(context) as page:
|
async with network.event_page(context) as page:
|
||||||
handler = partial(
|
handler = partial(
|
||||||
|
|
@ -210,10 +210,11 @@ async def scrape(browser: Browser) -> None:
|
||||||
log=log,
|
log=log,
|
||||||
)
|
)
|
||||||
|
|
||||||
sport, event, ts = (
|
sport, event, ts, link = (
|
||||||
ev["sport"],
|
ev["sport"],
|
||||||
ev["event"],
|
ev["event"],
|
||||||
ev["timestamp"],
|
ev["timestamp"],
|
||||||
|
ev["link"],
|
||||||
)
|
)
|
||||||
|
|
||||||
key = f"[{sport}] {event} ({TAG})"
|
key = f"[{sport}] {event} ({TAG})"
|
||||||
|
|
@ -226,6 +227,7 @@ async def scrape(browser: Browser) -> None:
|
||||||
"base": "https://livetv.sx/enx/",
|
"base": "https://livetv.sx/enx/",
|
||||||
"timestamp": ts,
|
"timestamp": ts,
|
||||||
"id": tvg_id or "Live.Event.us",
|
"id": tvg_id or "Live.Event.us",
|
||||||
|
"link": link,
|
||||||
}
|
}
|
||||||
|
|
||||||
cached_urls[key] = entry
|
cached_urls[key] = entry
|
||||||
|
|
|
||||||
146
M3U8/scrapers/totalsportek.py
Normal file
146
M3U8/scrapers/totalsportek.py
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
from functools import partial
|
||||||
|
from urllib.parse import urljoin, urlparse
|
||||||
|
|
||||||
|
from playwright.async_api import Browser
|
||||||
|
from selectolax.parser import HTMLParser
|
||||||
|
|
||||||
|
from .utils import Cache, Time, get_logger, leagues, network
|
||||||
|
|
||||||
|
log = get_logger(__name__)
|
||||||
|
|
||||||
|
urls: dict[str, dict[str, str | float]] = {}
|
||||||
|
|
||||||
|
TAG = "TOTALSPRTK"
|
||||||
|
|
||||||
|
CACHE_FILE = Cache(TAG, exp=28_800)
|
||||||
|
|
||||||
|
BASE_URL = "https://live3.totalsportek777.com/"
|
||||||
|
|
||||||
|
|
||||||
|
def fix_txt(s: str) -> str:
|
||||||
|
s = " ".join(s.split())
|
||||||
|
|
||||||
|
return s.upper() if s.islower() else s
|
||||||
|
|
||||||
|
|
||||||
|
async def get_events(cached_keys: list[str]) -> list[dict[str, str]]:
|
||||||
|
events = []
|
||||||
|
|
||||||
|
if not (html_data := await network.request(BASE_URL, log=log)):
|
||||||
|
return events
|
||||||
|
|
||||||
|
soup = HTMLParser(html_data.content)
|
||||||
|
|
||||||
|
sport = "Live Event"
|
||||||
|
|
||||||
|
for node in soup.css("a"):
|
||||||
|
if not node.attributes.get("class"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (parent := node.parent) and "my-1" in parent.attributes.get("class", ""):
|
||||||
|
if span := node.css_first("span"):
|
||||||
|
sport = span.text(strip=True)
|
||||||
|
|
||||||
|
sport = fix_txt(sport)
|
||||||
|
|
||||||
|
if not (teams := [t.text(strip=True) for t in node.css(".col-7 .col-12")]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not (href := node.attributes.get("href")):
|
||||||
|
continue
|
||||||
|
|
||||||
|
href = urlparse(href).path if href.startswith("http") else href
|
||||||
|
|
||||||
|
if not (time_node := node.css_first(".col-3 span")):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if time_node.text(strip=True) != "MatchStarted":
|
||||||
|
continue
|
||||||
|
|
||||||
|
event_name = fix_txt(" vs ".join(teams))
|
||||||
|
|
||||||
|
if f"[{sport}] {event_name} ({TAG})" in cached_keys:
|
||||||
|
continue
|
||||||
|
|
||||||
|
events.append(
|
||||||
|
{
|
||||||
|
"sport": sport,
|
||||||
|
"event": event_name,
|
||||||
|
"link": urljoin(BASE_URL, href),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return events
|
||||||
|
|
||||||
|
|
||||||
|
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"]}
|
||||||
|
|
||||||
|
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}"')
|
||||||
|
|
||||||
|
events = await get_events(cached_urls.keys())
|
||||||
|
|
||||||
|
log.info(f"Processing {len(events)} new URL(s)")
|
||||||
|
|
||||||
|
if events:
|
||||||
|
now = Time.clean(Time.now())
|
||||||
|
|
||||||
|
async with network.event_context(browser) as context:
|
||||||
|
for i, ev in enumerate(events, start=1):
|
||||||
|
async with network.event_page(context) as page:
|
||||||
|
handler = partial(
|
||||||
|
network.process_event,
|
||||||
|
url=ev["link"],
|
||||||
|
url_num=i,
|
||||||
|
page=page,
|
||||||
|
log=log,
|
||||||
|
)
|
||||||
|
|
||||||
|
url = await network.safe_process(
|
||||||
|
handler,
|
||||||
|
url_num=i,
|
||||||
|
semaphore=network.HTTP_S,
|
||||||
|
log=log,
|
||||||
|
)
|
||||||
|
|
||||||
|
sport, event, link = (
|
||||||
|
ev["sport"],
|
||||||
|
ev["event"],
|
||||||
|
ev["link"],
|
||||||
|
)
|
||||||
|
|
||||||
|
key = f"[{sport}] {event} ({TAG})"
|
||||||
|
|
||||||
|
tvg_id, logo = leagues.get_tvg_info(sport, event)
|
||||||
|
|
||||||
|
entry = {
|
||||||
|
"url": url,
|
||||||
|
"logo": logo,
|
||||||
|
"base": link,
|
||||||
|
"timestamp": now.timestamp(),
|
||||||
|
"id": tvg_id or "Live.Event.us",
|
||||||
|
"link": link,
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_urls[key] = entry
|
||||||
|
|
||||||
|
if url:
|
||||||
|
valid_count += 1
|
||||||
|
|
||||||
|
urls[key] = entry
|
||||||
|
|
||||||
|
if new_count := valid_count - cached_count:
|
||||||
|
log.info(f"Collected and cached {new_count} new event(s)")
|
||||||
|
|
||||||
|
else:
|
||||||
|
log.info("No new events found")
|
||||||
|
|
||||||
|
CACHE_FILE.write(cached_urls)
|
||||||
|
|
@ -811,65 +811,94 @@
|
||||||
"teams": {
|
"teams": {
|
||||||
"NBA": [
|
"NBA": [
|
||||||
"76ers",
|
"76ers",
|
||||||
|
"Atlanta",
|
||||||
"Atlanta Hawks",
|
"Atlanta Hawks",
|
||||||
"Blazers",
|
"Blazers",
|
||||||
|
"Boston",
|
||||||
"Boston Celtics",
|
"Boston Celtics",
|
||||||
"Brooklyn Nets",
|
"Brooklyn Nets",
|
||||||
"Bucks",
|
"Bucks",
|
||||||
"Bulls",
|
"Bulls",
|
||||||
"Cavaliers",
|
"Cavaliers",
|
||||||
"Celtics",
|
"Celtics",
|
||||||
|
"Charlotte",
|
||||||
"Charlotte Hornets",
|
"Charlotte Hornets",
|
||||||
|
"Chicago",
|
||||||
"Chicago Bulls",
|
"Chicago Bulls",
|
||||||
|
"Cleveland",
|
||||||
"Cleveland Cavaliers",
|
"Cleveland Cavaliers",
|
||||||
"Clippers",
|
"Clippers",
|
||||||
|
"Dallas",
|
||||||
"Dallas Mavericks",
|
"Dallas Mavericks",
|
||||||
|
"Denver",
|
||||||
"Denver Nuggets",
|
"Denver Nuggets",
|
||||||
|
"Detroit",
|
||||||
"Detroit Pistons",
|
"Detroit Pistons",
|
||||||
|
"Golden State",
|
||||||
"Golden State Warriors",
|
"Golden State Warriors",
|
||||||
"Grizzlies",
|
"Grizzlies",
|
||||||
"Hawks",
|
"Hawks",
|
||||||
"Heat",
|
"Heat",
|
||||||
"Hornets",
|
"Hornets",
|
||||||
|
"Houston",
|
||||||
"Houston Rockets",
|
"Houston Rockets",
|
||||||
|
"Indiana",
|
||||||
"Indiana Pacers",
|
"Indiana Pacers",
|
||||||
"Jazz",
|
"Jazz",
|
||||||
"Kings",
|
"Kings",
|
||||||
"Knicks",
|
"Knicks",
|
||||||
"Lakers",
|
"Lakers",
|
||||||
|
"Los Angeles",
|
||||||
"Los Angeles Clippers",
|
"Los Angeles Clippers",
|
||||||
"Los Angeles Lakers",
|
"Los Angeles Lakers",
|
||||||
"Magic",
|
"Magic",
|
||||||
"Mavericks",
|
"Mavericks",
|
||||||
|
"Memphis",
|
||||||
"Memphis Grizzlies",
|
"Memphis Grizzlies",
|
||||||
|
"Miami",
|
||||||
"Miami Heat",
|
"Miami Heat",
|
||||||
|
"Milwaukee",
|
||||||
"Milwaukee Bucks",
|
"Milwaukee Bucks",
|
||||||
|
"Minnesota",
|
||||||
"Minnesota Timberwolves",
|
"Minnesota Timberwolves",
|
||||||
"Nets",
|
"Nets",
|
||||||
|
"New Orleans",
|
||||||
"New Orleans Pelicans",
|
"New Orleans Pelicans",
|
||||||
|
"New York",
|
||||||
"New York Knicks",
|
"New York Knicks",
|
||||||
"Nuggets",
|
"Nuggets",
|
||||||
|
"Oklahoma",
|
||||||
|
"Oklahoma City",
|
||||||
"Oklahoma City Thunder",
|
"Oklahoma City Thunder",
|
||||||
|
"Orlando",
|
||||||
"Orlando Magic",
|
"Orlando Magic",
|
||||||
"Pacers",
|
"Pacers",
|
||||||
"Pelicans",
|
"Pelicans",
|
||||||
|
"Philadelphia",
|
||||||
"Philadelphia 76ers",
|
"Philadelphia 76ers",
|
||||||
|
"Phoenix",
|
||||||
"Phoenix Suns",
|
"Phoenix Suns",
|
||||||
"Pistons",
|
"Pistons",
|
||||||
|
"Portland",
|
||||||
"Portland Trail Blazers",
|
"Portland Trail Blazers",
|
||||||
"Raptors",
|
"Raptors",
|
||||||
"Rockets",
|
"Rockets",
|
||||||
|
"Sacramento",
|
||||||
"Sacramento Kings",
|
"Sacramento Kings",
|
||||||
|
"San Antonio",
|
||||||
"San Antonio Spurs",
|
"San Antonio Spurs",
|
||||||
"Sixers",
|
"Sixers",
|
||||||
"Spurs",
|
"Spurs",
|
||||||
"Suns",
|
"Suns",
|
||||||
"Thunder",
|
"Thunder",
|
||||||
"Timberwolves",
|
"Timberwolves",
|
||||||
|
"Toronto",
|
||||||
"Toronto Raptors",
|
"Toronto Raptors",
|
||||||
"Trail Blazers",
|
"Trail Blazers",
|
||||||
|
"Utah",
|
||||||
"Utah Jazz",
|
"Utah Jazz",
|
||||||
"Warriors",
|
"Warriors",
|
||||||
|
"Washington",
|
||||||
"Washington Wizards",
|
"Washington Wizards",
|
||||||
"Wizards",
|
"Wizards",
|
||||||
"Wolves"
|
"Wolves"
|
||||||
|
|
|
||||||
|
|
@ -129,12 +129,14 @@ class Network:
|
||||||
async def event_context(
|
async def event_context(
|
||||||
browser: Browser,
|
browser: Browser,
|
||||||
stealth: bool = True,
|
stealth: bool = True,
|
||||||
|
ignore_https: bool = False,
|
||||||
) -> AsyncGenerator[BrowserContext, None]:
|
) -> AsyncGenerator[BrowserContext, None]:
|
||||||
context: BrowserContext | None = None
|
context: BrowserContext | None = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context = await browser.new_context(
|
context = await browser.new_context(
|
||||||
user_agent=Network.UA if stealth else None,
|
user_agent=Network.UA if stealth else None,
|
||||||
|
ignore_https_errors=ignore_https,
|
||||||
viewport={"width": 1366, "height": 768},
|
viewport={"width": 1366, "height": 768},
|
||||||
device_scale_factor=1,
|
device_scale_factor=1,
|
||||||
locale="en-US",
|
locale="en-US",
|
||||||
|
|
|
||||||
15
health.sh
15
health.sh
|
|
@ -9,20 +9,24 @@ STATUSLOG=$(mktemp)
|
||||||
get_status() {
|
get_status() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
local channel="$2"
|
local channel="$2"
|
||||||
|
local index="$3"
|
||||||
|
local total="$4"
|
||||||
local attempt response status_code
|
local attempt response status_code
|
||||||
|
|
||||||
[[ "$url" != http* ]] && return
|
[[ "$url" != http* ]] && return
|
||||||
|
|
||||||
|
printf '[%d/%d] Checking %s\n' "$((index + 1))" "$total" "$url"
|
||||||
|
|
||||||
for attempt in $(seq 1 "$RETRY_COUNT"); do
|
for attempt in $(seq 1 "$RETRY_COUNT"); do
|
||||||
response=$(
|
response=$(
|
||||||
curl -skL \
|
curl -skL \
|
||||||
-A "$UA" \
|
-A "$UA" \
|
||||||
-H "Accept: */*" \
|
-H "Accept: */*" \
|
||||||
-H "Accept-Language: en-US,en;q=0.9" \
|
-H "Accept-Language: en-US,en;q=0.9" \
|
||||||
-H "Accept-Encoding: gzip, deflate, br" \
|
|
||||||
-H "Connection: keep-alive" \
|
-H "Connection: keep-alive" \
|
||||||
-o /dev/null \
|
-o /dev/null \
|
||||||
--max-time 15 \
|
--compressed \
|
||||||
|
--max-time 30 \
|
||||||
-w "%{http_code}" \
|
-w "%{http_code}" \
|
||||||
"$url" 2>&1
|
"$url" 2>&1
|
||||||
)
|
)
|
||||||
|
|
@ -47,7 +51,7 @@ get_status() {
|
||||||
status_code="$response"
|
status_code="$response"
|
||||||
|
|
||||||
case "$status_code" in
|
case "$status_code" in
|
||||||
200)
|
2* | 3*)
|
||||||
echo "PASS" >>"$STATUSLOG"
|
echo "PASS" >>"$STATUSLOG"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
|
@ -71,6 +75,7 @@ get_status() {
|
||||||
|
|
||||||
check_links() {
|
check_links() {
|
||||||
echo "Checking links from: $base_file"
|
echo "Checking links from: $base_file"
|
||||||
|
total_urls=$(grep -cE '^https?://' "$base_file")
|
||||||
channel_num=0
|
channel_num=0
|
||||||
name=""
|
name=""
|
||||||
|
|
||||||
|
|
@ -86,14 +91,14 @@ check_links() {
|
||||||
|
|
||||||
elif [[ "$line" =~ ^https?:// ]]; then
|
elif [[ "$line" =~ ^https?:// ]]; then
|
||||||
while (($(jobs -r | wc -l) >= MAX_JOBS)); do sleep 0.2; done
|
while (($(jobs -r | wc -l) >= MAX_JOBS)); do sleep 0.2; done
|
||||||
get_status "$line" "$name" &
|
get_status "$line" "$name" "$channel_num" "$total_urls" &
|
||||||
((channel_num++))
|
((channel_num++))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done < <(cat "$base_file")
|
done < <(cat "$base_file")
|
||||||
|
|
||||||
wait
|
wait
|
||||||
echo "Done."
|
echo -e "\nDone."
|
||||||
}
|
}
|
||||||
|
|
||||||
write_readme() {
|
write_readme() {
|
||||||
|
|
|
||||||
19
readme.md
19
readme.md
|
|
@ -1,17 +1,18 @@
|
||||||
## Base Log @ 2026-01-27 03:57 UTC
|
## Base Log @ 2026-01-28 03:55 UTC
|
||||||
|
|
||||||
### ✅ Working Streams: 136<br>❌ Dead Streams: 9
|
### ✅ Working Streams: 136<br>❌ Dead Streams: 10
|
||||||
|
|
||||||
| Channel | Error (Code) | Link |
|
| Channel | Error (Code) | Link |
|
||||||
| ------- | ------------ | ---- |
|
| ------- | ------------ | ---- |
|
||||||
| BBC World News | HTTP Error (404) | `http://fl1.moveonjoy.com/BBC_WORLD_NEWS/index.m3u8` |
|
| FDSN Ohio | HTTP Error (502) | `http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/222126` |
|
||||||
| FDSN Southeast | HTTP Error (403) | `http://mytvstream.net:8080/live/A1Jay5/362586/2213.m3u8` |
|
| FDSN Oklahoma | HTTP Error (403) | `http://mytvstream.net:8080/live/A1Jay5/362586/20934.m3u8` |
|
||||||
| FDSN Southwest | HTTP Error (403) | `http://mytvstream.net:8080/live/A1Jay5/362586/21843.m3u8` |
|
| FDSN Southeast | HTTP Error (502) | `http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/222130` |
|
||||||
|
| FDSN Southwest | HTTP Error (502) | `http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/220452` |
|
||||||
|
| FDSN Sun | HTTP Error (502) | `http://lucidhosting.xyz:82/sandriassoc@gmail.com/Sm8G4ddxoW/222132` |
|
||||||
| FXX | HTTP Error (404) | `https://fl1.moveonjoy.com/FXX/index.m3u8` |
|
| FXX | HTTP Error (404) | `https://fl1.moveonjoy.com/FXX/index.m3u8` |
|
||||||
| Lifetime Movie Network | HTTP Error (404) | `https://fl1.moveonjoy.com/LIFETIME_MOVIE_NETWORK/index.m3u8` |
|
| NBC Sports Philadelphia | HTTP Error (403) | `http://hardcoremedia.xyz:80/NW3Vk7xXwW/8375773282/136477` |
|
||||||
| NBC Sports Bay Area | Unknown status (302) | `http://hardcoremedia.xyz:80/NW3Vk7xXwW/8375773282/257216` |
|
| NFL RedZone | HTTP Error (502) | `http://hardcoremedia.xyz:80/NW3Vk7xXwW/8375773282/249239` |
|
||||||
| Paramount Network | HTTP Error (404) | `https://fl1.moveonjoy.com/PARAMOUNT_NETWORK/index.m3u8` |
|
| Premier Sports 2 | HTTP Error (502) | `http://hardcoremedia.xyz:80/NW3Vk7xXwW/8375773282/117038` |
|
||||||
| Premier Sports 2 | Unknown status (302) | `http://hardcoremedia.xyz:80/NW3Vk7xXwW/8375773282/117038` |
|
|
||||||
| Sportsnet One | HTTP Error (403) | `http://mytvstream.net:8080/live/k4Svp2/645504/57297.m3u8` |
|
| Sportsnet One | HTTP Error (403) | `http://mytvstream.net:8080/live/k4Svp2/645504/57297.m3u8` |
|
||||||
---
|
---
|
||||||
#### Base Channels URL
|
#### Base Channels URL
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue