PamGram/modules/apihelper/models/genshin/hyperion.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

212 lines
6.3 KiB
Python
Raw Normal View History

2024-07-22 04:35:33 +00:00
from collections import OrderedDict
2024-07-16 12:30:38 +00:00
import ujson
2024-03-16 10:30:34 +00:00
from datetime import datetime, timedelta
2024-06-26 16:01:49 +00:00
from enum import Enum
from io import BytesIO
from typing import Any, List, Optional, Dict
2022-07-26 10:07:31 +00:00
from PIL import Image, UnidentifiedImageError
2022-10-08 00:59:08 +00:00
from pydantic import BaseModel, PrivateAttr
2022-07-26 10:07:31 +00:00
2024-06-26 16:01:49 +00:00
__all__ = (
"ArtworkImage",
"PostInfo",
"LiveInfo",
"LiveCode",
"LiveCodeHoYo",
"PostTypeEnum",
"PostRecommend",
"HoYoPostMultiLang",
)
2022-12-10 12:37:43 +00:00
2022-07-26 10:07:31 +00:00
2022-10-08 00:59:08 +00:00
class ArtworkImage(BaseModel):
art_id: int
page: int = 0
data: bytes = b""
2023-04-14 03:53:15 +00:00
file_name: Optional[str] = None
file_extension: Optional[str] = None
2022-10-08 00:59:08 +00:00
is_error: bool = False
2024-07-22 04:35:33 +00:00
url: str = ""
2022-07-26 10:07:31 +00:00
2022-10-08 00:59:08 +00:00
@property
def format(self) -> Optional[str]:
if not self.is_error:
try:
with BytesIO(self.data) as stream, Image.open(stream) as im:
return im.format
except UnidentifiedImageError:
pass
return None
2023-02-18 07:41:10 +00:00
2023-09-20 08:34:02 +00:00
@staticmethod
def gen(*args, **kwargs) -> List["ArtworkImage"]:
data = [ArtworkImage(*args, **kwargs)]
if data[0].file_extension and data[0].file_extension in ["gif", "mp4"]:
return data
try:
with BytesIO(data[0].data) as stream, Image.open(stream) as image:
width, height = image.size
crop_height = height
crop_num = 1
2024-09-13 12:31:29 +00:00
max_height = 8000 - width
2023-09-20 08:34:02 +00:00
while crop_height > max_height:
crop_num += 1
crop_height = height / crop_num
new_data = []
for i in range(crop_num):
slice_image = image.crop((0, crop_height * i, width, crop_height * (i + 1)))
bio = BytesIO()
2024-09-13 12:31:29 +00:00
slice_image.save(bio, "JPEG", quality=95)
2023-09-20 08:34:02 +00:00
kwargs["data"] = bio.getvalue()
2024-09-13 12:31:29 +00:00
kwargs["file_extension"] = "jpg"
2023-09-20 08:34:02 +00:00
new_data.append(ArtworkImage(*args, **kwargs))
return new_data
except UnidentifiedImageError:
return data
2022-10-08 00:59:08 +00:00
class PostInfo(BaseModel):
_data: dict = PrivateAttr()
2024-06-26 16:01:49 +00:00
hoyolab: bool
2022-10-08 00:59:08 +00:00
post_id: int
user_uid: int
subject: str
image_urls: List[str]
created_at: int
video_urls: List[str]
2024-07-16 12:30:38 +00:00
content: str
2022-10-08 00:59:08 +00:00
def __init__(self, _data: dict, **data: Any):
super().__init__(**data)
self._data = _data
2024-07-16 12:30:38 +00:00
@staticmethod
def parse_structured_content(data: List[Dict]) -> str:
content = []
for item in data:
if not item or item.get("insert") is None:
continue
insert = item["insert"]
if isinstance(insert, str):
if attr := item.get("attributes"):
if link := attr.get("link"):
content.append(f'<p><a href="{link}">{insert}</a></p>')
continue
content.append(f"<p>{insert}</p>")
elif isinstance(insert, dict):
if image := insert.get("image"):
content.append(f'<img src="{image}" />')
return "\n".join(content)
2022-10-08 00:59:08 +00:00
@classmethod
2024-06-26 16:01:49 +00:00
def paste_data(cls, data: dict, hoyolab: bool = False) -> "PostInfo":
2022-10-08 00:59:08 +00:00
_data_post = data["post"]
post = _data_post["post"]
post_id = post["post_id"]
subject = post["subject"]
2024-07-16 12:30:38 +00:00
image_list = []
image_keys = {"cover_list", "image_list"}
for key in image_keys:
image_list.extend(_data_post.get(key, []))
2024-07-22 04:35:33 +00:00
image_urls = list(OrderedDict.fromkeys([image["url"] for image in image_list]))
2024-07-16 12:30:38 +00:00
key1, key2 = ("video", "resolution") if hoyolab else ("vod_list", "resolutions")
vod_list = _data_post.get(key1, [])
if not isinstance(vod_list, list):
vod_list = [vod_list]
video_urls = [vod[key2][-1]["url"] for vod in vod_list if vod]
2022-10-08 00:59:08 +00:00
created_at = post["created_at"]
user = _data_post["user"] # 用户数据
user_uid = user["uid"] # 用户ID
2024-07-16 12:30:38 +00:00
content = post["content"]
if hoyolab and ("<" not in content) and (structured_content := post.get("structured_content")):
content = PostInfo.parse_structured_content(ujson.loads(structured_content))
if hoyolab and post["view_type"] == 5:
# video
content = ujson.loads(content).get("describe", "")
2022-10-08 00:59:08 +00:00
return PostInfo(
_data=data,
2024-06-26 16:01:49 +00:00
hoyolab=hoyolab,
2022-10-08 00:59:08 +00:00
post_id=post_id,
user_uid=user_uid,
subject=subject,
image_urls=image_urls,
2023-02-18 07:41:10 +00:00
video_urls=video_urls,
2022-10-08 00:59:08 +00:00
created_at=created_at,
2024-07-16 12:30:38 +00:00
content=content,
2022-10-08 00:59:08 +00:00
)
def __getitem__(self, item):
return self._data[item]
2024-06-26 16:01:49 +00:00
@property
def type_enum(self) -> "PostTypeEnum":
return PostTypeEnum.CN if not self.hoyolab else PostTypeEnum.OS
def get_url(self, short_name: str) -> str:
if not self.hoyolab:
return f"https://www.miyoushe.com/{short_name}/article/{self.post_id}"
return f"https://www.hoyolab.com/article/{self.post_id}"
def get_fix_url(self, short_name: str) -> str:
url = self.get_url(short_name)
return url.replace(".com/", ".pp.ua/")
class LiveInfo(BaseModel):
act_type: str
title: str
live_time: str
start: datetime
end: datetime
remain: int
now: datetime
is_end: bool
code_ver: str
class LiveCode(BaseModel):
code: str
to_get_time: datetime
@property
def text(self) -> str:
return self.code if self.code else "XXXXXXXXXXXX"
class LiveCodeHoYo(BaseModel):
exchange_code: str
offline_at: datetime
@property
def text(self) -> str:
return self.exchange_code if self.exchange_code else "XXXXXXXXXXXX"
2024-03-16 10:30:34 +00:00
@staticmethod
def guess_offline_at() -> datetime:
return datetime.now().replace(hour=23, minute=59, second=59, microsecond=999999) + timedelta(days=1)
2024-06-26 16:01:49 +00:00
class PostTypeEnum(str, Enum):
"""社区类型枚举"""
NULL = "null"
CN = "cn"
OS = "os"
class HoYoPostMultiLang(BaseModel):
lang_subject: dict
class PostRecommend(BaseModel):
hoyolab: bool = False
post_id: int
@staticmethod
def parse(data: Dict, hoyolab: bool = False):
_post = data.get("post")
post_id = _post.get("post_id")
return PostRecommend(hoyolab=hoyolab, post_id=post_id)