Add Android animation library browsing
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Explicit mobile capability surface, sharing existing device business operations."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
@@ -51,8 +52,8 @@ class MobileControl:
|
||||
def identity(self):
|
||||
record = self.identity_record
|
||||
return dict(device_id=record["device_id"], device_name=record["name"],
|
||||
short_id=record["device_id"].replace("-", "")[:8], protocol_major=1, protocol_minor=2,
|
||||
capabilities=["status", "settings", "library", "library_progressive", "playback", "frame", "device_name", "wifi", "wifi_scan", "wifi_transport"],
|
||||
short_id=record["device_id"].replace("-", "")[:8], protocol_major=1, protocol_minor=3,
|
||||
capabilities=["status", "settings", "library", "library_progressive", "library_animation", "playback", "frame", "device_name", "wifi", "wifi_scan", "wifi_transport"],
|
||||
limits=dict(max_message_bytes=65536, library_page_size=50, preview_interval_ms=2000))
|
||||
|
||||
def settings(self):
|
||||
@@ -97,7 +98,7 @@ class MobileControl:
|
||||
("animation", [demo_animation()] + self.animations.list()["animations"])):
|
||||
for item in records:
|
||||
items.append(dict(type=kind, id=item["id"], name=item["name"], revision=item["revision"],
|
||||
is_demo=bool(item.get("is_demo", False)), playable=kind == "template" or item.get("frame_count", 0) > 0,
|
||||
frame_count=item.get("frame_count", 0), is_demo=bool(item.get("is_demo", False)), playable=kind == "template" or item.get("frame_count", 0) > 0,
|
||||
thumbnail_revision=item["revision"]))
|
||||
if self.library_order is not None:
|
||||
user_items = [item for item in items if not item["is_demo"]]
|
||||
@@ -205,6 +206,35 @@ class MobileControl:
|
||||
next_offset = offset + limit
|
||||
return dict(library_revision=revision, items=items[offset:next_offset],
|
||||
next_cursor=f"{revision}:{next_offset}" if next_offset < len(items) else None)
|
||||
if method in ("library.animation.info", "library.animation.chunk"):
|
||||
content = self._content(params)
|
||||
if content["type"] != "animation" or not content["frames"]:
|
||||
raise RpcError("NOT_FOUND", "内容没有动画帧")
|
||||
frames = content["frames"]
|
||||
if method.endswith(".info"):
|
||||
offset, limit = params.get("offset", 0), params.get("limit", 50)
|
||||
if type(offset) is not int or not 0 <= offset < len(frames) or type(limit) is not int or not 1 <= limit <= 50:
|
||||
raise RpcError("BAD_REQUEST", "帧分页参数无效")
|
||||
end = min(offset + limit, len(frames))
|
||||
return dict(revision=content["revision"], frame_count=len(frames),
|
||||
frames=[dict(index=i, duration_ms=frames[i]["duration_ms"]) for i in range(offset, end)],
|
||||
next_offset=end if end < len(frames) else None)
|
||||
index, offset, tier = params.get("frame_index"), params.get("offset", 0), params.get("tier")
|
||||
if type(index) is not int or not 0 <= index < len(frames) or type(offset) is not int or offset < 0 or tier not in ("preview", "full"):
|
||||
raise RpcError("BAD_REQUEST", "帧读取参数无效")
|
||||
image = self._preview_image(dict(type="animation", frames=[frames[index]]))
|
||||
if tier == "preview":
|
||||
image = image.resize((16, 16), Image.Resampling.LANCZOS)
|
||||
output = BytesIO()
|
||||
image.save(output, format="PNG", optimize=True)
|
||||
data = output.getvalue()
|
||||
if offset >= len(data):
|
||||
raise RpcError("BAD_REQUEST", "帧字节偏移无效")
|
||||
end = min(offset + 4096, len(data))
|
||||
return dict(revision=content["revision"], tier=tier, frame_index=index, offset=offset,
|
||||
total_bytes=len(data), sha256=hashlib.sha256(data).hexdigest(),
|
||||
data_base64=base64.b64encode(data[offset:end]).decode("ascii"),
|
||||
next_offset=end if end < len(data) else None)
|
||||
if method == "library.thumbnail":
|
||||
content = self._content(params)
|
||||
return self._png(self._preview_image(content))
|
||||
|
||||
Reference in New Issue
Block a user