pynintendoparental 0.6.9__py3-none-any.whl → 0.7.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.
- pynintendoparental/__init__.py +1 -4
- pynintendoparental/_version.py +1 -1
- pynintendoparental/api.py +155 -29
- pynintendoparental/device.py +21 -30
- {pynintendoparental-0.6.9.dist-info → pynintendoparental-0.7.0.dist-info}/METADATA +1 -1
- {pynintendoparental-0.6.9.dist-info → pynintendoparental-0.7.0.dist-info}/RECORD +9 -9
- {pynintendoparental-0.6.9.dist-info → pynintendoparental-0.7.0.dist-info}/WHEEL +0 -0
- {pynintendoparental-0.6.9.dist-info → pynintendoparental-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {pynintendoparental-0.6.9.dist-info → pynintendoparental-0.7.0.dist-info}/top_level.txt +0 -0
pynintendoparental/__init__.py
CHANGED
|
@@ -30,10 +30,7 @@ class NintendoParental:
|
|
|
30
30
|
dev.device_id,
|
|
31
31
|
err)
|
|
32
32
|
|
|
33
|
-
response = await self._api.
|
|
34
|
-
endpoint="get_account_devices",
|
|
35
|
-
ACCOUNT_ID=self.account_id
|
|
36
|
-
)
|
|
33
|
+
response = await self._api.async_get_account_devices()
|
|
37
34
|
|
|
38
35
|
for dev_raw in response["json"]["items"]:
|
|
39
36
|
device: Device = Device.from_device_response(dev_raw, self._api)
|
pynintendoparental/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.7.0"
|
pynintendoparental/api.py
CHANGED
|
@@ -25,11 +25,15 @@ def _check_http_success(status: int) -> bool:
|
|
|
25
25
|
class Api:
|
|
26
26
|
"""Nintendo Parental Controls API."""
|
|
27
27
|
|
|
28
|
-
def __init__(self, auth, tz, lang):
|
|
28
|
+
def __init__(self, auth, tz, lang, session: aiohttp.ClientSession=None):
|
|
29
29
|
"""INIT"""
|
|
30
30
|
self._auth: Authenticator = auth
|
|
31
31
|
self._tz = tz
|
|
32
32
|
self._language = lang
|
|
33
|
+
if session is None:
|
|
34
|
+
session = aiohttp.ClientSession()
|
|
35
|
+
self._session_created_internally = True
|
|
36
|
+
self._session = session
|
|
33
37
|
|
|
34
38
|
@property
|
|
35
39
|
def _auth_token(self) -> str:
|
|
@@ -41,6 +45,29 @@ class Api:
|
|
|
41
45
|
"""Return the account id."""
|
|
42
46
|
return self._auth.account_id
|
|
43
47
|
|
|
48
|
+
@property
|
|
49
|
+
def _headers(self) -> dict:
|
|
50
|
+
"""Return web request headers."""
|
|
51
|
+
return {
|
|
52
|
+
"User-Agent": USER_AGENT,
|
|
53
|
+
"X-Moon-App-Id": MOBILE_APP_PKG,
|
|
54
|
+
"X-Moon-Os": OS_NAME,
|
|
55
|
+
"X-Moon-Os-Version": OS_VERSION,
|
|
56
|
+
"X-Moon-Model": DEVICE_MODEL,
|
|
57
|
+
"X-Moon-App-Display-Version": MOBILE_APP_VERSION,
|
|
58
|
+
"X-Moon-App-Internal-Version": MOBILE_APP_BUILD,
|
|
59
|
+
"X-Moon-TimeZone": self._tz,
|
|
60
|
+
"X-Moon-Os-Language": self._language,
|
|
61
|
+
"X-Moon-App-Language": self._language,
|
|
62
|
+
"Authorization": self._auth_token
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async def async_close(self):
|
|
66
|
+
"""Closes the underlying aiohttp.ClientSession if it was created by this instance."""
|
|
67
|
+
if hasattr(self, '_session_created_internally') and self._session_created_internally and self._session and not self._session.closed:
|
|
68
|
+
await self._session.close()
|
|
69
|
+
self._session = None # Optional: clear the session attribute
|
|
70
|
+
|
|
44
71
|
async def send_request(self, endpoint: str, body: object=None, **kwargs):
|
|
45
72
|
"""Sends a request to a given endpoint."""
|
|
46
73
|
_LOGGER.debug("Sending request to %s", endpoint)
|
|
@@ -62,35 +89,134 @@ class Api:
|
|
|
62
89
|
"json": "",
|
|
63
90
|
"headers": ""
|
|
64
91
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
method=e_point.get("method"),
|
|
80
|
-
url=url,
|
|
81
|
-
json=body
|
|
82
|
-
) as response:
|
|
83
|
-
_LOGGER.debug("%s request to %s status code %s",
|
|
84
|
-
e_point.get("method"),
|
|
85
|
-
url,
|
|
86
|
-
response.status)
|
|
87
|
-
if _check_http_success(response.status):
|
|
88
|
-
resp["status"] = response.status
|
|
89
|
-
resp["text"] = await response.text()
|
|
92
|
+
self._session.headers.update(self._headers)
|
|
93
|
+
async with self._session.request(
|
|
94
|
+
method=e_point.get("method"),
|
|
95
|
+
url=url,
|
|
96
|
+
json=body
|
|
97
|
+
) as response:
|
|
98
|
+
_LOGGER.debug("%s request to %s status code %s",
|
|
99
|
+
e_point.get("method"),
|
|
100
|
+
url,
|
|
101
|
+
response.status)
|
|
102
|
+
if _check_http_success(response.status):
|
|
103
|
+
resp["status"] = response.status
|
|
104
|
+
resp["text"] = await response.text()
|
|
105
|
+
try:
|
|
90
106
|
resp["json"] = await response.json()
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
except (aiohttp.ContentTypeError, ValueError) as e:
|
|
108
|
+
_LOGGER.warning(
|
|
109
|
+
"""Failed to decode JSON response from %s.
|
|
110
|
+
Status: %s, Error: %s.
|
|
111
|
+
Response text: %s...""",
|
|
112
|
+
url, response.status, e, resp['text'][:200]
|
|
113
|
+
)
|
|
114
|
+
resp["json"] = {}
|
|
115
|
+
resp["headers"] = response.headers
|
|
116
|
+
else:
|
|
117
|
+
raise HttpException("HTTP Error", response.status, await response.text())
|
|
94
118
|
|
|
95
119
|
# now return the resp dict
|
|
96
120
|
return resp
|
|
121
|
+
|
|
122
|
+
async def async_get_account_details(self) -> dict:
|
|
123
|
+
"""Get account details."""
|
|
124
|
+
return await self.send_request(
|
|
125
|
+
endpoint="get_account_details",
|
|
126
|
+
ACCOUNT_ID=self.account_id
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
async def async_get_account_devices(self) -> dict:
|
|
130
|
+
"""Get account devices."""
|
|
131
|
+
return await self.send_request(
|
|
132
|
+
endpoint="get_account_devices",
|
|
133
|
+
ACCOUNT_ID=self.account_id
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
async def async_get_account_device(self, device_id: str) -> dict:
|
|
137
|
+
"""Get account device."""
|
|
138
|
+
return await self.send_request(
|
|
139
|
+
endpoint="get_account_device",
|
|
140
|
+
ACCOUNT_ID=self.account_id,
|
|
141
|
+
DEVICE_ID=device_id
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
async def async_get_device_daily_summaries(self, device_id: str) -> dict:
|
|
145
|
+
"""Get device daily summaries."""
|
|
146
|
+
return await self.send_request(
|
|
147
|
+
endpoint="get_device_daily_summaries",
|
|
148
|
+
DEVICE_ID=device_id
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
async def async_get_device_monthly_summaries(self, device_id: str) -> dict:
|
|
152
|
+
"""Get device monthly summaries."""
|
|
153
|
+
return await self.send_request(
|
|
154
|
+
endpoint="get_device_monthly_summaries",
|
|
155
|
+
DEVICE_ID=device_id
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
async def async_get_device_parental_control_setting(self, device_id: str) -> dict:
|
|
159
|
+
"""Get device parental control setting."""
|
|
160
|
+
return await self.send_request(
|
|
161
|
+
endpoint="get_device_parental_control_setting",
|
|
162
|
+
DEVICE_ID=device_id
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
async def async_get_device_parental_control_setting_state(self, device_id: str) -> dict:
|
|
166
|
+
"""Get device parental control setting state."""
|
|
167
|
+
return await self.send_request(
|
|
168
|
+
endpoint="get_device_parental_control_setting_state",
|
|
169
|
+
DEVICE_ID=device_id
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
async def async_get_device_alarm_setting_state(self, device_id: str) -> dict:
|
|
173
|
+
"""Get device alarm setting state."""
|
|
174
|
+
return await self.send_request(
|
|
175
|
+
endpoint="get_device_alarm_setting_state",
|
|
176
|
+
DEVICE_ID=device_id
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
async def async_get_device_monthly_summary(self, device_id: str, year: int, month: int) -> dict:
|
|
180
|
+
"""Get device monthly summary."""
|
|
181
|
+
return await self.send_request(
|
|
182
|
+
endpoint="get_device_monthly_summary",
|
|
183
|
+
DEVICE_ID=device_id,
|
|
184
|
+
YEAR=year,
|
|
185
|
+
MONTH=f"{month:02d}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
async def async_set_device_parental_control_setting(
|
|
189
|
+
self,
|
|
190
|
+
device_id: str,
|
|
191
|
+
settings: dict
|
|
192
|
+
) -> dict:
|
|
193
|
+
"""Update device parental control setting."""
|
|
194
|
+
return await self.send_request(
|
|
195
|
+
endpoint="update_device_parental_control_setting",
|
|
196
|
+
DEVICE_ID=device_id,
|
|
197
|
+
body=settings
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
async def async_set_device_whitelisted_applications(
|
|
201
|
+
self,
|
|
202
|
+
device_id: str,
|
|
203
|
+
applications: dict
|
|
204
|
+
) -> dict:
|
|
205
|
+
"""Update device whitelisted applications."""
|
|
206
|
+
return await self.send_request(
|
|
207
|
+
endpoint="update_device_whitelisted_applications",
|
|
208
|
+
DEVICE_ID=device_id,
|
|
209
|
+
body=applications
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
async def async_set_device_alarm_setting_state(
|
|
213
|
+
self,
|
|
214
|
+
device_id: str,
|
|
215
|
+
alarm_state: dict
|
|
216
|
+
) -> dict:
|
|
217
|
+
"""Update device alarm setting state."""
|
|
218
|
+
return await self.send_request(
|
|
219
|
+
endpoint="update_device_alarm_setting_state",
|
|
220
|
+
DEVICE_ID=device_id,
|
|
221
|
+
body=alarm_state
|
|
222
|
+
)
|
pynintendoparental/device.py
CHANGED
|
@@ -115,10 +115,9 @@ class Device:
|
|
|
115
115
|
async def _set_parental_control_setting(self):
|
|
116
116
|
"""Shortcut method to deduplicate code used to update parental control settings."""
|
|
117
117
|
_LOGGER.debug(">> Device._set_parental_control_setting()")
|
|
118
|
-
await self._api.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
DEVICE_ID=self.device_id
|
|
118
|
+
await self._api.async_set_device_parental_control_setting(
|
|
119
|
+
settings=self._get_update_parental_control_setting_body(),
|
|
120
|
+
device_id=self.device_id
|
|
122
121
|
)
|
|
123
122
|
await self._get_parental_control_setting()
|
|
124
123
|
|
|
@@ -209,9 +208,8 @@ class Device:
|
|
|
209
208
|
async def _get_parental_control_setting(self):
|
|
210
209
|
"""Retreives parental control settings from the API."""
|
|
211
210
|
_LOGGER.debug(">> Device._get_parental_control_setting()")
|
|
212
|
-
response = await self._api.
|
|
213
|
-
|
|
214
|
-
DEVICE_ID=self.device_id
|
|
211
|
+
response = await self._api.async_get_device_parental_control_setting(
|
|
212
|
+
device_id=self.device_id
|
|
215
213
|
)
|
|
216
214
|
self.parental_control_settings = response["json"]
|
|
217
215
|
if "bedtimeStartingTime" in self.parental_control_settings["playTimerRegulations"]:
|
|
@@ -235,9 +233,8 @@ class Device:
|
|
|
235
233
|
async def _get_daily_summaries(self):
|
|
236
234
|
"""Retrieve daily summaries."""
|
|
237
235
|
_LOGGER.debug(">> Device._get_daily_summaries()")
|
|
238
|
-
response = await self._api.
|
|
239
|
-
|
|
240
|
-
DEVICE_ID = self.device_id
|
|
236
|
+
response = await self._api.async_get_device_daily_summaries(
|
|
237
|
+
device_id = self.device_id
|
|
241
238
|
)
|
|
242
239
|
self.daily_summaries = response["json"]["items"]
|
|
243
240
|
_LOGGER.debug("New daily summary %s", self.daily_summaries)
|
|
@@ -334,10 +331,8 @@ class Device:
|
|
|
334
331
|
_LOGGER.debug(">> Device._get_extras()")
|
|
335
332
|
if self.alarms_enabled is not None:
|
|
336
333
|
# first refresh can come from self.extra without http request
|
|
337
|
-
response = await self._api.
|
|
338
|
-
|
|
339
|
-
ACCOUNT_ID = self._api.account_id,
|
|
340
|
-
DEVICE_ID = self.device_id
|
|
334
|
+
response = await self._api.async_get_account_device(
|
|
335
|
+
device_id = self.device_id
|
|
341
336
|
)
|
|
342
337
|
self.extra = response["json"]
|
|
343
338
|
status = self.extra["device"]["alarmSetting"]["visibility"]
|
|
@@ -351,9 +346,8 @@ class Device:
|
|
|
351
346
|
_LOGGER.debug(">> Device.get_monthly_summary(search_date=%s)", search_date)
|
|
352
347
|
latest = False
|
|
353
348
|
if search_date is None:
|
|
354
|
-
response = await self._api.
|
|
355
|
-
|
|
356
|
-
DEVICE_ID=self.device_id
|
|
349
|
+
response = await self._api.async_get_device_monthly_summaries(
|
|
350
|
+
device_id=self.device_id
|
|
357
351
|
)
|
|
358
352
|
_LOGGER.debug("Available monthly summaries: %s", response)
|
|
359
353
|
response = response["json"]["indexes"][0]
|
|
@@ -362,11 +356,10 @@ class Device:
|
|
|
362
356
|
latest = True
|
|
363
357
|
|
|
364
358
|
try:
|
|
365
|
-
response = await self._api.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
MONTH=str(search_date.month).zfill(2)
|
|
359
|
+
response = await self._api.async_get_device_monthly_summary(
|
|
360
|
+
device_id = self.device_id,
|
|
361
|
+
year=search_date.year,
|
|
362
|
+
month=search_date.month
|
|
370
363
|
)
|
|
371
364
|
_LOGGER.debug("Monthly summary query complete for device %s: %s",
|
|
372
365
|
self.device_id,
|
|
@@ -385,12 +378,11 @@ class Device:
|
|
|
385
378
|
"""Updates the alarm state for the device."""
|
|
386
379
|
_LOGGER.debug(">> Device.set_alarm_state(state=%s)",
|
|
387
380
|
state)
|
|
388
|
-
await self._api.
|
|
389
|
-
|
|
390
|
-
body={
|
|
381
|
+
await self._api.async_set_device_alarm_setting_state(
|
|
382
|
+
alarm_state={
|
|
391
383
|
"status": str(state)
|
|
392
384
|
},
|
|
393
|
-
|
|
385
|
+
device_id = self.device_id
|
|
394
386
|
)
|
|
395
387
|
|
|
396
388
|
async def set_whitelisted_application(self, app_id: str, allowed: bool):
|
|
@@ -403,10 +395,9 @@ class Device:
|
|
|
403
395
|
# take a snapshot of the whitelisted apps state
|
|
404
396
|
current_state = self.parental_control_settings["whitelistedApplications"]
|
|
405
397
|
current_state[app_id]["safeLaunch"] = "ALLOW" if allowed else "NONE"
|
|
406
|
-
await self._api.
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
DEVICE_ID=self.device_id
|
|
398
|
+
await self._api.async_set_device_whitelisted_applications(
|
|
399
|
+
applications=current_state,
|
|
400
|
+
device_id=self.device_id
|
|
410
401
|
)
|
|
411
402
|
await self._get_parental_control_setting()
|
|
412
403
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
pynintendoparental/__init__.py,sha256=
|
|
2
|
-
pynintendoparental/_version.py,sha256=
|
|
3
|
-
pynintendoparental/api.py,sha256=
|
|
1
|
+
pynintendoparental/__init__.py,sha256=bvsCZ4_n8Ud6M1u3whiN14tAW5KSTnVH57CAUvWCIwk,2028
|
|
2
|
+
pynintendoparental/_version.py,sha256=RaANGbRu5e-vehwXI1-Qe2ggPPfs1TQaZj072JdbLk4,22
|
|
3
|
+
pynintendoparental/api.py,sha256=z26VnHFDQzGSUKAiWKLL1dmhbZbSZGwj7qKT4yYCy4k,7810
|
|
4
4
|
pynintendoparental/application.py,sha256=l-oVwM4hrVVUf_2djQ7rJVya7LQP38yhaLPAWt8V8TY,3941
|
|
5
5
|
pynintendoparental/const.py,sha256=41Mn9ptZVFhQ2h6QcyFgcp5UaDyst0jED7wCn5w6kxQ,2313
|
|
6
|
-
pynintendoparental/device.py,sha256=
|
|
6
|
+
pynintendoparental/device.py,sha256=w-AHD0c6bNU_thnJbeIzgRNE8SRP-tvIWMqpolM6cog,22174
|
|
7
7
|
pynintendoparental/enum.py,sha256=lzacGti7fcQqAOROjB9782De7bOMYKSEM61SQd6aYG4,401
|
|
8
8
|
pynintendoparental/exceptions.py,sha256=5M3y0OLSRvX9Ly8D4981HqiKTNxxVqeyzPIuAekQ6J8,410
|
|
9
9
|
pynintendoparental/player.py,sha256=n0wabGjCZumVT84sL8_Wag738A7OQlPnnL1H49U64Bg,1713
|
|
@@ -11,8 +11,8 @@ pynintendoparental/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
11
11
|
pynintendoparental/utils.py,sha256=5-EP_rmPnSSWtbi18Y226GtjLhF3PLONKwmRdiy7m2c,198
|
|
12
12
|
pynintendoparental/authenticator/__init__.py,sha256=SPnvXhcpZeikL_-0Wmw2h3SEkBYbQfY6GfYMv9WtDdU,6964
|
|
13
13
|
pynintendoparental/authenticator/const.py,sha256=4QhojJ_dTAFwlS9LPnRxm6wWc_wjrme8cICvMnKGwVE,823
|
|
14
|
-
pynintendoparental-0.
|
|
15
|
-
pynintendoparental-0.
|
|
16
|
-
pynintendoparental-0.
|
|
17
|
-
pynintendoparental-0.
|
|
18
|
-
pynintendoparental-0.
|
|
14
|
+
pynintendoparental-0.7.0.dist-info/licenses/LICENSE,sha256=zsxHgHVMnyWq121yND8zBl9Rl9H6EF2K9N51B2ZSm_k,1071
|
|
15
|
+
pynintendoparental-0.7.0.dist-info/METADATA,sha256=5euaNXOHNlETRkKWipmX8Kgc24xY__9an2ZqRiUBa-k,1871
|
|
16
|
+
pynintendoparental-0.7.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
17
|
+
pynintendoparental-0.7.0.dist-info/top_level.txt,sha256=QQ5bAl-Ljso16P8KLf1NHrFmKk9jLT7bVJG_rVlIXWk,19
|
|
18
|
+
pynintendoparental-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|