92 lines
2.3 KiB
Python
92 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import re
|
|
from typing import Any
|
|
from urllib.parse import urlparse
|
|
|
|
_MXC_URL_PATTERN = re.compile(r"^mxc://([^/]+)/(.+)$")
|
|
_HTTP_URL_PATTERN = re.compile(r"^https?://")
|
|
|
|
|
|
def resolve_avatar_url(raw_url: str, homeserver: str | None = None) -> str | None:
|
|
if not raw_url:
|
|
return None
|
|
|
|
if _MXC_URL_PATTERN.match(raw_url):
|
|
return raw_url
|
|
|
|
if _HTTP_URL_PATTERN.match(raw_url):
|
|
if homeserver:
|
|
return _http_to_mxc(raw_url, homeserver)
|
|
return raw_url
|
|
|
|
return None
|
|
|
|
|
|
def _http_to_mxc(http_url: str, homeserver: str) -> str:
|
|
media_id = hashlib.sha256(http_url.encode()).hexdigest()[:24]
|
|
|
|
if homeserver.startswith("http"):
|
|
hs_domain = urlparse(homeserver).hostname or "matrix.org"
|
|
else:
|
|
hs_domain = homeserver
|
|
|
|
return f"mxc://{hs_domain}/{media_id}"
|
|
|
|
|
|
def resolve_display_name(
|
|
profile_data: dict[str, Any],
|
|
fallback_user_id: str = "",
|
|
) -> str:
|
|
displayname = profile_data.get("displayname", "")
|
|
if displayname:
|
|
return displayname.strip()
|
|
|
|
user_id = profile_data.get("user_id", fallback_user_id)
|
|
if user_id and user_id.startswith("@"):
|
|
localpart = user_id[1:].split(":")[0]
|
|
return localpart
|
|
|
|
return user_id or "unknown"
|
|
|
|
|
|
def compare_profiles(
|
|
current: dict[str, Any],
|
|
incoming: dict[str, Any],
|
|
) -> dict[str, tuple[Any, Any]]:
|
|
changes: dict[str, tuple[Any, Any]] = {}
|
|
for key in ("displayname", "avatar_url"):
|
|
old_val = current.get(key)
|
|
new_val = incoming.get(key)
|
|
if old_val != new_val:
|
|
changes[key] = (old_val, new_val)
|
|
return changes
|
|
|
|
|
|
def build_profile_update(
|
|
display_name: str = "",
|
|
avatar_url: str = "",
|
|
) -> dict[str, Any]:
|
|
result: dict[str, Any] = {}
|
|
if display_name:
|
|
result["displayname"] = display_name
|
|
if avatar_url:
|
|
result["avatar_url"] = avatar_url
|
|
return result
|
|
|
|
|
|
def mxc_to_http(mxc_url: str, homeserver: str) -> str:
|
|
match = _MXC_URL_PATTERN.match(mxc_url)
|
|
if not match:
|
|
return mxc_url
|
|
|
|
base = homeserver.rstrip("/")
|
|
if not base.startswith("http"):
|
|
base = f"https://{base}"
|
|
|
|
server_name = match.group(1)
|
|
media_id = match.group(2)
|
|
|
|
return f"{base}/_matrix/media/r0/download/{server_name}/{media_id}"
|