e
This commit is contained in:
parent
5e66ad6f80
commit
00000d94a5
4 changed files with 109 additions and 100 deletions
|
|
@ -1,17 +1,13 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import pytz
|
|
||||||
from scrape import fstv, tvpass
|
from scrape import fstv, tvpass
|
||||||
|
|
||||||
m3u8_file = Path(__file__).parent / "TV.m3u8"
|
m3u8_file = Path(__file__).parent / "TV.m3u8"
|
||||||
|
|
||||||
base = "http://m3u4u.com/m3u/d5k2nvp8w2t3w2k1n984"
|
base_url = "https://spoo.me/yBR2jV"
|
||||||
|
|
||||||
current_hour = datetime.now(pytz.timezone("America/New_York")).hour
|
|
||||||
|
|
||||||
client = httpx.Client(
|
client = httpx.Client(
|
||||||
timeout=5,
|
timeout=5,
|
||||||
|
|
@ -26,10 +22,10 @@ def vanilla_fetch() -> tuple[list[str], int]:
|
||||||
print("Fetching base M3U8")
|
print("Fetching base M3U8")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = client.get(base)
|
r = client.get(base_url)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise SystemExit(f'Failed to fetch "{base}"\n{e}') from e
|
raise SystemExit(f'Failed to fetch "{base_url}"\n{e}') from e
|
||||||
|
|
||||||
d = r.text.splitlines()
|
d = r.text.splitlines()
|
||||||
|
|
||||||
|
|
@ -41,13 +37,7 @@ def vanilla_fetch() -> tuple[list[str], int]:
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
if current_hour <= 11:
|
|
||||||
tvpass.main(client)
|
tvpass.main(client)
|
||||||
else:
|
|
||||||
try:
|
|
||||||
tvpass.urls = json.loads(tvpass.base_file.read_text(encoding="utf-8"))
|
|
||||||
except (FileNotFoundError, json.JSONDecodeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
fstv.main(client)
|
fstv.main(client)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,8 +104,3 @@ def main(client: httpx.Client) -> None:
|
||||||
urls[key] = link
|
urls[key] = link
|
||||||
|
|
||||||
print(f"Collected {len(urls)} live events")
|
print(f"Collected {len(urls)} live events")
|
||||||
|
|
||||||
|
|
||||||
# if __name__ == "__main__":
|
|
||||||
# # create client beforehand
|
|
||||||
# main()
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,47 @@
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
from datetime import datetime, timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
import pytz
|
||||||
|
|
||||||
base_url = "https://tvpass.org/playlist/m3u"
|
base_url = "https://tvpass.org/playlist/m3u"
|
||||||
base_file = Path(__file__).parent / "tvpass.json"
|
base_file = Path(__file__).parent / "tvpass.json"
|
||||||
|
|
||||||
urls: dict[str, str] = {}
|
urls: dict[str, str] = {}
|
||||||
|
|
||||||
|
TZ = pytz.timezone("America/New_York")
|
||||||
|
|
||||||
|
|
||||||
|
def cache_expired(t: float) -> bool:
|
||||||
|
now = datetime.now(TZ)
|
||||||
|
|
||||||
|
r = now.replace(hour=11, minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
|
if now < r:
|
||||||
|
r -= timedelta(days=1)
|
||||||
|
|
||||||
|
return t < r.timestamp()
|
||||||
|
|
||||||
|
|
||||||
|
def load_cache() -> dict[str, str]:
|
||||||
|
try:
|
||||||
|
data = json.loads(base_file.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
ts = data.get("_timestamp", 0)
|
||||||
|
|
||||||
|
return {} if cache_expired(ts) else data.get("urls", {})
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def save_cache(urls: dict[str, str]) -> None:
|
||||||
|
payload = {"_timestamp": datetime.now(TZ).timestamp(), "urls": urls}
|
||||||
|
|
||||||
|
base_file.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
def fetch_m3u8(client: httpx.Client) -> list[str] | None:
|
def fetch_m3u8(client: httpx.Client) -> list[str] | None:
|
||||||
try:
|
try:
|
||||||
|
|
@ -22,6 +54,11 @@ def fetch_m3u8(client: httpx.Client) -> list[str] | None:
|
||||||
|
|
||||||
|
|
||||||
def main(client: httpx.Client) -> None:
|
def main(client: httpx.Client) -> None:
|
||||||
|
if cached := load_cache():
|
||||||
|
urls.update(cached)
|
||||||
|
print(f"TVPass: Collected {len(urls)} live events from cache")
|
||||||
|
return
|
||||||
|
|
||||||
print(f'Scraping from "{base_url}"')
|
print(f'Scraping from "{base_url}"')
|
||||||
|
|
||||||
if not (data := fetch_m3u8(client)):
|
if not (data := fetch_m3u8(client)):
|
||||||
|
|
@ -51,12 +88,6 @@ def main(client: httpx.Client) -> None:
|
||||||
|
|
||||||
urls[f"[{sport}] {tvg_name}"] = url
|
urls[f"[{sport}] {tvg_name}"] = url
|
||||||
|
|
||||||
print(f"Collected {len(urls)} live events")
|
|
||||||
|
|
||||||
if urls:
|
if urls:
|
||||||
base_file.write_text(json.dumps(urls, indent=2), encoding="utf-8")
|
save_cache(urls)
|
||||||
|
print(f"Cached {len(urls)} live events")
|
||||||
|
|
||||||
# if __name__ == "__main__":
|
|
||||||
# # create client beforehand
|
|
||||||
# main()
|
|
||||||
|
|
|
||||||
31
health.sh
31
health.sh
|
|
@ -1,12 +1,12 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
main="http://m3u4u.com/m3u/d5k2nvp8w2t3w2k1n984"
|
base_url="https://spoo.me/yBR2jV"
|
||||||
|
UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0"
|
||||||
MAX_JOBS=10
|
MAX_JOBS=10
|
||||||
RETRY_COUNT=3
|
RETRY_COUNT=3
|
||||||
README="./readme.md"
|
README="./readme.md"
|
||||||
STATUSLOG=$(mktemp)
|
STATUSLOG=$(mktemp)
|
||||||
PASSED=0
|
PASSED=0
|
||||||
FAILED=0
|
FAILED=0
|
||||||
REDIRECTED=0
|
|
||||||
EMPTY=0
|
EMPTY=0
|
||||||
|
|
||||||
get_status() {
|
get_status() {
|
||||||
|
|
@ -17,7 +17,7 @@ get_status() {
|
||||||
[[ "$url" != http* ]] && return
|
[[ "$url" != http* ]] && return
|
||||||
|
|
||||||
for attempt in $(seq 1 "$RETRY_COUNT"); do
|
for attempt in $(seq 1 "$RETRY_COUNT"); do
|
||||||
response=$(curl -sL -o /dev/null --max-time 10 -w "%{http_code}" "$url" 2>&1)
|
response=$(curl -sL -A "$UA" -o /dev/null --max-time 10 -w "%{http_code}" "$url" 2>&1)
|
||||||
[[ "$response" =~ ^[0-9]+$ ]] && break
|
[[ "$response" =~ ^[0-9]+$ ]] && break
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
@ -36,18 +36,13 @@ get_status() {
|
||||||
|
|
||||||
case "$status_code" in
|
case "$status_code" in
|
||||||
200)
|
200)
|
||||||
if ! curl -sL --max-time 5 "$url" | head -c 1 | grep -q '.'; then
|
if ! curl -sL -A "$UA" --max-time 5 "$url" | head -c 1 | grep -q '.'; then
|
||||||
echo "| $channel | Empty body (404) | \`$url\` |" >>"$STATUSLOG"
|
echo "| $channel | Empty body (404) | \`$url\` |" >>"$STATUSLOG"
|
||||||
echo "EMPTY" >>"$STATUSLOG"
|
echo "EMPTY" >>"$STATUSLOG"
|
||||||
else
|
else
|
||||||
echo "PASS" >>"$STATUSLOG"
|
echo "PASS" >>"$STATUSLOG"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
301 | 302 | 307 | 308)
|
|
||||||
redirect_url=$(curl -sI --max-time 5 "$url" | grep -i '^Location:' | sed 's/Location: //I' | tr -d '\r\n')
|
|
||||||
echo "| $channel | Redirect ($status_code) | \`$url → $redirect_url\` |" >>"$STATUSLOG"
|
|
||||||
echo "REDIRECT" >>"$STATUSLOG"
|
|
||||||
;;
|
|
||||||
4* | 5*)
|
4* | 5*)
|
||||||
echo "| $channel | HTTP Error ($status_code) | \`$url\` |" >>"$STATUSLOG"
|
echo "| $channel | HTTP Error ($status_code) | \`$url\` |" >>"$STATUSLOG"
|
||||||
echo "FAIL" >>"$STATUSLOG"
|
echo "FAIL" >>"$STATUSLOG"
|
||||||
|
|
@ -64,7 +59,7 @@ get_status() {
|
||||||
}
|
}
|
||||||
|
|
||||||
check_links() {
|
check_links() {
|
||||||
echo "Checking links from: $main"
|
echo "Checking links from: $base_url"
|
||||||
channel_num=0
|
channel_num=0
|
||||||
name=""
|
name=""
|
||||||
jobs_running=0
|
jobs_running=0
|
||||||
|
|
@ -83,7 +78,7 @@ check_links() {
|
||||||
get_status "$line" "$name" &
|
get_status "$line" "$name" &
|
||||||
((channel_num++))
|
((channel_num++))
|
||||||
fi
|
fi
|
||||||
done < <(curl -sL "$main")
|
done < <(curl -sL -A "$UA" "$base_url")
|
||||||
|
|
||||||
wait
|
wait
|
||||||
echo "Done."
|
echo "Done."
|
||||||
|
|
@ -92,27 +87,25 @@ check_links() {
|
||||||
write_readme() {
|
write_readme() {
|
||||||
local passed redirected empty failed
|
local passed redirected empty failed
|
||||||
passed=$(grep -c '^PASS$' "$STATUSLOG")
|
passed=$(grep -c '^PASS$' "$STATUSLOG")
|
||||||
redirected=$(grep -c '^REDIRECT$' "$STATUSLOG")
|
|
||||||
empty=$(grep -c '^EMPTY$' "$STATUSLOG")
|
empty=$(grep -c '^EMPTY$' "$STATUSLOG")
|
||||||
failed=$(grep -c '^FAIL$' "$STATUSLOG")
|
failed=$(grep -c '^FAIL$' "$STATUSLOG")
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "## Log @ $(date '+%Y-%m-%d %H:%M:%S UTC')"
|
echo "## Log @ $(date '+%Y-%m-%d %H:%M UTC')"
|
||||||
echo
|
echo
|
||||||
echo "### ✅ Working Streams: $passed<br>🔁 Redirected Links: $redirected<br>➖ Empty Streams: $empty<br>❌ Dead Streams: $failed"
|
echo "### ✅ Working Streams: $passed<br>➖ Empty Streams: $empty<br>❌ Dead Streams: $failed"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if [ $failed -gt 0 ] || [ $empty -gt 0 ] || [ $redirected -gt 0 ]; then
|
if (($failed > 0 || $empty > 0)); then
|
||||||
head -n 1 "$STATUSLOG"
|
head -n 1 "$STATUSLOG"
|
||||||
grep -v -e '^PASS$' -e '^FAIL$' -e '^EMPTY$' -e '^REDIRECT$' -e '^---' "$STATUSLOG" |
|
grep -v -e '^PASS$' -e '^FAIL$' -e '^EMPTY$' -e '^---' "$STATUSLOG" | grep -v '^| Channel' | sort -u
|
||||||
grep -v '^| Channel' | sort -u
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "---"
|
echo "---"
|
||||||
echo "#### M3U8 URL"
|
echo "#### M3U8 URL"
|
||||||
printf "\`\`\`\nhttps://raw.githubusercontent.com/doms9/iptv/refs/heads/default/M3U8/TV.m3u8\n\`\`\`\n"
|
printf "\`\`\`\nhttps://spoo.me/d9M3U8\n\`\`\`\n"
|
||||||
echo "#### EPG URL"
|
echo "#### EPG URL"
|
||||||
printf "\`\`\`\nhttps://raw.githubusercontent.com/doms9/iptv/refs/heads/default/EPG/TV.xml\n\`\`\`\n"
|
printf "\`\`\`\nhttps://spoo.me/d9EPG\n\`\`\`\n"
|
||||||
echo "---"
|
echo "---"
|
||||||
echo "#### Legal Disclaimer"
|
echo "#### Legal Disclaimer"
|
||||||
echo "This repository lists publicly accessible IPTV streams as found on the internet at the time of checking."
|
echo "This repository lists publicly accessible IPTV streams as found on the internet at the time of checking."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue