pynintendoparental 0.7.2__tar.gz → 1.0.0__tar.gz
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-0.7.2 → pynintendoparental-1.0.0}/PKG-INFO +1 -1
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/__init__.py +2 -2
- pynintendoparental-1.0.0/pynintendoparental/_version.py +1 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/api.py +20 -31
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/authenticator/__init__.py +4 -4
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/authenticator/const.py +15 -1
- pynintendoparental-1.0.0/pynintendoparental/const.py +56 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/device.py +50 -83
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/player.py +9 -9
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/PKG-INFO +1 -1
- pynintendoparental-0.7.2/pynintendoparental/_version.py +0 -1
- pynintendoparental-0.7.2/pynintendoparental/const.py +0 -68
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/LICENSE +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/README.md +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/application.py +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/enum.py +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/exceptions.py +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/py.typed +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/utils.py +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/SOURCES.txt +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/dependency_links.txt +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/requires.txt +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/top_level.txt +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pyproject.toml +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/setup.cfg +0 -0
- {pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/setup.py +0 -0
|
@@ -26,13 +26,13 @@ class NintendoParental:
|
|
|
26
26
|
try:
|
|
27
27
|
await dev.update()
|
|
28
28
|
except Exception as err:
|
|
29
|
-
_LOGGER.
|
|
29
|
+
_LOGGER.exception("Error updating device %s: %s",
|
|
30
30
|
dev.device_id,
|
|
31
31
|
err)
|
|
32
32
|
|
|
33
33
|
response = await self._api.async_get_account_devices()
|
|
34
34
|
|
|
35
|
-
for dev_raw in response["json"]["
|
|
35
|
+
for dev_raw in response["json"]["ownedDevices"]:
|
|
36
36
|
device: Device = Device.from_device_response(dev_raw, self._api)
|
|
37
37
|
if self.devices.get(device.device_id, None) is None:
|
|
38
38
|
_LOGGER.debug("Creating new device %s", device.device_id)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
|
@@ -112,15 +112,13 @@ class Api:
|
|
|
112
112
|
async def async_get_account_devices(self) -> dict:
|
|
113
113
|
"""Get account devices."""
|
|
114
114
|
return await self.send_request(
|
|
115
|
-
endpoint="get_account_devices"
|
|
116
|
-
ACCOUNT_ID=self.account_id
|
|
115
|
+
endpoint="get_account_devices"
|
|
117
116
|
)
|
|
118
117
|
|
|
119
118
|
async def async_get_account_device(self, device_id: str) -> dict:
|
|
120
119
|
"""Get account device."""
|
|
121
120
|
return await self.send_request(
|
|
122
121
|
endpoint="get_account_device",
|
|
123
|
-
ACCOUNT_ID=self.account_id,
|
|
124
122
|
DEVICE_ID=device_id
|
|
125
123
|
)
|
|
126
124
|
|
|
@@ -152,13 +150,6 @@ class Api:
|
|
|
152
150
|
DEVICE_ID=device_id
|
|
153
151
|
)
|
|
154
152
|
|
|
155
|
-
async def async_get_device_alarm_setting_state(self, device_id: str) -> dict:
|
|
156
|
-
"""Get device alarm setting state."""
|
|
157
|
-
return await self.send_request(
|
|
158
|
-
endpoint="get_device_alarm_setting_state",
|
|
159
|
-
DEVICE_ID=device_id
|
|
160
|
-
)
|
|
161
|
-
|
|
162
153
|
async def async_get_device_monthly_summary(self, device_id: str, year: int, month: int) -> dict:
|
|
163
154
|
"""Get device monthly summary."""
|
|
164
155
|
return await self.send_request(
|
|
@@ -168,38 +159,36 @@ class Api:
|
|
|
168
159
|
MONTH=f"{month:02d}"
|
|
169
160
|
)
|
|
170
161
|
|
|
171
|
-
async def
|
|
162
|
+
async def async_update_restriction_level(
|
|
172
163
|
self,
|
|
173
|
-
device_id: str,
|
|
174
164
|
settings: dict
|
|
175
165
|
) -> dict:
|
|
176
|
-
"""Update device
|
|
166
|
+
"""Update device restriction level."""
|
|
177
167
|
return await self.send_request(
|
|
178
|
-
endpoint="
|
|
179
|
-
DEVICE_ID=device_id,
|
|
168
|
+
endpoint="update_restriction_level",
|
|
180
169
|
body=settings
|
|
181
170
|
)
|
|
182
171
|
|
|
183
|
-
async def
|
|
172
|
+
async def async_update_play_timer(
|
|
184
173
|
self,
|
|
185
|
-
|
|
186
|
-
applications: dict
|
|
174
|
+
settings: dict
|
|
187
175
|
) -> dict:
|
|
188
|
-
"""Update device
|
|
176
|
+
"""Update device play timer settings."""
|
|
189
177
|
return await self.send_request(
|
|
190
|
-
endpoint="
|
|
191
|
-
|
|
192
|
-
body=applications
|
|
178
|
+
endpoint="update_play_timer",
|
|
179
|
+
body=settings
|
|
193
180
|
)
|
|
194
181
|
|
|
195
|
-
async def
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
"""Update device
|
|
182
|
+
async def async_update_unlock_code(
|
|
183
|
+
self,
|
|
184
|
+
new_code: str,
|
|
185
|
+
device_id: str
|
|
186
|
+
) -> dict:
|
|
187
|
+
"""Update device unlock code."""
|
|
201
188
|
return await self.send_request(
|
|
202
|
-
endpoint="
|
|
203
|
-
|
|
204
|
-
|
|
189
|
+
endpoint="update_unlock_code",
|
|
190
|
+
body={
|
|
191
|
+
"deviceId": device_id,
|
|
192
|
+
"unlockCode": new_code
|
|
193
|
+
}
|
|
205
194
|
)
|
{pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/authenticator/__init__.py
RENAMED
|
@@ -25,7 +25,7 @@ from .const import (
|
|
|
25
25
|
GRANT_TYPE,
|
|
26
26
|
MY_ACCOUNT_ENDPOINT,
|
|
27
27
|
REDIRECT_URI,
|
|
28
|
-
|
|
28
|
+
SCOPES,
|
|
29
29
|
AUTHORIZE_URL
|
|
30
30
|
)
|
|
31
31
|
|
|
@@ -89,7 +89,7 @@ class Authenticator:
|
|
|
89
89
|
@property
|
|
90
90
|
def access_token(self) -> str:
|
|
91
91
|
"""Return the formatted access token."""
|
|
92
|
-
return f"Bearer {self.
|
|
92
|
+
return f"Bearer {self._id_token}" # v2 seems to use ID token for API access?
|
|
93
93
|
|
|
94
94
|
@property
|
|
95
95
|
def access_token_expired(self) -> bool:
|
|
@@ -173,7 +173,7 @@ class Authenticator:
|
|
|
173
173
|
method="GET",
|
|
174
174
|
url=MY_ACCOUNT_ENDPOINT,
|
|
175
175
|
headers={
|
|
176
|
-
"Authorization": self.
|
|
176
|
+
"Authorization": f"Bearer {self._access_token}"
|
|
177
177
|
}
|
|
178
178
|
)
|
|
179
179
|
if account["status"] != 200:
|
|
@@ -195,7 +195,7 @@ class Authenticator:
|
|
|
195
195
|
# "interacted": 1,
|
|
196
196
|
"redirect_uri": REDIRECT_URI,
|
|
197
197
|
"response_type": "session_token_code",
|
|
198
|
-
"scope":
|
|
198
|
+
"scope": "+".join(SCOPES),
|
|
199
199
|
"session_token_code_challenge": _hash(verifier),
|
|
200
200
|
"session_token_code_challenge_method": "S256",
|
|
201
201
|
"state": _rand(),
|
{pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental/authenticator/const.py
RENAMED
|
@@ -5,7 +5,21 @@ CLIENT_ID = "54789befb391a838"
|
|
|
5
5
|
GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer-session-token"
|
|
6
6
|
|
|
7
7
|
REDIRECT_URI = f"npf{CLIENT_ID}://auth"
|
|
8
|
-
|
|
8
|
+
SCOPES = [
|
|
9
|
+
"openid",
|
|
10
|
+
"user",
|
|
11
|
+
"user.mii",
|
|
12
|
+
"moonUser:administration",
|
|
13
|
+
"moonDevice:create",
|
|
14
|
+
"moonOwnedDevice:administration",
|
|
15
|
+
"moonParentalControlSetting",
|
|
16
|
+
"moonParentalControlSetting:update",
|
|
17
|
+
"moonParentalControlSettingState",
|
|
18
|
+
"moonPairingState",
|
|
19
|
+
"moonSmartDevice:administration",
|
|
20
|
+
"moonDailySummary",
|
|
21
|
+
"moonMonthlySummary",
|
|
22
|
+
]
|
|
9
23
|
|
|
10
24
|
AUTHORIZE_URL = "https://accounts.nintendo.com/connect/1.0.0/authorize?{}"
|
|
11
25
|
SESSION_TOKEN_URL = "https://accounts.nintendo.com/connect/1.0.0/api/session_token"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# pylint: disable=line-too-long
|
|
2
|
+
"""pynintendoparental"""
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
_LOGGER = logging.getLogger(__package__)
|
|
7
|
+
MOBILE_APP_PKG = "com.nintendo.znma"
|
|
8
|
+
MOBILE_APP_VERSION = "2.0.0"
|
|
9
|
+
MOBILE_APP_BUILD = "502"
|
|
10
|
+
OS_NAME = "ANDROID"
|
|
11
|
+
OS_VERSION = "33"
|
|
12
|
+
OS_STR = f"{OS_NAME} {OS_VERSION}"
|
|
13
|
+
DEVICE_MODEL = "Pixel 4 XL"
|
|
14
|
+
BASE_URL = "https://app.lp1.znma.srv.nintendo.net/v2"
|
|
15
|
+
USER_AGENT = f"moon_ANDROID/{MOBILE_APP_VERSION} ({MOBILE_APP_PKG}; build:{MOBILE_APP_BUILD}; {OS_STR})"
|
|
16
|
+
|
|
17
|
+
DAYS_OF_WEEK = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
|
|
18
|
+
|
|
19
|
+
ENDPOINTS = {
|
|
20
|
+
"get_account_devices": {
|
|
21
|
+
"url": "{BASE_URL}/actions/user/fetchOwnedDevices",
|
|
22
|
+
"method": "GET"
|
|
23
|
+
},
|
|
24
|
+
"get_account_device": {
|
|
25
|
+
"url": "{BASE_URL}/actions/user/fetchOwnedDevice?deviceId={DEVICE_ID}",
|
|
26
|
+
"method": "GET"
|
|
27
|
+
},
|
|
28
|
+
"get_device_daily_summaries": {
|
|
29
|
+
"url": "{BASE_URL}/actions/playSummary/fetchDailySummaries?deviceId={DEVICE_ID}",
|
|
30
|
+
"method": "GET"
|
|
31
|
+
},
|
|
32
|
+
"get_device_monthly_summaries": {
|
|
33
|
+
"url": "{BASE_URL}/actions/playSummary/fetchLatestMonthlySummary?deviceId={DEVICE_ID}",
|
|
34
|
+
"method": "GET"
|
|
35
|
+
},
|
|
36
|
+
"get_device_parental_control_setting": {
|
|
37
|
+
"url": "{BASE_URL}/actions/parentalControlSetting/fetchParentalControlSetting?deviceId={DEVICE_ID}",
|
|
38
|
+
"method": "GET"
|
|
39
|
+
},
|
|
40
|
+
"update_restriction_level": {
|
|
41
|
+
"url": "{BASE_URL}/actions/parentalControlSetting/updateRestrictionLevel",
|
|
42
|
+
"method": "POST"
|
|
43
|
+
},
|
|
44
|
+
"update_play_timer": {
|
|
45
|
+
"url": "{BASE_URL}/actions/parentalControlSetting/updatePlayTimer",
|
|
46
|
+
"method": "POST"
|
|
47
|
+
},
|
|
48
|
+
"update_unlock_code": {
|
|
49
|
+
"url": "{BASE_URL}/actions/parentalControlSetting/updateUnlockCode",
|
|
50
|
+
"method": "POST"
|
|
51
|
+
},
|
|
52
|
+
"get_device_monthly_summary": {
|
|
53
|
+
"url": "{BASE_URL}/actions/playSummary/fetchMonthlySummary?deviceId={DEVICE_ID}&year={YEAR}&month={MONTH}&containLatest=false",
|
|
54
|
+
"method": "GET"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -87,13 +87,23 @@ class Device:
|
|
|
87
87
|
"""Updates the pin for the device."""
|
|
88
88
|
_LOGGER.debug(">> Device.set_new_pin(pin=REDACTED)")
|
|
89
89
|
self.parental_control_settings["unlockCode"] = pin
|
|
90
|
-
await self.
|
|
90
|
+
response = await self._api.async_update_unlock_code(
|
|
91
|
+
new_code=pin,
|
|
92
|
+
device_id=self.device_id
|
|
93
|
+
)
|
|
94
|
+
self._parse_parental_control_setting(response["json"])
|
|
91
95
|
|
|
92
96
|
async def set_restriction_mode(self, mode: RestrictionMode):
|
|
93
97
|
"""Updates the restriction mode of the device."""
|
|
94
98
|
_LOGGER.debug(">> Device.set_restriction_mode(mode=%s)", mode)
|
|
95
99
|
self.parental_control_settings["playTimerRegulations"]["restrictionMode"] = str(mode)
|
|
96
|
-
await self.
|
|
100
|
+
response = await self._api.async_update_play_timer(
|
|
101
|
+
settings={
|
|
102
|
+
"deviceId": self.device_id,
|
|
103
|
+
"playTimerRegulations": self.parental_control_settings["playTimerRegulations"]
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
self._parse_parental_control_setting(response["json"])
|
|
97
107
|
|
|
98
108
|
async def set_bedtime_alarm(self, end_time: time = None, enabled: bool = True):
|
|
99
109
|
"""Update the bedtime alarm for the device."""
|
|
@@ -117,16 +127,13 @@ class Device:
|
|
|
117
127
|
self.parental_control_settings["playTimerRegulations"]["eachDayOfTheWeekRegulations"][
|
|
118
128
|
DAYS_OF_WEEK[datetime.now().weekday()]
|
|
119
129
|
]["bedtime"] = bedtime
|
|
120
|
-
await self.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
await self._api.async_set_device_parental_control_setting(
|
|
126
|
-
settings=self._get_update_parental_control_setting_body(),
|
|
127
|
-
device_id=self.device_id
|
|
130
|
+
response = await self._api.async_update_play_timer(
|
|
131
|
+
settings={
|
|
132
|
+
"deviceId": self.device_id,
|
|
133
|
+
"playTimerRegulations": self.parental_control_settings["playTimerRegulations"]
|
|
134
|
+
}
|
|
128
135
|
)
|
|
129
|
-
|
|
136
|
+
self._parse_parental_control_setting(response["json"])
|
|
130
137
|
|
|
131
138
|
async def update_max_daily_playtime(self, minutes: int = 0):
|
|
132
139
|
"""Updates the maximum daily playtime of a device."""
|
|
@@ -148,7 +155,6 @@ class Device:
|
|
|
148
155
|
self.parental_control_settings["playTimerRegulations"]["dailyRegulations"]["timeToPlayInOneDay"].pop("limitTime")
|
|
149
156
|
else:
|
|
150
157
|
self.parental_control_settings["playTimerRegulations"]["dailyRegulations"]["timeToPlayInOneDay"]["limitTime"] = minutes
|
|
151
|
-
await self._set_parental_control_setting()
|
|
152
158
|
else:
|
|
153
159
|
_LOGGER.debug(
|
|
154
160
|
"Setting timeToPlayInOneDay.limitTime for device %s to value %s",
|
|
@@ -162,16 +168,14 @@ class Device:
|
|
|
162
168
|
day_of_week_regs[current_day]["timeToPlayInOneDay"].pop("limitTime")
|
|
163
169
|
else:
|
|
164
170
|
day_of_week_regs[current_day]["timeToPlayInOneDay"]["limitTime"] = minutes
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
"playTimerRegulations": self.parental_control_settings["playTimerRegulations"]
|
|
174
|
-
}
|
|
171
|
+
|
|
172
|
+
response = await self._api.async_update_play_timer(
|
|
173
|
+
settings={
|
|
174
|
+
"deviceId": self.device_id,
|
|
175
|
+
"playTimerRegulations": self.parental_control_settings["playTimerRegulations"]
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
self._parse_parental_control_setting(response["json"])
|
|
175
179
|
|
|
176
180
|
def _update_applications(self):
|
|
177
181
|
"""Updates applications from daily summary."""
|
|
@@ -212,30 +216,26 @@ class Device:
|
|
|
212
216
|
self.bedtime_alarm = None
|
|
213
217
|
return True
|
|
214
218
|
|
|
215
|
-
|
|
216
|
-
"""
|
|
217
|
-
_LOGGER.debug(">> Device.
|
|
218
|
-
|
|
219
|
-
device_id=self.device_id
|
|
220
|
-
)
|
|
221
|
-
self.parental_control_settings = response["json"]
|
|
219
|
+
def _parse_parental_control_setting(self, pcs: dict):
|
|
220
|
+
"""Parse a parental control setting request response."""
|
|
221
|
+
_LOGGER.debug(">> Device._parse_parental_control_setting()")
|
|
222
|
+
self.parental_control_settings = pcs["parentalControlSetting"]
|
|
222
223
|
if "bedtimeStartingTime" in self.parental_control_settings["playTimerRegulations"]:
|
|
223
224
|
if self.parental_control_settings["playTimerRegulations"].get("bedtimeStartingTime", {}).get("hour", 0) == 0:
|
|
224
225
|
self.parental_control_settings["playTimerRegulations"].pop("bedtimeStartingTime")
|
|
225
|
-
|
|
226
226
|
self.forced_termination_mode = (
|
|
227
227
|
self.parental_control_settings["playTimerRegulations"]["restrictionMode"] == str(RestrictionMode.FORCED_TERMINATION)
|
|
228
228
|
)
|
|
229
229
|
self._update_day_of_week_regulations()
|
|
230
|
-
self._get_whitelisted_applications()
|
|
231
230
|
self._update_applications()
|
|
232
231
|
|
|
233
|
-
def
|
|
234
|
-
"""
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
232
|
+
async def _get_parental_control_setting(self):
|
|
233
|
+
"""Retreives parental control settings from the API."""
|
|
234
|
+
_LOGGER.debug(">> Device._get_parental_control_setting()")
|
|
235
|
+
response = await self._api.async_get_device_parental_control_setting(
|
|
236
|
+
device_id=self.device_id
|
|
237
|
+
)
|
|
238
|
+
self._parse_parental_control_setting(response["json"])
|
|
239
239
|
|
|
240
240
|
async def _get_daily_summaries(self):
|
|
241
241
|
"""Retrieve daily summaries."""
|
|
@@ -243,7 +243,7 @@ class Device:
|
|
|
243
243
|
response = await self._api.async_get_device_daily_summaries(
|
|
244
244
|
device_id = self.device_id
|
|
245
245
|
)
|
|
246
|
-
self.daily_summaries = response["json"]["
|
|
246
|
+
self.daily_summaries = response["json"]["dailySummaries"]
|
|
247
247
|
_LOGGER.debug("New daily summary %s", self.daily_summaries)
|
|
248
248
|
try:
|
|
249
249
|
today_playing_time = self.get_date_summary()[0].get("playingTime", 0)
|
|
@@ -287,11 +287,6 @@ class Device:
|
|
|
287
287
|
|
|
288
288
|
self.today_time_remaining = int(max(0.0, effective_remaining_time)) # Ensure non-negative and integer
|
|
289
289
|
_LOGGER.debug("Calculated and updated the amount of time remaining for today: %s", self.today_time_remaining)
|
|
290
|
-
self.today_important_info = self.get_date_summary()[0].get("importantInfos", [])
|
|
291
|
-
self.today_notices = self.get_date_summary()[0].get("notices", [])
|
|
292
|
-
self.today_observations = self.get_date_summary()[0].get("observations", [])
|
|
293
|
-
_LOGGER.debug("Cached today important info, notices and observations for device %s",
|
|
294
|
-
self.device_id)
|
|
295
290
|
self.stats_update_failed = False
|
|
296
291
|
except ValueError as err:
|
|
297
292
|
_LOGGER.debug("Unable to update daily summary for device %s: %s", self.name, err)
|
|
@@ -341,8 +336,8 @@ class Device:
|
|
|
341
336
|
response = await self._api.async_get_account_device(
|
|
342
337
|
device_id = self.device_id
|
|
343
338
|
)
|
|
344
|
-
self.extra = response["json"]
|
|
345
|
-
status = self.extra["
|
|
339
|
+
self.extra = response["json"]["ownedDevice"]["device"]
|
|
340
|
+
status = self.extra["alarmSetting"]["visibility"]
|
|
346
341
|
self.alarms_enabled = status == str(AlarmSettingState.VISIBLE)
|
|
347
342
|
_LOGGER.debug("Cached alarms enabled to state %s for device %s",
|
|
348
343
|
self.alarms_enabled,
|
|
@@ -356,10 +351,10 @@ class Device:
|
|
|
356
351
|
response = await self._api.async_get_device_monthly_summaries(
|
|
357
352
|
device_id=self.device_id
|
|
358
353
|
)
|
|
359
|
-
_LOGGER.debug("Available monthly summaries: %s", response)
|
|
360
|
-
response = response["json"]["
|
|
361
|
-
search_date = datetime.strptime(f"{response}-01", "%Y-%m-%d")
|
|
362
|
-
_LOGGER.debug("Using search date %s for
|
|
354
|
+
_LOGGER.debug("Available monthly summaries: %s", response["json"]["available"])
|
|
355
|
+
response = response["json"]["available"][0]
|
|
356
|
+
search_date = datetime.strptime(f"{response['year']}-{response['month']}-01", "%Y-%m-%d")
|
|
357
|
+
_LOGGER.debug("Using search date %s for monthly summary request", search_date)
|
|
363
358
|
latest = True
|
|
364
359
|
|
|
365
360
|
try:
|
|
@@ -370,44 +365,16 @@ class Device:
|
|
|
370
365
|
)
|
|
371
366
|
_LOGGER.debug("Monthly summary query complete for device %s: %s",
|
|
372
367
|
self.device_id,
|
|
373
|
-
response)
|
|
368
|
+
response["json"]["summary"])
|
|
374
369
|
if latest:
|
|
375
|
-
self.last_month_summary = response["json"]["
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
return response["json"]["insights"]
|
|
370
|
+
self.last_month_summary = summary = response["json"]["summary"]
|
|
371
|
+
return summary
|
|
372
|
+
return response["json"]["summary"]
|
|
379
373
|
except HttpException as exc:
|
|
380
374
|
_LOGGER.warning("HTTP Exception raised while getting monthly summary for device %s: %s",
|
|
381
375
|
self.device_id,
|
|
382
376
|
exc)
|
|
383
377
|
|
|
384
|
-
async def set_alarm_state(self, state: AlarmSettingState):
|
|
385
|
-
"""Updates the alarm state for the device."""
|
|
386
|
-
_LOGGER.debug(">> Device.set_alarm_state(state=%s)",
|
|
387
|
-
state)
|
|
388
|
-
await self._api.async_set_device_alarm_setting_state(
|
|
389
|
-
alarm_state={
|
|
390
|
-
"status": str(state)
|
|
391
|
-
},
|
|
392
|
-
device_id = self.device_id
|
|
393
|
-
)
|
|
394
|
-
|
|
395
|
-
async def set_whitelisted_application(self, app_id: str, allowed: bool):
|
|
396
|
-
"""Set the state of the application."""
|
|
397
|
-
_LOGGER.debug(">> Device.set_whitelisted_application(app_id=%s, allowed=%s)",
|
|
398
|
-
app_id,
|
|
399
|
-
allowed)
|
|
400
|
-
# check if the application exists first
|
|
401
|
-
self.get_application(app_id)
|
|
402
|
-
# take a snapshot of the whitelisted apps state
|
|
403
|
-
current_state = self.parental_control_settings["whitelistedApplications"]
|
|
404
|
-
current_state[app_id]["safeLaunch"] = "ALLOW" if allowed else "NONE"
|
|
405
|
-
await self._api.async_set_device_whitelisted_applications(
|
|
406
|
-
applications=current_state,
|
|
407
|
-
device_id=self.device_id
|
|
408
|
-
)
|
|
409
|
-
await self._get_parental_control_setting()
|
|
410
|
-
|
|
411
378
|
def get_date_summary(self, input_date: datetime = datetime.now()) -> dict:
|
|
412
379
|
"""Returns usage for a given date."""
|
|
413
380
|
summary = [
|
|
@@ -444,10 +411,10 @@ class Device:
|
|
|
444
411
|
async def from_devices_response(cls, raw: dict, api) -> list['Device']:
|
|
445
412
|
"""Parses a device request response body."""
|
|
446
413
|
_LOGGER.debug("Parsing device list response")
|
|
447
|
-
if "
|
|
414
|
+
if "ownedDevices" not in raw.keys():
|
|
448
415
|
raise ValueError("Invalid response from API.")
|
|
449
416
|
devices = []
|
|
450
|
-
for device in raw.get("
|
|
417
|
+
for device in raw.get("ownedDevices", []):
|
|
451
418
|
parsed = Device(api)
|
|
452
419
|
parsed.device_id = device["deviceId"]
|
|
453
420
|
parsed.name = device["label"]
|
|
@@ -16,10 +16,10 @@ class Player:
|
|
|
16
16
|
"""Update the current instance of the player from the daily summery"""
|
|
17
17
|
_LOGGER.debug("Updating player %s daily summary", self.player_id)
|
|
18
18
|
for player in raw[0].get("devicePlayers", []):
|
|
19
|
-
if self.player_id is player.get("playerId"):
|
|
20
|
-
self.player_id = player.get("playerId")
|
|
21
|
-
self.player_image = player.get("imageUri")
|
|
22
|
-
self.nickname = player.get("nickname")
|
|
19
|
+
if self.player_id is player["profile"].get("playerId"):
|
|
20
|
+
self.player_id = player["profile"].get("playerId")
|
|
21
|
+
self.player_image = player["profile"].get("imageUri")
|
|
22
|
+
self.nickname = player["profile"].get("nickname")
|
|
23
23
|
self.playing_time = player.get("playingTime")
|
|
24
24
|
self.apps = player.get("playedApps")
|
|
25
25
|
break
|
|
@@ -29,13 +29,13 @@ class Player:
|
|
|
29
29
|
"""Converts a daily summary response into a list of players."""
|
|
30
30
|
players = []
|
|
31
31
|
_LOGGER.debug("Building players from device daily summary.")
|
|
32
|
-
for player in raw[0].get("
|
|
32
|
+
for player in raw[0].get("players", []):
|
|
33
33
|
parsed = cls()
|
|
34
|
-
parsed.player_id = player.get("playerId")
|
|
35
|
-
parsed.player_image = player.get("imageUri")
|
|
36
|
-
parsed.nickname = player.get("nickname")
|
|
34
|
+
parsed.player_id = player["profile"].get("playerId")
|
|
35
|
+
parsed.player_image = player["profile"].get("imageUri")
|
|
36
|
+
parsed.nickname = player["profile"].get("nickname")
|
|
37
37
|
parsed.playing_time = player.get("playingTime")
|
|
38
|
-
parsed.apps = player.get("
|
|
38
|
+
parsed.apps = player.get("playedGames")
|
|
39
39
|
players.append(parsed)
|
|
40
40
|
_LOGGER.debug("Built player %s", parsed.player_id)
|
|
41
41
|
return players
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.7.2"
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# pylint: disable=line-too-long
|
|
2
|
-
"""pynintendoparental"""
|
|
3
|
-
|
|
4
|
-
import logging
|
|
5
|
-
|
|
6
|
-
_LOGGER = logging.getLogger(__package__)
|
|
7
|
-
MOBILE_APP_PKG = "com.nintendo.znma"
|
|
8
|
-
MOBILE_APP_VERSION = "1.23.0"
|
|
9
|
-
MOBILE_APP_BUILD = "293"
|
|
10
|
-
OS_NAME = "ANDROID"
|
|
11
|
-
OS_VERSION = "33"
|
|
12
|
-
OS_STR = f"{OS_NAME} {OS_VERSION}"
|
|
13
|
-
DEVICE_MODEL = "Pixel 4 XL"
|
|
14
|
-
BASE_URL = "https://api-lp1.pctl.srv.nintendo.net/moon/v1"
|
|
15
|
-
USER_AGENT = f"moon_ANDROID/{MOBILE_APP_VERSION} ({MOBILE_APP_PKG}; build:{MOBILE_APP_BUILD}; {OS_STR})"
|
|
16
|
-
|
|
17
|
-
DAYS_OF_WEEK = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
|
|
18
|
-
|
|
19
|
-
ENDPOINTS = {
|
|
20
|
-
"get_account_details": {
|
|
21
|
-
"url": "{BASE_URL}/users/{ACCOUNT_ID}",
|
|
22
|
-
"method": "GET"
|
|
23
|
-
},
|
|
24
|
-
"get_account_devices": {
|
|
25
|
-
"url": "{BASE_URL}/users/{ACCOUNT_ID}/devices?filter.device.activated.$eq=true",
|
|
26
|
-
"method": "GET"
|
|
27
|
-
},
|
|
28
|
-
"get_account_device": {
|
|
29
|
-
"url": "{BASE_URL}/users/{ACCOUNT_ID}/devices/{DEVICE_ID}",
|
|
30
|
-
"method": "GET"
|
|
31
|
-
},
|
|
32
|
-
"get_device_daily_summaries": {
|
|
33
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/daily_summaries",
|
|
34
|
-
"method": "GET"
|
|
35
|
-
},
|
|
36
|
-
"get_device_monthly_summaries": {
|
|
37
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/monthly_summaries",
|
|
38
|
-
"method": "GET"
|
|
39
|
-
},
|
|
40
|
-
"get_device_parental_control_setting": {
|
|
41
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/parental_control_setting",
|
|
42
|
-
"method": "GET"
|
|
43
|
-
},
|
|
44
|
-
"update_device_parental_control_setting": {
|
|
45
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/parental_control_setting",
|
|
46
|
-
"method": "POST"
|
|
47
|
-
},
|
|
48
|
-
"update_device_whitelisted_applications": {
|
|
49
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/parental_control_setting/whitelisted_applications",
|
|
50
|
-
"method": "POST"
|
|
51
|
-
},
|
|
52
|
-
"get_device_parental_control_setting_state": {
|
|
53
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/parental_control_setting_state",
|
|
54
|
-
"method": "GET"
|
|
55
|
-
},
|
|
56
|
-
"update_device_alarm_setting_state": {
|
|
57
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/alarm_setting_state",
|
|
58
|
-
"method": "POST"
|
|
59
|
-
},
|
|
60
|
-
"get_device_alarm_setting_state": {
|
|
61
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/alarm_setting_state",
|
|
62
|
-
"method": "GET"
|
|
63
|
-
},
|
|
64
|
-
"get_device_monthly_summary": {
|
|
65
|
-
"url": "{BASE_URL}/devices/{DEVICE_ID}/monthly_summaries/{YEAR}-{MONTH}",
|
|
66
|
-
"method": "GET"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/requires.txt
RENAMED
|
File without changes
|
{pynintendoparental-0.7.2 → pynintendoparental-1.0.0}/pynintendoparental.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|