iptv/M3U8/scrapers/utils/config.py

208 lines
5.5 KiB
Python
Raw Normal View History

2025-09-19 15:44:02 -04:00
import json
2025-09-24 12:30:55 -04:00
import re
2025-11-14 19:27:54 -05:00
from datetime import date, datetime, timedelta, timezone
2025-09-19 15:44:02 -04:00
from pathlib import Path
2025-09-03 15:00:17 -04:00
import pytz
2025-10-29 03:21:18 -04:00
class Time(datetime):
ZONES = {
2025-11-08 16:22:00 -05:00
"CET": pytz.timezone("Europe/Berlin"),
2025-10-29 03:21:18 -04:00
"ET": pytz.timezone("America/New_York"),
"PST": pytz.timezone("America/Los_Angeles"),
"UTC": timezone.utc,
}
2025-09-04 09:59:19 -04:00
2025-10-29 03:21:18 -04:00
ZONES["EDT"] = ZONES["EST"] = ZONES["ET"]
2025-09-19 15:44:02 -04:00
2025-10-01 14:56:15 -04:00
TZ = ZONES["ET"]
2025-10-01 11:57:49 -04:00
@classmethod
def now(cls) -> "Time":
2025-10-02 13:19:44 -04:00
return cls.from_ts(datetime.now(cls.TZ).timestamp())
2025-10-01 11:57:49 -04:00
@classmethod
def from_ts(cls, ts: int | float) -> "Time":
return cls.fromtimestamp(ts, tz=cls.TZ)
2025-10-15 10:53:54 -04:00
@classmethod
def default_8(cls) -> float:
return (
cls.now()
.replace(hour=8, minute=0, second=0, microsecond=0, tzinfo=cls.TZ)
.timestamp()
)
2025-10-01 11:57:49 -04:00
def delta(self, **kwargs) -> "Time":
2025-10-02 13:19:44 -04:00
return self.from_ts((self + timedelta(**kwargs)).timestamp())
2025-10-01 11:57:49 -04:00
2025-10-02 12:57:25 -04:00
def clean(self) -> "Time":
2025-10-02 13:19:44 -04:00
return self.__class__.fromtimestamp(
self.replace(second=0, microsecond=0).timestamp(),
tz=self.TZ,
)
def to_tz(self, tzone: str) -> "Time":
2025-10-29 03:21:18 -04:00
dt = self.astimezone(self.ZONES[tzone])
return self.__class__.fromtimestamp(dt.timestamp(), tz=self.ZONES[tzone])
2025-10-02 12:57:25 -04:00
2025-11-11 17:16:10 -05:00
@classmethod
def _to_class_tz(cls, dt) -> "Time":
dt = dt.astimezone(cls.TZ)
return cls.fromtimestamp(dt.timestamp(), tz=cls.TZ)
2025-11-14 19:27:54 -05:00
@classmethod
def from_only_time(cls, s: str, d: date, timezone: str) -> "Time":
hour, minute = map(int, s.split(":"))
dt = datetime(
2000,
1,
1,
hour,
minute,
tzinfo=cls.ZONES.get(timezone, cls.TZ),
)
dt = dt.astimezone(cls.TZ)
dt = datetime.combine(d, dt.timetz())
return cls.fromtimestamp(dt.timestamp(), tz=cls.TZ)
2025-10-01 11:57:49 -04:00
@classmethod
2025-10-12 00:27:42 -04:00
def from_str(
cls,
s: str,
fmt: str | None = None,
2025-11-11 17:16:10 -05:00
timezone: str | None = None,
2025-10-12 00:27:42 -04:00
) -> "Time":
2025-11-11 17:16:10 -05:00
tz = cls.ZONES.get(timezone, cls.TZ)
2025-10-01 11:57:49 -04:00
if fmt:
2025-11-11 17:16:10 -05:00
dt = datetime.strptime(s, fmt)
dt = tz.localize(dt)
2025-10-29 03:21:18 -04:00
2025-10-01 11:57:49 -04:00
else:
formats = [
2025-11-11 17:16:10 -05:00
"%B %d, %Y %I:%M %p",
"%B %d, %Y %I:%M:%S %p",
"%m/%d/%Y %I:%M %p",
2025-11-09 10:01:41 -05:00
"%B %d, %Y %H:%M",
2025-11-09 10:02:32 -05:00
"%B %d, %Y %H:%M:%S",
2025-11-11 17:16:10 -05:00
"%Y-%m-%d",
2025-10-01 11:57:49 -04:00
"%Y-%m-%d %H:%M",
"%Y-%m-%d %H:%M:%S",
2025-11-22 02:52:16 -05:00
"%Y-%m-%d %H:%M %p",
"%Y-%m-%d %I:%M %p",
2025-10-26 18:29:10 -04:00
"%Y/%m/%d %H:%M",
"%Y/%m/%d %H:%M:%S",
"%m/%d/%Y %H:%M",
"%m/%d/%Y %H:%M:%S",
2025-12-05 13:34:37 -05:00
"%Y-%m-%dT%H:%M:%S",
2025-10-26 18:29:10 -04:00
"%Y/%m/%dT%H:%M:%S.%fZ",
2025-11-11 17:16:10 -05:00
"%Y-%m-%dT%H:%M:%S.%fZ",
2025-10-01 14:56:15 -04:00
"%a, %d %b %Y %H:%M:%S %z",
2025-10-01 11:57:49 -04:00
]
for frmt in formats:
try:
2025-11-11 17:16:10 -05:00
dt = datetime.strptime(s, frmt)
2025-10-01 11:57:49 -04:00
break
except ValueError:
continue
else:
2025-10-15 10:53:54 -04:00
return cls.from_ts(Time.default_8())
2025-10-01 11:57:49 -04:00
2025-11-11 17:16:10 -05:00
if not dt.tzinfo:
dt = (
tz.localize(dt)
if hasattr(tz, "localize")
else dt.replace(tzinfo=tz)
)
2025-10-01 11:57:49 -04:00
2025-11-11 17:16:10 -05:00
return cls._to_class_tz(dt)
2025-10-01 11:57:49 -04:00
2025-09-19 02:05:40 -04:00
2025-09-24 12:30:55 -04:00
class Leagues:
2025-10-15 10:53:54 -04:00
live_img = "https://i.gyazo.com/978f2eb4a199ca5b56b447aded0cb9e3.png"
2025-09-24 12:30:55 -04:00
def __init__(self) -> None:
2025-10-01 11:57:49 -04:00
self.data = json.loads(
(Path(__file__).parent / "leagues.json").read_text(encoding="utf-8")
)
2025-09-24 12:30:55 -04:00
def teams(self, league: str) -> list[str]:
return self.data["teams"].get(league, [])
2025-09-23 20:55:52 -04:00
2025-10-01 11:57:49 -04:00
def info(self, name: str) -> tuple[str | None, str]:
2025-09-24 12:30:55 -04:00
name = name.upper()
2025-09-21 15:24:47 -04:00
2025-09-24 12:30:55 -04:00
if match := next(
(
(tvg_id, league_data.get("logo"))
for tvg_id, leagues in self.data["leagues"].items()
for league_entry in leagues
for league_name, league_data in league_entry.items()
if name == league_name or name in league_data.get("names", [])
),
None,
):
tvg_id, logo = match
2025-09-21 15:24:47 -04:00
2025-10-01 11:57:49 -04:00
return (tvg_id, logo or self.live_img)
2025-09-24 12:30:55 -04:00
2025-10-01 11:57:49 -04:00
return (None, self.live_img)
2025-09-24 12:30:55 -04:00
2025-10-12 00:27:42 -04:00
def is_valid(
self,
event: str,
league: str,
) -> bool:
2025-11-14 19:27:54 -05:00
pattern = re.compile(r"\s+(?:-|vs\.?|at|@)\s+", flags=re.IGNORECASE)
2025-10-06 19:53:10 -04:00
if pattern.search(event):
t1, t2 = re.split(pattern, event)
2025-09-24 12:30:55 -04:00
return any(t in self.teams(league) for t in (t1.strip(), t2.strip()))
2025-11-03 04:13:00 -05:00
return event.lower() in {"nfl redzone", "college gameday"}
2025-09-24 12:30:55 -04:00
2025-10-12 00:27:42 -04:00
def get_tvg_info(
self,
sport: str,
event: str,
) -> tuple[str | None, str]:
2025-10-11 18:43:57 -04:00
match sport:
2025-11-01 12:32:51 -04:00
case "American Football" | "NFL":
2025-10-11 18:43:57 -04:00
return (
self.info("NFL")
if self.is_valid(event, "NFL")
else self.info("NCAA")
)
2025-10-30 15:38:34 -04:00
case "Basketball" | "NBA":
2025-10-11 18:43:57 -04:00
if self.is_valid(event, "NBA"):
return self.info("NBA")
elif self.is_valid(event, "WNBA"):
return self.info("WNBA")
else:
return self.info("Basketball")
2025-10-15 10:53:54 -04:00
case "Ice Hockey" | "Hockey":
2025-10-11 18:43:57 -04:00
return self.info("NHL")
case _:
return self.info(sport)
2025-09-24 12:30:55 -04:00
leagues = Leagues()
2025-10-01 11:57:49 -04:00
__all__ = ["leagues", "Time"]