11
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import hashlib
|
||||
import json
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from astrbot.api import logger
|
||||
|
||||
from ..request import APIResponseFormatError
|
||||
from .base import EndpointAdapter
|
||||
|
||||
|
||||
class JX3BoxAdapter(EndpointAdapter):
|
||||
"""适配 JX3BOX 响应结构,并集中实现其分页规则。"""
|
||||
|
||||
def extract_payload(self, payload: Any, out_key: str | None) -> Any:
|
||||
if out_key in (None, ""):
|
||||
return payload
|
||||
if not isinstance(payload, Mapping):
|
||||
raise APIResponseFormatError(
|
||||
f"JX3BOX 响应不是对象,无法提取字段: {out_key}"
|
||||
)
|
||||
if out_key not in payload:
|
||||
raise APIResponseFormatError(f"JX3BOX 响应缺少字段: {out_key}")
|
||||
return payload[out_key]
|
||||
|
||||
async def request_all_pages(
|
||||
self,
|
||||
endpoint_name: str,
|
||||
*,
|
||||
params: Mapping[str, Any] | None = None,
|
||||
out_key: str | None = None,
|
||||
path_params: Mapping[str, Any] | None = None,
|
||||
page_key: str = "page",
|
||||
list_key: str = "list",
|
||||
max_pages: int = 10,
|
||||
) -> list[Any]:
|
||||
if max_pages < 1:
|
||||
raise ValueError("max_pages 必须大于等于 1")
|
||||
|
||||
all_items: list[Any] = []
|
||||
request_params = dict(params or {})
|
||||
previous_page_hash: str | None = None
|
||||
|
||||
for current_page in range(1, max_pages + 1):
|
||||
request_params[page_key] = str(current_page)
|
||||
data = await self.request(
|
||||
endpoint_name,
|
||||
params=request_params,
|
||||
out_key=out_key,
|
||||
path_params=path_params,
|
||||
)
|
||||
page_items = self._extract_page_items(data, list_key)
|
||||
if not page_items:
|
||||
break
|
||||
|
||||
page_hash = hashlib.sha256(
|
||||
json.dumps(
|
||||
page_items,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
default=str,
|
||||
).encode("utf-8")
|
||||
).hexdigest()
|
||||
if page_hash == previous_page_hash:
|
||||
logger.warning(
|
||||
"JX3BOX 分页接口连续返回重复页面,已停止: "
|
||||
f"key={endpoint_name}, page={current_page}"
|
||||
)
|
||||
break
|
||||
|
||||
all_items.extend(page_items)
|
||||
previous_page_hash = page_hash
|
||||
|
||||
return all_items
|
||||
|
||||
@staticmethod
|
||||
def _extract_page_items(data: Any, list_key: str) -> list[Any]:
|
||||
if data is None:
|
||||
return []
|
||||
if isinstance(data, bytes):
|
||||
raise APIResponseFormatError("JX3BOX 分页接口返回了二进制内容")
|
||||
if isinstance(data, list):
|
||||
return data
|
||||
if not isinstance(data, Mapping):
|
||||
raise APIResponseFormatError("JX3BOX 分页响应必须是列表或对象")
|
||||
if list_key not in data:
|
||||
raise APIResponseFormatError(f"JX3BOX 分页响应缺少字段: {list_key}")
|
||||
|
||||
items = data[list_key]
|
||||
if not isinstance(items, list):
|
||||
raise APIResponseFormatError(f"JX3BOX 分页字段 {list_key} 不是列表")
|
||||
return items
|
||||
Reference in New Issue
Block a user