python-xbox 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. python_xbox-0.1.0.dist-info/METADATA +217 -0
  2. python_xbox-0.1.0.dist-info/RECORD +64 -0
  3. python_xbox-0.1.0.dist-info/WHEEL +4 -0
  4. python_xbox-0.1.0.dist-info/entry_points.txt +6 -0
  5. python_xbox-0.1.0.dist-info/licenses/LICENSE +20 -0
  6. pythonxbox/__init__.py +4 -0
  7. pythonxbox/api/__init__.py +0 -0
  8. pythonxbox/api/client.py +166 -0
  9. pythonxbox/api/language.py +76 -0
  10. pythonxbox/api/provider/__init__.py +0 -0
  11. pythonxbox/api/provider/account/__init__.py +73 -0
  12. pythonxbox/api/provider/account/models.py +11 -0
  13. pythonxbox/api/provider/achievements/__init__.py +164 -0
  14. pythonxbox/api/provider/achievements/models.py +133 -0
  15. pythonxbox/api/provider/baseprovider.py +22 -0
  16. pythonxbox/api/provider/catalog/__init__.py +86 -0
  17. pythonxbox/api/provider/catalog/const.py +15 -0
  18. pythonxbox/api/provider/catalog/models.py +428 -0
  19. pythonxbox/api/provider/cqs/__init__.py +85 -0
  20. pythonxbox/api/provider/cqs/models.py +59 -0
  21. pythonxbox/api/provider/gameclips/__init__.py +167 -0
  22. pythonxbox/api/provider/gameclips/models.py +58 -0
  23. pythonxbox/api/provider/lists/__init__.py +71 -0
  24. pythonxbox/api/provider/lists/models.py +33 -0
  25. pythonxbox/api/provider/mediahub/__init__.py +64 -0
  26. pythonxbox/api/provider/mediahub/models.py +82 -0
  27. pythonxbox/api/provider/message/__init__.py +135 -0
  28. pythonxbox/api/provider/message/models.py +96 -0
  29. pythonxbox/api/provider/people/__init__.py +193 -0
  30. pythonxbox/api/provider/people/models.py +252 -0
  31. pythonxbox/api/provider/presence/__init__.py +110 -0
  32. pythonxbox/api/provider/presence/models.py +53 -0
  33. pythonxbox/api/provider/profile/__init__.py +140 -0
  34. pythonxbox/api/provider/profile/models.py +47 -0
  35. pythonxbox/api/provider/ratelimitedprovider.py +79 -0
  36. pythonxbox/api/provider/screenshots/__init__.py +167 -0
  37. pythonxbox/api/provider/screenshots/models.py +56 -0
  38. pythonxbox/api/provider/smartglass/__init__.py +402 -0
  39. pythonxbox/api/provider/smartglass/models.py +186 -0
  40. pythonxbox/api/provider/titlehub/__init__.py +143 -0
  41. pythonxbox/api/provider/titlehub/models.py +106 -0
  42. pythonxbox/api/provider/usersearch/__init__.py +29 -0
  43. pythonxbox/api/provider/usersearch/models.py +17 -0
  44. pythonxbox/api/provider/userstats/__init__.py +164 -0
  45. pythonxbox/api/provider/userstats/models.py +44 -0
  46. pythonxbox/authentication/__init__.py +0 -0
  47. pythonxbox/authentication/manager.py +161 -0
  48. pythonxbox/authentication/models.py +162 -0
  49. pythonxbox/authentication/xal.py +348 -0
  50. pythonxbox/common/__init__.py +0 -0
  51. pythonxbox/common/exceptions.py +59 -0
  52. pythonxbox/common/filetimes.py +81 -0
  53. pythonxbox/common/models.py +34 -0
  54. pythonxbox/common/ratelimits/__init__.py +268 -0
  55. pythonxbox/common/ratelimits/models.py +23 -0
  56. pythonxbox/common/request_signer.py +190 -0
  57. pythonxbox/common/signed_session.py +60 -0
  58. pythonxbox/py.typed +0 -0
  59. pythonxbox/scripts/__init__.py +15 -0
  60. pythonxbox/scripts/authenticate.py +159 -0
  61. pythonxbox/scripts/change_gamertag.py +111 -0
  62. pythonxbox/scripts/friends.py +80 -0
  63. pythonxbox/scripts/search.py +43 -0
  64. pythonxbox/scripts/xal.py +113 -0
