66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
import asyncio
|
|
import copy
|
|
import time
|
|
from typing import cast
|
|
|
|
from astrbot.api import logger
|
|
|
|
from .base import BaseBangumiService
|
|
from .contracts import CalendarDay
|
|
from .exceptions import BangumiApiError
|
|
|
|
|
|
class CalendarService(BaseBangumiService):
|
|
CALENDAR_CACHE_TTL_SECONDS = 12 * 60 * 60
|
|
|
|
def __init__(self, *args: object, **kwargs: object) -> None:
|
|
super().__init__(*args, **kwargs)
|
|
self._calendar_cache: list[CalendarDay] | None = None
|
|
self._calendar_cache_expire_at: float = 0.0
|
|
self._calendar_cache_lock = asyncio.Lock()
|
|
|
|
def _is_calendar_cache_valid(self, now: float) -> bool:
|
|
return self._calendar_cache is not None and now < self._calendar_cache_expire_at
|
|
|
|
def invalidate_calendar_cache(self) -> None:
|
|
self._calendar_cache = None
|
|
self._calendar_cache_expire_at = 0.0
|
|
|
|
async def get_calendar(self) -> list[CalendarDay]:
|
|
now = time.time()
|
|
if self._is_calendar_cache_valid(now):
|
|
return copy.deepcopy(self._calendar_cache)
|
|
|
|
# 双重检查 + 锁,避免并发下重复请求远端 API
|
|
async with self._calendar_cache_lock:
|
|
now = time.time()
|
|
if self._is_calendar_cache_valid(now):
|
|
return copy.deepcopy(self._calendar_cache)
|
|
|
|
url = f"{self.base_url}/calendar"
|
|
previous_cache = copy.deepcopy(self._calendar_cache)
|
|
try:
|
|
data = await self._request(url, method="GET")
|
|
except (BangumiApiError, RuntimeError, ValueError, TypeError) as e:
|
|
logger.error(f"get_calendar 刷新缓存失败: {e}")
|
|
if previous_cache is not None:
|
|
return previous_cache
|
|
return []
|
|
|
|
if not isinstance(data, list):
|
|
logger.warning(f"get_calendar 返回了非 list 类型: {type(data)}")
|
|
if previous_cache is not None:
|
|
return previous_cache
|
|
return []
|
|
|
|
normalized: list[CalendarDay] = []
|
|
for item in data:
|
|
if isinstance(item, dict):
|
|
normalized.append(cast(CalendarDay, item))
|
|
else:
|
|
logger.warning(f"get_calendar 列表元素类型异常: {type(item)}")
|
|
|
|
self._calendar_cache = copy.deepcopy(normalized)
|
|
self._calendar_cache_expire_at = now + self.CALENDAR_CACHE_TTL_SECONDS
|
|
return copy.deepcopy(self._calendar_cache)
|