Files
astrbot_plugin_bangumi/src/services/calendar.py
chenxiangtong a05ce6e07e fork
2026-03-26 17:38:47 +08:00

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)