@@ -0,0 +1,402 @@
1
+ """
2
+ SmartGlass - Control Registered Devices
3
+ """
4
+
5
+ from typing import TYPE_CHECKING
6
+ from uuid import uuid4
7
+
8
+ from httpx import Response
9
+
10
+ from pythonxbox.api.provider.baseprovider import BaseProvider
11
+ from pythonxbox.api.provider.smartglass.models import (
12
+ CommandResponse,
13
+ GuideTab,
14
+ InputKeyType,
15
+ InstalledPackagesList,
16
+ OperationStatusResponse,
17
+ SmartglassConsoleList,
18
+ SmartglassConsoleStatus,
19
+ StorageDevicesList,
20
+ VolumeDirection,
21
+ )
22
+
23
+ if TYPE_CHECKING:
24
+ from pythonxbox.api.client import XboxLiveClient
25
+
26
+
27
+ class SmartglassProvider(BaseProvider):
28
+ SG_URL = "https://xccs.xboxlive.com"
29
+ HEADERS_SG = {
30
+ "x-xbl-contract-version": "4",
31
+ "skillplatform": "RemoteManagement",
32
+ }
33
+
34
+ def __init__(self, client: "XboxLiveClient") -> None:
35
+ """
36
+ Initialize Baseclass, create smartglass session id
37
+
38
+ Args: Instance of XBL client
39
+ """
40
+ super().__init__(client)
41
+ self._smartglass_session_id = str(uuid4())
42
+
43
+ async def get_console_list(
44
+ self, include_storage_devices: bool = True, **kwargs
45
+ ) -> SmartglassConsoleList:
46
+ """
47
+ Get Console list
48
+
49
+ Args:
50
+ include_storage_devices: Include a list of storage devices in the response
51
+
52
+ Returns: Console List
53
+ """
54
+ params = {
55
+ "queryCurrentDevice": "false",
56
+ "includeStorageDevices": str(include_storage_devices).lower(),
57
+ }
58
+ resp = await self._fetch_list("devices", params, **kwargs)
59
+ return SmartglassConsoleList(**resp.json())
60
+
61
+ async def get_installed_apps(
62
+ self, device_id: str | None = None, **kwargs
63
+ ) -> InstalledPackagesList:
64
+ """
65
+ Get Installed Apps
66
+
67
+ Args:
68
+ device_id: ID of console (from console list)
69
+
70
+ Returns: Installed Apps
71
+ """
72
+ params = {}
73
+ if device_id:
74
+ params["deviceId"] = device_id
75
+ resp = await self._fetch_list("installedApps", params, **kwargs)
76
+ return InstalledPackagesList(**resp.json())
77
+
78
+ async def get_storage_devices(self, device_id: str, **kwargs) -> StorageDevicesList:
79
+ """
80
+ Get Installed Apps
81
+
82
+ Args:
83
+ device_id: ID of console (from console list)
84
+
85
+ Returns: Storage Devices list
86
+ """
87
+ params = {"deviceId": device_id}
88
+ resp = await self._fetch_list("storageDevices", params, **kwargs)
89
+ return StorageDevicesList(**resp.json())
90
+
91
+ async def get_console_status(
92
+ self, device_id: str, **kwargs
93
+ ) -> SmartglassConsoleStatus:
94
+ """
95
+ Get Console Status
96
+
97
+ Args:
98
+ device_id: ID of console (from console list)
99
+
100
+ Returns: Console Status
101
+ """
102
+ url = f"{self.SG_URL}/consoles/{device_id}"
103
+ resp = await self.client.session.get(url, headers=self.HEADERS_SG, **kwargs)
104
+ resp.raise_for_status()
105
+ return SmartglassConsoleStatus(**resp.json())
106
+
107
+ async def get_op_status(
108
+ self, device_id: str, op_id: str, **kwargs
109
+ ) -> OperationStatusResponse:
110
+ """
111
+ Get Operation Status
112
+
113
+ Args:
114
+ device_id: ID of console (from console list)
115
+ op_id: Operation ID (from previous command)
116
+
117
+ Returns: Operation Status
118
+ """
119
+ url = f"{self.SG_URL}/opStatus"
120
+ headers = {
121
+ "x-xbl-contract-version": "3",
122
+ "x-xbl-opId": op_id,
123
+ "x-xbl-deviceId": device_id,
124
+ }
125
+ resp = await self.client.session.get(url, headers=headers, **kwargs)
126
+ resp.raise_for_status()
127
+ return OperationStatusResponse(**resp.json())
128
+
129
+ async def wake_up(self, device_id: str, **kwargs) -> CommandResponse:
130
+ """
131
+ Wake Up Console
132
+
133
+ Args:
134
+ device_id: ID of console (from console list)
135
+
136
+ Returns: Command Response
137
+ """
138
+ return await self._send_one_shot_command(device_id, "Power", "WakeUp", **kwargs)
139
+
140
+ async def turn_off(self, device_id: str, **kwargs) -> CommandResponse:
141
+ """
142
+ Turn Off Console
143
+
144
+ Args:
145
+ device_id: ID of console (from console list)
146
+
147
+ Returns: Command Response
148
+ """
149
+ return await self._send_one_shot_command(
150
+ device_id, "Power", "TurnOff", **kwargs
151
+ )
152
+
153
+ async def reboot(self, device_id: str, **kwargs) -> CommandResponse:
154
+ """
155
+ Reboot Console
156
+
157
+ Args:
158
+ device_id: ID of console (from console list)
159
+
160
+ Returns: Command Response
161
+ """
162
+ return await self._send_one_shot_command(device_id, "Power", "Reboot", **kwargs)
163
+
164
+ async def mute(self, device_id: str, **kwargs) -> CommandResponse:
165
+ """
166
+ Mute
167
+
168
+ Args:
169
+ device_id: ID of console (from console list)
170
+
171
+ Returns: Command Response
172
+ """
173
+ return await self._send_one_shot_command(device_id, "Audio", "Mute", **kwargs)
174
+
175
+ async def unmute(self, device_id: str, **kwargs) -> CommandResponse:
176
+ """
177
+ Unmute
178
+
179
+ Args:
180
+ device_id: ID of console (from console list)
181
+
182
+ Returns: Command Response
183
+ """
184
+ return await self._send_one_shot_command(device_id, "Audio", "Unmute", **kwargs)
185
+
186
+ async def volume(
187
+ self, device_id: str, direction: VolumeDirection, amount: int = 1, **kwargs
188
+ ) -> CommandResponse:
189
+ """
190
+ Adjust Volume
191
+
192
+ Args:
193
+ device_id: ID of console (from console list)
194
+
195
+ Returns: Command Response
196
+ """
197
+ params = [{"direction": direction.value, "amount": str(amount)}]
198
+ return await self._send_one_shot_command(
199
+ device_id, "Audio", "Volume", params, **kwargs
200
+ )
201
+
202
+ async def play(self, device_id: str, **kwargs) -> CommandResponse:
203
+ """
204
+ Play (media controls)
205
+
206
+ Args:
207
+ device_id: ID of console (from console list)
208
+
209
+ Returns: Command Response
210
+ """
211
+ return await self._send_one_shot_command(device_id, "Media", "Play", **kwargs)
212
+
213
+ async def pause(self, device_id: str, **kwargs) -> CommandResponse:
214
+ """
215
+ Pause (media controls)
216
+
217
+ Args:
218
+ device_id: ID of console (from console list)
219
+
220
+ Returns: Command Response
221
+ """
222
+ return await self._send_one_shot_command(device_id, "Media", "Pause", **kwargs)
223
+
224
+ async def previous(self, device_id: str, **kwargs) -> CommandResponse:
225
+ """
226
+ Previous (media controls)
227
+
228
+ Args:
229
+ device_id: ID of console (from console list)
230
+
231
+ Returns: Command Response
232
+ """
233
+ return await self._send_one_shot_command(
234
+ device_id, "Media", "Previous", **kwargs
235
+ )
236
+
237
+ async def next(self, device_id: str, **kwargs) -> CommandResponse:
238
+ """
239
+ Next (media controls)
240
+
241
+ Args:
242
+ device_id: ID of console (from console list)
243
+
244
+ Returns: Command Response
245
+ """
246
+ return await self._send_one_shot_command(device_id, "Media", "Next", **kwargs)
247
+
248
+ async def go_home(self, device_id: str, **kwargs) -> CommandResponse:
249
+ """
250
+ Go Home
251
+
252
+ Args:
253
+ device_id: ID of console (from console list)
254
+
255
+ Returns: Command Response
256
+ """
257
+ return await self._send_one_shot_command(device_id, "Shell", "GoHome", **kwargs)
258
+
259
+ async def go_back(self, device_id: str, **kwargs) -> CommandResponse:
260
+ """
261
+ Go Back
262
+
263
+ Args:
264
+ device_id: ID of console (from console list)
265
+
266
+ Returns:
267
+ :class:`SmartglassConsoleStatus`: Command Response
268
+ """
269
+ return await self._send_one_shot_command(device_id, "Shell", "GoBack", **kwargs)
270
+
271
+ async def show_guide_tab(
272
+ self, device_id: str, tab: GuideTab = GuideTab.Guide, **kwargs
273
+ ) -> CommandResponse:
274
+ """
275
+ Show Guide Tab
276
+
277
+ Args:
278
+ device_id: ID of console (from console list)
279
+
280
+ Returns: Command Response
281
+ """
282
+ params = [{"tabName": tab.value}]
283
+ return await self._send_one_shot_command(
284
+ device_id, "Shell", "ShowGuideTab", params, **kwargs
285
+ )
286
+
287
+ async def press_button(
288
+ self, device_id: str, button: InputKeyType, **kwargs
289
+ ) -> CommandResponse:
290
+ """
291
+ Press Button
292
+
293
+ Args:
294
+ device_id: ID of console (from console list)
295
+
296
+ Returns: Command Response
297
+ """
298
+ params = [{"keyType": button.value}]
299
+ return await self._send_one_shot_command(
300
+ device_id, "Shell", "InjectKey", params, **kwargs
301
+ )
302
+
303
+ async def insert_text(self, device_id: str, text: str, **kwargs) -> CommandResponse:
304
+ """
305
+ Insert Text
306
+
307
+ Args:
308
+ device_id: ID of console (from console list)
309
+
310
+ Returns: Command Response
311
+ """
312
+ params = [{"replacementString": text}]
313
+ return await self._send_one_shot_command(
314
+ device_id, "Shell", "InjectString", params, **kwargs
315
+ )
316
+
317
+ async def launch_app(
318
+ self, device_id: str, one_store_product_id: str, **kwargs
319
+ ) -> CommandResponse:
320
+ """
321
+ Launch Application
322
+
323
+ Args:
324
+ device_id: ID of console (from console list)
325
+ one_store_product_id: OneStoreProductID for the app to launch
326
+
327
+ Returns: Command Response
328
+ """
329
+ params = [{"oneStoreProductId": one_store_product_id}]
330
+ return await self._send_one_shot_command(
331
+ device_id,
332
+ "Shell",
333
+ "ActivateApplicationWithOneStoreProductId",
334
+ params,
335
+ **kwargs,
336
+ )
337
+
338
+ async def show_tv_guide(self, device_id: str, **kwargs) -> CommandResponse:
339
+ """
340
+ Show TV Guide
341
+
342
+ Args:
343
+ device_id: ID of console (from console list)
344
+
345
+ Returns: Command Response
346
+ """
347
+ return await self._send_one_shot_command(device_id, "TV", "ShowGuide", **kwargs)
348
+
349
+ async def _fetch_list(
350
+ self, list_name: str, params: dict | None = None, **kwargs
351
+ ) -> Response:
352
+ """
353
+ Fetch arbitrary list
354
+
355
+ Args:
356
+ list_name: name of list
357
+ params: query params
358
+
359
+ Returns:
360
+ :class:`httpx.Response`: HTTP Response
361
+ """
362
+ url = f"{self.SG_URL}/lists/{list_name}"
363
+ resp = await self.client.session.get(
364
+ url, params=params, headers=self.HEADERS_SG, **kwargs
365
+ )
366
+ resp.raise_for_status()
367
+ return resp
368
+
369
+ async def _send_one_shot_command(
370
+ self,
371
+ device_id: str,
372
+ command_type: str,
373
+ command: str,
374
+ params: list[dict] | None = None,
375
+ **kwargs,
376
+ ) -> CommandResponse:
377
+ """
378
+ Send One Shot command to console
379
+
380
+ Args:
381
+ device_id: ID of console (from console list)
382
+ type: type of command
383
+ command: name of command
384
+ params: command parameters
385
+
386
+ Returns: Command Response
387
+ """
388
+ url = f"{self.SG_URL}/commands"
389
+ body = {
390
+ "destination": "Xbox",
391
+ "type": command_type,
392
+ "command": command,
393
+ "sessionId": self._smartglass_session_id,
394
+ "sourceId": "com.microsoft.smartglass",
395
+ "parameters": params or [{}],
396
+ "linkedXboxId": device_id,
397
+ }
398
+ resp = await self.client.session.post(
399
+ url, json=body, headers=self.HEADERS_SG, **kwargs
400
+ )
401
+ resp.raise_for_status()
402
+ return CommandResponse(**resp.json())
@@ -0,0 +1,186 @@
1
+ from datetime import datetime
2
+ from enum import Enum
3
+
4
+ from pythonxbox.common.models import CamelCaseModel
5
+
6
+ # Responses
7
+
8
+
9
+ class ConsoleType(str, Enum):
10
+ XboxOne = "XboxOne"
11
+ XboxOneS = "XboxOneS"
12
+ XboxOneSDigital = "XboxOneSDigital"
13
+ XboxOneX = "XboxOneX"
14
+ XboxSeriesS = "XboxSeriesS"
15
+ XboxSeriesX = "XboxSeriesX"
16
+
17
+
18
+ class PowerState(str, Enum):
19
+ Unknown = "Unknown"
20
+ On = "On"
21
+ Off = "Off"
22
+ ConnectedStandby = "ConnectedStandby"
23
+ SystemUpdate = "SystemUpdate"
24
+
25
+
26
+ class PlaybackState(str, Enum):
27
+ Unknown = "Unknown"
28
+ Playing = "Playing"
29
+ Paused = "Paused"
30
+ Stopped = "Stopped"
31
+
32
+
33
+ class ErrorCode(str, Enum):
34
+ OK = "OK"
35
+ CurrentConsoleNotFound = "CurrentConsoleNotFound"
36
+ RemoteManagementDisabled = "RemoteManagementDisabled"
37
+ XboxDataNotFound = "XboxDataNotFound"
38
+ XboxNotPaired = "XboxNotPaired"
39
+
40
+
41
+ class OpStatus(str, Enum):
42
+ Paused = "Paused"
43
+ OffConsoleError = "OffConsoleError"
44
+ Pending = "Pending"
45
+ TimedOut = "TimedOut"
46
+ Error = "Error"
47
+ Succeeded = "Succeeded"
48
+
49
+
50
+ class SmartglassApiStatus(CamelCaseModel):
51
+ error_code: str
52
+ error_message: str | None = None
53
+
54
+
55
+ class StorageDevice(CamelCaseModel):
56
+ storage_device_id: str
57
+ storage_device_name: str
58
+ is_default: bool
59
+ total_space_bytes: float
60
+ free_space_bytes: float
61
+
62
+
63
+ class SmartglassConsole(CamelCaseModel):
64
+ id: str
65
+ name: str
66
+ console_type: ConsoleType
67
+ power_state: PowerState
68
+ console_streaming_enabled: bool
69
+ digital_assistant_remote_control_enabled: bool
70
+ remote_management_enabled: bool
71
+ storage_devices: list[StorageDevice] | None = None
72
+
73
+
74
+ class SmartglassConsoleList(CamelCaseModel):
75
+ agent_user_id: str | None = None
76
+ result: list[SmartglassConsole]
77
+ status: SmartglassApiStatus
78
+
79
+
80
+ class SmartglassConsoleStatus(CamelCaseModel):
81
+ power_state: PowerState
82
+ console_streaming_enabled: bool
83
+ digital_assistant_remote_control_enabled: bool
84
+ remote_management_enabled: bool
85
+ focus_app_aumid: str
86
+ is_tv_configured: bool
87
+ login_state: str | None = None
88
+ playback_state: PlaybackState
89
+ power_state: PowerState
90
+ storage_devices: list[StorageDevice] | None = None
91
+ status: SmartglassApiStatus
92
+
93
+
94
+ class InstalledPackage(CamelCaseModel):
95
+ one_store_product_id: str | None = None
96
+ title_id: int
97
+ aumid: str | None = None
98
+ last_active_time: datetime | None = None
99
+ is_game: bool
100
+ name: str | None = None
101
+ content_type: str
102
+ instance_id: str
103
+ storage_device_id: str
104
+ unique_id: str
105
+ legacy_product_id: str | None = None
106
+ version: int
107
+ size_in_bytes: int
108
+ install_time: datetime
109
+ update_time: datetime | None = None
110
+ parent_id: str | None = None
111
+
112
+
113
+ class InstalledPackagesList(CamelCaseModel):
114
+ result: list[InstalledPackage]
115
+ status: SmartglassApiStatus
116
+ agent_user_id: str | None = None
117
+
118
+
119
+ class StorageDevicesList(CamelCaseModel):
120
+ device_id: str
121
+ result: list[StorageDevice]
122
+ status: SmartglassApiStatus
123
+
124
+
125
+ class OpStatusNode(CamelCaseModel):
126
+ operation_status: OpStatus
127
+ op_id: str
128
+ originating_session_id: str
129
+ command: str
130
+ succeeded: bool
131
+ console_status_code: int | None = None
132
+ xccs_error_code: ErrorCode | None = None
133
+ h_result: int | None = None
134
+ message: str | None = None
135
+
136
+
137
+ class OperationStatusResponse(CamelCaseModel):
138
+ op_status_list: list[OpStatusNode]
139
+ status: SmartglassApiStatus
140
+
141
+
142
+ class CommandDestination(CamelCaseModel):
143
+ id: str
144
+ name: str
145
+ power_state: PowerState
146
+ remote_management_enabled: bool
147
+ console_streaming_enabled: bool
148
+ console_type: ConsoleType
149
+ wireless_warning: str | None = None
150
+ out_of_home_warning: str | None = None
151
+
152
+
153
+ class CommandResponse(CamelCaseModel):
154
+ result: str | None = None
155
+ ui_text: str | None = None
156
+ destination: CommandDestination
157
+ user_info: str | None = None
158
+ op_id: str
159
+ status: SmartglassApiStatus
160
+
161
+
162
+ # Requests
163
+
164
+
165
+ class VolumeDirection(str, Enum):
166
+ Up = "Up"
167
+ Down = "Down"
168
+
169
+
170
+ class InputKeyType(str, Enum):
171
+ Guide = "Guide"
172
+ Menu = "Menu"
173
+ View = "View"
174
+ A = "A"
175
+ B = "B"
176
+ X = "X"
177
+ Y = "Y"
178
+ Up = "Up"
179
+ Down = "Down"
180
+ Left = "Left"
181
+ Right = "Right"
182
+ Nexus = "Nexus"
183
+
184
+
185
+ class GuideTab(str, Enum):
186
+ Guide = "Guide"