115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
import logging
|
|
from datetime import date, datetime, timedelta
|
|
from typing import List
|
|
|
|
from epg2xml.providers import EPGProgram, EPGProvider
|
|
|
|
log = logging.getLogger(__name__.rsplit(".", maxsplit=1)[-1].upper())
|
|
|
|
|
|
class SPOTV(EPGProvider):
|
|
"""EPGProvider for SPOTV
|
|
|
|
데이터: jsonapi
|
|
요청수: #days
|
|
특이사항:
|
|
- 5일치만 제공
|
|
"""
|
|
|
|
referer = "https://www.spotvnow.co.kr/channel"
|
|
title_regex = r"\s?(?:\[(.*?)\])?\s?(.*?)\s?(?:[\(<](.*)[\)>])?\s?(?:-(\d+))?\s?(?:<?([\d,]+)회>?)?\s?$"
|
|
|
|
def get_svc_channels(self) -> List[dict]:
|
|
url = "https://www.spotvnow.co.kr/api/v3/channel"
|
|
return [
|
|
{
|
|
"Name": ch["name"],
|
|
"ServiceId": ch["id"],
|
|
"Icon_url": ch["logo"],
|
|
}
|
|
for ch in self.request(url)
|
|
]
|
|
|
|
def __dt(self, dt: str) -> datetime:
|
|
if not dt:
|
|
return None
|
|
if dt.endswith("24:00"):
|
|
return datetime.strptime(dt.replace("24:00", "00:00"), "%Y-%m-%d %H:%M") + timedelta(days=1)
|
|
return datetime.strptime(dt, "%Y-%m-%d %H:%M")
|
|
|
|
def get_programs(self) -> None:
|
|
max_ndays = 5
|
|
if int(self.cfg["FETCH_LIMIT"]) > max_ndays:
|
|
log.warning(
|
|
"""
|
|
|
|
***********************************************************************
|
|
|
|
%s는 당일포함 %d일치만 EPG를 제공하고 있습니다.
|
|
|
|
***********************************************************************
|
|
""",
|
|
self.provider_name,
|
|
max_ndays,
|
|
)
|
|
data = []
|
|
for nd in range(min(int(self.cfg["FETCH_LIMIT"]), max_ndays)):
|
|
day = date.today() + timedelta(days=nd)
|
|
url = "https://www.spotvnow.co.kr/api/v3/program/" + day.strftime("%Y-%m-%d")
|
|
try:
|
|
data.extend(self.request(url))
|
|
except Exception:
|
|
log.exception("데이터 가져오는 중 에러:")
|
|
continue
|
|
|
|
# 날짜의 경계에서 발생할 수 있는 중복 제거
|
|
_data = []
|
|
for _d in data:
|
|
_d.pop("date", None)
|
|
if _d not in _data:
|
|
_data.append(_d)
|
|
|
|
for idx, _ch in enumerate(self.req_channels):
|
|
log.info("%03d/%03d %s", idx + 1, len(self.req_channels), _ch)
|
|
try:
|
|
_epgs = self.__epgs_of_channel(_ch.id, _data, _ch.svcid)
|
|
except AssertionError as e:
|
|
log.warning("%s: %s", e, _ch)
|
|
except Exception:
|
|
log.exception("프로그램 파싱 중 예외: %s", _ch)
|
|
else:
|
|
_ch.programs.extend(_epgs)
|
|
|
|
def __epgs_of_channel(self, channelid: str, data: dict, svcid: str) -> List[EPGProgram]:
|
|
programs = [x for x in data if x["channelId"] == svcid]
|
|
assert programs, "EPG 정보가 없거나 없는 채널입니다"
|
|
|
|
_epgs = []
|
|
for p in programs:
|
|
_epg = EPGProgram(channelid)
|
|
_epg.title = p["title"]
|
|
_epg.stime = self.__dt(p["startTime"])
|
|
# 끝나는 시간이 없으면 해당일 자정으로 강제
|
|
_epg.etime = self.__dt(p["endTime"]) or (_epg.stime.replace(hour=0, minute=0) + timedelta(days=1))
|
|
if _epg.stime == _epg.etime:
|
|
continue
|
|
|
|
if m := self.title_regex.match(_epg.title):
|
|
_epg.title = m.group(2)
|
|
subs = []
|
|
if prefix := m.group(1):
|
|
subs.append(prefix)
|
|
if sub := m.group(3):
|
|
subs += [sub.replace(")(", ", ").replace(") (", ", ")]
|
|
title_sub = ", ".join(subs)
|
|
if num := m.group(4):
|
|
title_sub += f"-{num}"
|
|
if title_sub:
|
|
_epg.title_sub = title_sub
|
|
_epg.ep_num = m.group(5)
|
|
if p["type"] == 300:
|
|
# 100: live, 200: 본방송
|
|
_epg.rebroadcast = True
|
|
_epgs.append(_epg)
|
|
return _epgs
|