Update utils.py
Browse files
utils.py
CHANGED
|
@@ -196,42 +196,105 @@ def _ts_normalize(t_val) -> Optional[float]:
|
|
| 196 |
return None
|
| 197 |
|
| 198 |
|
| 199 |
-
async def get_all_epg(auth:
|
| 200 |
-
if
|
| 201 |
-
channels = await get_channels(auth)
|
| 202 |
-
jst = timezone(timedelta(hours=9))
|
| 203 |
-
if date is None:
|
| 204 |
-
target_date = datetime.now(jst).strftime('%Y-%m-%d')
|
| 205 |
-
else:
|
| 206 |
-
if len(str(date)) == 8 and str(date).isdigit():
|
| 207 |
-
target_date = f"{str(date)[:4]}-{str(date)[4:6]}-{str(date)[6:8]}"
|
| 208 |
-
else:
|
| 209 |
-
target_date = date
|
| 210 |
if not force:
|
| 211 |
-
cached = cache.get_epg('_all_',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
if cached:
|
| 213 |
return cached
|
| 214 |
-
|
| 215 |
-
async def _fetch_one(ch):
|
| 216 |
-
ch_id = str(ch.get('id', ''))
|
| 217 |
-
if not ch_id:
|
| 218 |
-
return ch_id, []
|
| 219 |
-
if not force:
|
| 220 |
-
cached_ch = cache.get_epg(ch_id, target_date)
|
| 221 |
-
if cached_ch is not None:
|
| 222 |
-
return ch_id, cached_ch
|
| 223 |
-
async with sem:
|
| 224 |
-
try:
|
| 225 |
-
data = await fetch_epg(ch_id, target_date, auth)
|
| 226 |
-
if data:
|
| 227 |
-
cache.set_epg(ch_id, target_date, data)
|
| 228 |
-
return ch_id, data or []
|
| 229 |
-
except Exception:
|
| 230 |
-
return ch_id, []
|
| 231 |
-
results = await asyncio.gather(*[_fetch_one(ch) for ch in channels])
|
| 232 |
-
all_epg = {ch_id: {"data": data} for ch_id, data in results if ch_id}
|
| 233 |
-
cache.set_epg('_all_', 'full', all_epg)
|
| 234 |
-
return all_epg
|
| 235 |
|
| 236 |
|
| 237 |
def get_jst_date(dt: Optional[datetime] = None) -> str:
|
|
|
|
| 196 |
return None
|
| 197 |
|
| 198 |
|
| 199 |
+
async def get_all_epg(auth: Dict[str, Any], channels: list = None, date: str = None, force: bool = False) -> Dict[str, Any]:
|
| 200 |
+
cache_key_date = date if date else 'full'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
if not force:
|
| 202 |
+
cached = cache.get_epg('_all_', cache_key_date)
|
| 203 |
+
if cached:
|
| 204 |
+
return cached
|
| 205 |
+
|
| 206 |
+
try:
|
| 207 |
+
url = Config.get_list_url(auth['vms_uid'], with_epg=True)
|
| 208 |
+
|
| 209 |
+
headers = {
|
| 210 |
+
'Referer': Config.REQUIRED_REFERER,
|
| 211 |
+
'User-Agent': 'Mozilla/5.0'
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
async with httpx.AsyncClient(timeout=Config.TIMEOUT) as client:
|
| 215 |
+
response = await client.get(url, headers=headers)
|
| 216 |
+
response.raise_for_status()
|
| 217 |
+
data = response.json()
|
| 218 |
+
|
| 219 |
+
result = {}
|
| 220 |
+
jst = timezone(timedelta(hours=9))
|
| 221 |
+
|
| 222 |
+
if date:
|
| 223 |
+
try:
|
| 224 |
+
target_dt = datetime.strptime(date, "%Y%m%d").replace(tzinfo=jst)
|
| 225 |
+
except ValueError:
|
| 226 |
+
target_dt = datetime.strptime(date, "%Y-%m-%d").replace(tzinfo=jst)
|
| 227 |
+
start_ts = target_dt.timestamp()
|
| 228 |
+
end_ts = (target_dt + timedelta(days=1)).timestamp()
|
| 229 |
+
else:
|
| 230 |
+
start_ts = None
|
| 231 |
+
end_ts = None
|
| 232 |
+
|
| 233 |
+
source_channels = data.get('result', [])
|
| 234 |
+
|
| 235 |
+
for channel in source_channels:
|
| 236 |
+
channel_id = channel.get('id')
|
| 237 |
+
record_epg = channel.get('record_epg')
|
| 238 |
+
|
| 239 |
+
if not channel_id:
|
| 240 |
+
continue
|
| 241 |
+
|
| 242 |
+
if not record_epg:
|
| 243 |
+
result[channel_id] = {'data': []}
|
| 244 |
+
continue
|
| 245 |
+
|
| 246 |
+
try:
|
| 247 |
+
epg_list = json.loads(record_epg)
|
| 248 |
+
|
| 249 |
+
processed_programs = []
|
| 250 |
+
for i, program in enumerate(epg_list):
|
| 251 |
+
if not program.get('time'):
|
| 252 |
+
continue
|
| 253 |
+
|
| 254 |
+
if 'time_end' not in program or not program['time_end']:
|
| 255 |
+
if i + 1 < len(epg_list) and epg_list[i + 1].get('time'):
|
| 256 |
+
program['time_end'] = epg_list[i + 1]['time']
|
| 257 |
+
else:
|
| 258 |
+
continue
|
| 259 |
+
|
| 260 |
+
processed_programs.append(program)
|
| 261 |
+
|
| 262 |
+
daily_epg = {}
|
| 263 |
+
for program in processed_programs:
|
| 264 |
+
ts = _ts_normalize(program['time'])
|
| 265 |
+
if ts is None:
|
| 266 |
+
continue
|
| 267 |
+
dt = datetime.fromtimestamp(ts, tz=jst)
|
| 268 |
+
date_str = dt.strftime('%Y-%m-%d')
|
| 269 |
+
if date_str not in daily_epg:
|
| 270 |
+
daily_epg[date_str] = []
|
| 271 |
+
daily_epg[date_str].append(program)
|
| 272 |
+
|
| 273 |
+
for d, programs in daily_epg.items():
|
| 274 |
+
sorted_programs = sorted(programs, key=lambda x: x['time'])
|
| 275 |
+
cache.set_epg(channel_id, d, sorted_programs)
|
| 276 |
+
|
| 277 |
+
if start_ts is not None and end_ts is not None:
|
| 278 |
+
filtered = [
|
| 279 |
+
p for p in processed_programs
|
| 280 |
+
if start_ts <= (_ts_normalize(p.get('time')) or 0) < end_ts
|
| 281 |
+
]
|
| 282 |
+
result[channel_id] = {'data': sorted(filtered, key=lambda x: x['time'])}
|
| 283 |
+
else:
|
| 284 |
+
result[channel_id] = {'data': processed_programs}
|
| 285 |
+
|
| 286 |
+
except json.JSONDecodeError:
|
| 287 |
+
result[channel_id] = {'data': []}
|
| 288 |
+
continue
|
| 289 |
+
|
| 290 |
+
cache.set_epg('_all_', cache_key_date, result)
|
| 291 |
+
return result
|
| 292 |
+
|
| 293 |
+
except Exception as e:
|
| 294 |
+
cached = cache.get_epg('_all_', cache_key_date)
|
| 295 |
if cached:
|
| 296 |
return cached
|
| 297 |
+
return {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
|
| 299 |
|
| 300 |
def get_jst_date(dt: Optional[datetime] = None) -> str:
|