Files
abot/wechat_ipad/models/friend_circle_info.py
2026-04-07 12:50:50 +08:00

108 lines
3.6 KiB
Python

import random
import time
from typing import Iterable
def _safe_float(value) -> float:
try:
return float(value or 0)
except (TypeError, ValueError):
return 0.0
def generate_timeline_id() -> str:
return f"{int(time.time() * 1000)}{random.randint(1000, 9999)}"
def build_media_xml(media_items: Iterable[dict]) -> str:
parts = []
for index, item in enumerate(media_items):
url = item.get("url", "")
thumb = item.get("thumb", url)
media_id = item.get("id") or f"{int(time.time() * 1000)}{index}"
md5 = item.get("md5", "")
total_size = item.get("total_size", 0)
width = item.get("width", 0)
height = item.get("height", 0)
parts.append(
f"""
<media>
<id><![CDATA[{media_id}]]></id>
<type><![CDATA[2]]></type>
<title></title>
<description></description>
<private><![CDATA[0]]></private>
<url type="1" md5="{md5}"><![CDATA[{url}]]></url>
<thumb type="1"><![CDATA[{thumb}]]></thumb>
<videoDuration><![CDATA[0.0]]></videoDuration>
<size totalSize="{_safe_float(total_size):.1f}" width="{_safe_float(width):.1f}" height="{_safe_float(height):.1f}"></size>
</media>
""".strip()
)
return "\n".join(parts)
def build_friend_circle_xml(wxid: str, content: str, media_items: list[dict] | None = None,
timeline_id: str | None = None, create_time: int | None = None) -> str:
media_items = media_items or []
timeline_id = timeline_id or generate_timeline_id()
create_time = create_time or int(time.time())
content_style = 1 if media_items else 2
media_xml = build_media_xml(media_items)
return f"""
<TimelineObject>
<id><![CDATA[{timeline_id}]]></id>
<username><![CDATA[{wxid}]]></username>
<createTime><![CDATA[{create_time}]]></createTime>
<contentDescShowType>0</contentDescShowType>
<contentDescScene>0</contentDescScene>
<private><![CDATA[0]]></private>
<contentDesc><![CDATA[{content}]]></contentDesc>
<contentattr><![CDATA[0]]></contentattr>
<sourceUserName></sourceUserName>
<publicUserName></publicUserName>
<sourceNickName></sourceNickName>
<statisticsData></statisticsData>
<weappInfo>
<appUserName></appUserName>
<pagePath></pagePath>
<version><![CDATA[0]]></version>
<isHidden>0</isHidden>
<debugMode><![CDATA[0]]></debugMode>
<shareActionId></shareActionId>
<isGame><![CDATA[0]]></isGame>
<messageExtraData></messageExtraData>
<subType><![CDATA[0]]></subType>
<preloadResources></preloadResources>
</weappInfo>
<canvasInfoXml></canvasInfoXml>
<ContentObject>
<contentStyle><![CDATA[{content_style}]]></contentStyle>
<contentSubStyle><![CDATA[0]]></contentSubStyle>
<title></title>
<description></description>
<contentUrl></contentUrl>
<mediaList>
{media_xml}
</mediaList>
</ContentObject>
<actionInfo>
<appMsg>
<mediaTagName></mediaTagName>
<messageExt></messageExt>
<messageAction></messageAction>
</appMsg>
</actionInfo>
<appInfo>
<id></id>
</appInfo>
<location poiClassifyId="" poiName="" poiAddress="" poiClassifyType="0" city=""></location>
<streamvideo>
<streamvideourl></streamvideourl>
<streamvideothumburl></streamvideothumburl>
<streamvideoweburl></streamvideoweburl>
</streamvideo>
</TimelineObject>
""".strip()