Add optional photo providers, layout studio and scoped integrations

This commit is contained in:
Pigway
2026-10-08 23:18:11 +08:00
parent 3643fae86a
commit 69a0841868
38 changed files with 2843 additions and 41 deletions
@@ -95,14 +95,19 @@ def capabilities() -> tuple[OfficialCapability, ...]:
return tuple(
OfficialCapability(
method=method,
implemented=method in READ_OPERATIONS or method == "app.login",
implemented=method in READ_OPERATIONS
or method in {"app.login", "appFrame.setFrameCover"},
effect="read"
if method in READ_OPERATIONS
else "authentication"
if method == "app.login"
else "write"
if method == "appFrame.setFrameCover"
else "unverified",
evidence="live_verified"
if method in READ_OPERATIONS or method == "app.login"
else "mock_verified"
if method == "appFrame.setFrameCover"
else "apk_discovered",
)
for method in DISCOVERED_METHODS
@@ -17,8 +17,15 @@ class OfficialRPC:
def authorized(self) -> bool:
return bool(self._token)
def _call(self, method: str, params: dict) -> dict:
if method not in READ_OPERATIONS and method != "app.login":
def _call(self, method: str, params: dict, *, allow_write=False) -> dict:
if method == "appFrame.setFrameCover" and not allow_write:
raise FlowError(
E.UNSUPPORTED_CAPABILITY, "Use the explicit widget operation", 422
)
if method not in READ_OPERATIONS and method not in (
"app.login",
"appFrame.setFrameCover",
):
raise FlowError(
E.UNSUPPORTED_CAPABILITY, "Official operation is not enabled", 422
)
@@ -62,6 +69,10 @@ class OfficialRPC:
except FlowError:
raise
except (requests.RequestException, ValueError, AttributeError):
if method == "appFrame.setFrameCover":
raise FlowError(
E.WRITE_RESULT_UNKNOWN, "Official widget write result unknown", 409
) from None
raise FlowError(
E.CLOUD_UNAVAILABLE, "Official service query failed", 502
) from None
@@ -86,3 +97,10 @@ class OfficialRPC:
def widgets(self, robot_id: int) -> dict:
return self._call("appFrame.getFrameCovers", {"robotId": robot_id})
def set_widget(self, robot_id, cover_id, args):
return self._call(
"appFrame.setFrameCover",
{"robotId": robot_id, "coverId": cover_id, "args": args},
allow_write=True,
)
@@ -15,6 +15,7 @@ class WidgetReader:
self.rpc = OfficialRPC(token)
self._robot_id = robot_id
self.mock = mock
self.mock_selection = 188
self._cached = None
self._cached_at = 0.0
@@ -37,7 +38,8 @@ class WidgetReader:
source="mock",
configured=True,
catalog=catalog,
current=catalog[0],
current=next((x for x in catalog if x.id == self.mock_selection), None),
status="OK" if self.mock_selection else "NO_WIDGET",
current_verified=True,
)
if not self.rpc.authorized or self._robot_id is None: