Add more Hoyolabs data
All checks were successful
Test and build Docker image / docker (push) Successful in 26s

This commit is contained in:
Joakim Hellsén 2026-07-20 06:35:13 +02:00
commit 347aa3fdcc
Signed by: Joakim Hellsén
SSH key fingerprint: SHA256:/9h/CsExpFp+PRhsfA0xznFx2CGfTT5R/kpuFfUgEQk

View file

@ -146,15 +146,42 @@ class HoyolabExtension(FeedExtension):
name = "hoyolab" name = "hoyolab"
description = ( description = (
"Detects c3kay.de / Hoyolab feeds and replaces the Discord embed " "Fetches post data from the Hoyolab API for c3kay.de feeds. "
"with full post data from the Hoyolab API " "Provides 20+ template variables (stats, topics, game info, "
"(Genshin Impact, Honkai Starrail, Honkai Impact 3rd, ZZZ)." "event dates, etc.) for text-mode messages, and replaces the "
"Discord embed with richer content for embed-mode."
) )
provides_variables: ClassVar[list[str]] = [ provides_variables: ClassVar[list[str]] = [
"hoyolab_subject", "hoyolab_subject",
"hoyolab_description", "hoyolab_description",
"hoyolab_image", "hoyolab_image",
"hoyolab_author", "hoyolab_author",
# Stats
"hoyolab_view_num",
"hoyolab_like_num",
"hoyolab_reply_num",
"hoyolab_bookmark_num",
"hoyolab_share_num",
# Post metadata
"hoyolab_post_id",
"hoyolab_created_at",
"hoyolab_reply_time",
"hoyolab_official_type",
# Author extras
"hoyolab_author_avatar_url",
"hoyolab_author_introduce",
"hoyolab_author_certification",
# Game
"hoyolab_game_name",
# Media
"hoyolab_cover",
"hoyolab_video_url",
# Classification / Topics
"hoyolab_classification",
"hoyolab_topics",
# Event dates
"hoyolab_event_start",
"hoyolab_event_end",
] ]
auto_enable_url_patterns: ClassVar[list[str]] = [ auto_enable_url_patterns: ClassVar[list[str]] = [
r"feeds\.c3kay\.de", r"feeds\.c3kay\.de",
@ -168,9 +195,10 @@ class HoyolabExtension(FeedExtension):
reader: The reader instance. reader: The reader instance.
Returns: Returns:
Dict with ``hoyolab_subject``, ``hoyolab_description``, Dict with up to 20+ ``hoyolab_*`` variables (subject,
``hoyolab_image`` and ``hoyolab_author`` if the data was description, image, author, stats, post metadata, game
fetched successfully, otherwise empty dict. name, topics, event dates, etc.) if the data was fetched
successfully, otherwise empty dict.
""" """
if not is_c3kay_feed_url(entry.feed.url): if not is_c3kay_feed_url(entry.feed.url):
return {} return {}
@ -183,7 +211,30 @@ class HoyolabExtension(FeedExtension):
if not post_data: if not post_data:
return {} return {}
return self._collect_template_variables(post_data)
@staticmethod
def _collect_template_variables(post_data: JsonObject) -> dict[str, str]:
"""Extract all template variables from the Hoyolab post payload.
Returns:
Dict of ``hoyolab_*`` template variables.
"""
post: JsonObject = _as_json_object(post_data.get("post")) post: JsonObject = _as_json_object(post_data.get("post"))
user: JsonObject = _as_json_object(post_data.get("user"))
result: dict[str, str] = {}
result.update(HoyolabExtension._collect_core_and_stat_vars(post_data, post, user))
result.update(HoyolabExtension._collect_meta_vars(post, user))
result.update(HoyolabExtension._collect_content_vars(post_data, post))
return result
@staticmethod
def _collect_core_and_stat_vars(post_data: JsonObject, post: JsonObject, user: JsonObject) -> dict[str, str]:
"""Extract core post fields and engagement stats.
Returns:
Dict with subject, description, image, author, and stats.
"""
subject: str = str(post.get("subject", "")) subject: str = str(post.get("subject", ""))
description: str = str(post.get("desc", "")) description: str = str(post.get("desc", ""))
@ -194,16 +245,96 @@ class HoyolabExtension(FeedExtension):
if isinstance(first_image, dict): if isinstance(first_image, dict):
image_url = str(first_image.get("url", "")) image_url = str(first_image.get("url", ""))
author: str = "" author: str = str(user.get("nickname", "")) if user else ""
user: JsonObject = _as_json_object(post_data.get("user"))
if user: stat: JsonObject = _as_json_object(post_data.get("stat"))
author = str(user.get("nickname", "")) view_num: str = str(stat.get("view_num", ""))
like_num: str = str(stat.get("like_num", ""))
reply_num: str = str(stat.get("reply_num", ""))
bookmark_num: str = str(stat.get("bookmark_num", ""))
share_num: str = str(stat.get("share_num", ""))
return { return {
"hoyolab_subject": subject, "hoyolab_subject": subject,
"hoyolab_description": description, "hoyolab_description": description,
"hoyolab_image": image_url, "hoyolab_image": image_url,
"hoyolab_author": author, "hoyolab_author": author,
"hoyolab_view_num": view_num,
"hoyolab_like_num": like_num,
"hoyolab_reply_num": reply_num,
"hoyolab_bookmark_num": bookmark_num,
"hoyolab_share_num": share_num,
}
@staticmethod
def _collect_meta_vars(post: JsonObject, user: JsonObject) -> dict[str, str]:
"""Extract post metadata and author extras.
Returns:
Dict with post ID, timestamps, official type, and author info.
"""
post_id_str: str = str(post.get("post_id", ""))
created_at: str = str(post.get("created_at", ""))
reply_time: str = str(post.get("reply_time", ""))
official_type: str = str(post.get("official_type", ""))
avatar_url_field: str = str(user.get("avatar_url", ""))
introduce: str = str(user.get("introduce", ""))
certification: JsonObject = _as_json_object(user.get("certification"))
certification_desc: str = str(certification.get("desc", "")) if certification else ""
return {
"hoyolab_post_id": post_id_str,
"hoyolab_created_at": created_at,
"hoyolab_reply_time": reply_time,
"hoyolab_official_type": official_type,
"hoyolab_author_avatar_url": avatar_url_field,
"hoyolab_author_introduce": introduce,
"hoyolab_author_certification": certification_desc,
}
@staticmethod
def _collect_content_vars(post_data: JsonObject, post: JsonObject) -> dict[str, str]:
"""Extract game, media, classification, topics and event dates.
Returns:
Dict with game name, media URLs, classification, topics, and event dates.
"""
game: JsonObject = _as_json_object(post_data.get("game"))
game_name: str = str(game.get("game_name", "")) if game else ""
cover_url: str = str(post.get("cover", ""))
video: JsonObject = _as_json_object(post_data.get("video"))
video_url: str = str(video.get("url", "")) if video else ""
classification: JsonObject = _as_json_object(post_data.get("classification"))
classification_name: str = str(classification.get("name", "")) if classification else ""
topics_value: JsonValue = post_data.get("topics", [])
topic_names: list[str] = []
if isinstance(topics_value, list):
for t in topics_value:
if isinstance(t, dict):
tn: str = str(t.get("name", ""))
if tn:
topic_names.append(tn)
topics_str: str = ", ".join(topic_names)
event_start: str = str(post.get("event_start_date", ""))
if event_start == "0":
event_start = ""
event_end: str = str(post.get("event_end_date", ""))
if event_end == "0":
event_end = ""
return {
"hoyolab_game_name": game_name,
"hoyolab_cover": cover_url,
"hoyolab_video_url": video_url,
"hoyolab_classification": classification_name,
"hoyolab_topics": topics_str,
"hoyolab_event_start": event_start,
"hoyolab_event_end": event_end,
} }
def modify_webhook( def modify_webhook(