pynintendoparental 2.0.0__py3-none-any.whl → 2.1.1__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.
@@ -1 +1 @@
1
- __version__ = "2.0.0"
1
+ __version__ = "2.1.1"
pynintendoparental/api.py CHANGED
@@ -112,12 +112,6 @@ class Api:
112
112
  # now return the resp dict
113
113
  return resp
114
114
 
115
- async def async_get_account_details(self) -> dict:
116
- """Get account details."""
117
- return await self.send_request(
118
- endpoint="get_account_details", ACCOUNT_ID=self.account_id
119
- )
120
-
121
115
  async def async_get_account_devices(self) -> dict:
122
116
  """Get account devices."""
123
117
  return await self.send_request(endpoint="get_account_devices")
@@ -146,14 +140,6 @@ class Api:
146
140
  endpoint="get_device_parental_control_setting", DEVICE_ID=device_id
147
141
  )
148
142
 
149
- async def async_get_device_parental_control_setting_state(
150
- self, device_id: str
151
- ) -> dict:
152
- """Get device parental control setting state."""
153
- return await self.send_request(
154
- endpoint="get_device_parental_control_setting_state", DEVICE_ID=device_id
155
- )
156
-
157
143
  async def async_get_device_monthly_summary(
158
144
  self, device_id: str, year: int, month: int
159
145
  ) -> dict:
@@ -6,8 +6,8 @@ import logging
6
6
  _LOGGER = logging.getLogger(__package__)
7
7
  CLIENT_ID = "54789befb391a838"
8
8
  MOBILE_APP_PKG = "com.nintendo.znma"
9
- MOBILE_APP_VERSION = "2.2.0"
10
- MOBILE_APP_BUILD = "560"
9
+ MOBILE_APP_VERSION = "2.3.0"
10
+ MOBILE_APP_BUILD = "600"
11
11
  OS_NAME = "ANDROID"
12
12
  OS_VERSION = "34"
13
13
  OS_STR = f"{OS_NAME} {OS_VERSION}"
@@ -32,8 +32,9 @@ class Device:
32
32
  self._api: Api = api
33
33
  self.daily_summaries: dict = {}
34
34
  self.parental_control_settings: dict = {}
35
- self.players: list[Player] = []
35
+ self.players: dict[str, Player] = {}
36
36
  self.limit_time: int | float | None = 0
37
+ self.extra_playing_time: int | None = None
37
38
  self.timer_mode: DeviceTimerMode | None = None
38
39
  self.today_playing_time: int | float = 0
39
40
  self.today_time_remaining: int | float = 0
@@ -66,6 +67,13 @@ class Device:
66
67
  """Return the generation."""
67
68
  return self.extra.get("platformGeneration", None)
68
69
 
70
+ @property
71
+ def last_sync(self) -> float | None:
72
+ """Return the last time this device was synced."""
73
+ return self.extra.get("synchronizedParentalControlSetting", {}).get(
74
+ "synchronizedAt", None
75
+ )
76
+
69
77
  async def update(self):
70
78
  """Update data."""
71
79
  _LOGGER.debug(">> Device.update()")
@@ -76,11 +84,8 @@ class Device:
76
84
  self.get_monthly_summary(),
77
85
  self._get_extras(),
78
86
  )
79
- if not self.players:
80
- self.players = Player.from_device_daily_summary(self.daily_summaries)
81
- else:
82
- for player in self.players:
83
- player.update_from_daily_summary(self.daily_summaries)
87
+ for player in self.players.values():
88
+ player.update_from_daily_summary(self.daily_summaries)
84
89
  await self._execute_callbacks()
85
90
 
86
91
  def add_device_callback(self, callback):
@@ -321,6 +326,14 @@ class Device:
321
326
  today_reg = self._get_today_regulation(now)
322
327
  limit_time = today_reg.get("timeToPlayInOneDay", {}).get("limitTime")
323
328
  self.limit_time = limit_time if limit_time is not None else -1
329
+ extra_playing_time_data = (
330
+ pcs.get("ownedDevice", {}).get("device", {}).get("extraPlayingTime")
331
+ )
332
+ self.extra_playing_time = None
333
+ if extra_playing_time_data:
334
+ self.extra_playing_time = extra_playing_time_data.get("inOneDay", {}).get(
335
+ "duration"
336
+ )
324
337
 
325
338
  bedtime_setting = today_reg.get("bedtime", {})
326
339
  if bedtime_setting.get("enabled"):
@@ -527,6 +540,15 @@ class Device:
527
540
  )
528
541
  if latest:
529
542
  self.last_month_summary = summary = response["json"]["summary"]
543
+ # Generate player objects
544
+ for player in response.get("json", {}).get("summary", {}).get("players", []):
545
+ profile = player.get("profile")
546
+ if not profile or not profile.get("playerId"):
547
+ continue
548
+ player_id = profile["playerId"]
549
+ if player_id not in self.players:
550
+ self.players[player_id] = Player.from_profile(profile)
551
+ self.players[player_id].month_summary = player.get("summary", {})
530
552
  return summary
531
553
  return response["json"]["summary"]
532
554
 
@@ -564,7 +586,7 @@ class Device:
564
586
 
565
587
  def get_player(self, player_id: str) -> Player:
566
588
  """Returns a player."""
567
- player = next((p for p in self.players if p.player_id == player_id), None)
589
+ player = self.players.get(player_id)
568
590
  if player:
569
591
  return player
570
592
  raise ValueError(f"Player with id {player_id} not found.")
@@ -2,12 +2,14 @@
2
2
 
3
3
  from enum import StrEnum
4
4
 
5
+
5
6
  class RangeErrorKeys(StrEnum):
6
7
  """Keys for range errors."""
7
8
 
8
9
  DAILY_PLAYTIME = "daily_playtime_out_of_range"
9
10
  BEDTIME = "bedtime_alarm_out_of_range"
10
11
 
12
+
11
13
  class NoDevicesFoundException(Exception):
12
14
  """No devices were found for the account."""
13
15
 
@@ -8,22 +8,22 @@ class Player:
8
8
 
9
9
  def __init__(self):
10
10
  """Init a player."""
11
- self.player_image: str = None
12
- self.nickname: str = None
11
+ self.player_image: str | None = None
12
+ self.nickname: str | None = None
13
13
  self.apps: list = []
14
- self.player_id: str = None
15
- self.playing_time: int = None
14
+ self.month_summary: dict = {}
15
+ self.player_id: str | None = None
16
+ self.playing_time: int = 0
16
17
 
17
18
  def update_from_daily_summary(self, raw: list[dict]):
18
19
  """Update the current instance of the player from the daily summery"""
19
20
  _LOGGER.debug("Updating player %s daily summary", self.player_id)
20
- for player in raw[0].get("devicePlayers", []):
21
- if self.player_id is player["profile"].get("playerId"):
22
- self.player_id = player["profile"].get("playerId")
21
+ for player in raw[0].get("players", []):
22
+ if self.player_id == player["profile"].get("playerId"):
23
23
  self.player_image = player["profile"].get("imageUri")
24
24
  self.nickname = player["profile"].get("nickname")
25
25
  self.playing_time = player.get("playingTime")
26
- self.apps = player.get("playedApps")
26
+ self.apps = player.get("playedGames")
27
27
  break
28
28
 
29
29
  @classmethod
@@ -41,3 +41,12 @@ class Player:
41
41
  players.append(parsed)
42
42
  _LOGGER.debug("Built player %s", parsed.player_id)
43
43
  return players
44
+
45
+ @classmethod
46
+ def from_profile(cls, raw: dict) -> "Player":
47
+ """Converts a profile response into a player."""
48
+ parsed = cls()
49
+ parsed.player_id = raw.get("playerId")
50
+ parsed.player_image = raw.get("imageUri")
51
+ parsed.nickname = raw.get("nickname")
52
+ return parsed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pynintendoparental
3
- Version: 2.0.0
3
+ Version: 2.1.1
4
4
  Summary: A Python module to interact with Nintendo Parental Controls
5
5
  Home-page: http://github.com/pantherale0/pynintendoparental
6
6
  Author: pantherale0
@@ -11,16 +11,20 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.8, <4
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: pynintendoauth~=1.0.0
14
+ Requires-Dist: pynintendoauth==1.0.0
15
15
  Provides-Extra: dev
16
+ Requires-Dist: aiofiles<26,>=23; extra == "dev"
16
17
  Requires-Dist: bandit<1.9,>=1.7; extra == "dev"
17
18
  Requires-Dist: black<26,>=23; extra == "dev"
18
19
  Requires-Dist: build<1.4,>=0.10; extra == "dev"
20
+ Requires-Dist: Faker<39,>=38; extra == "dev"
19
21
  Requires-Dist: flake8<8,>=6; extra == "dev"
20
22
  Requires-Dist: isort<7,>=5; extra == "dev"
21
- Requires-Dist: mypy<1.19,>=1.5; extra == "dev"
23
+ Requires-Dist: mypy<1.20,>=1.5; extra == "dev"
22
24
  Requires-Dist: pytest<9,>=7; extra == "dev"
23
25
  Requires-Dist: pytest-cov<8,>=4; extra == "dev"
26
+ Requires-Dist: pytest-asyncio<1.0,>=0.21; extra == "dev"
27
+ Requires-Dist: syrupy<6,>=5; extra == "dev"
24
28
  Requires-Dist: twine<7,>=4; extra == "dev"
25
29
  Dynamic: author
26
30
  Dynamic: classifier
@@ -0,0 +1,17 @@
1
+ pynintendoparental/__init__.py,sha256=gO3rH9gukrFoACVkdqj_liqcgtHxSZlitE0PrVQZGok,2334
2
+ pynintendoparental/_version.py,sha256=zPJIgPGcoSNiD0qme18OnYJYE3A9VVytlhO-V5DaAW0,22
3
+ pynintendoparental/api.py,sha256=cVL17wmkCA4AHnVAGzMkNA-40t9M9Q7iZYNFWxu-Oa8,6534
4
+ pynintendoparental/application.py,sha256=8zTisF3_COgIzKCLIgLpYdHcX4OiwRQU5NH2WUngvxc,3995
5
+ pynintendoparental/authenticator.py,sha256=WPAEAUKmIymIiQUXILYt4B2_3UgYRKEVi6btJRwzjmM,430
6
+ pynintendoparental/const.py,sha256=bKfv1O-eFbzvhz0EE2Cj6Px2b5yoq8HL7itMP4TWmwo,2174
7
+ pynintendoparental/device.py,sha256=CiW-SXYGvjsZzW10Sf1Xu0PA6hkduabpWyWPIxgzKng,25541
8
+ pynintendoparental/enum.py,sha256=NlkfrZTfiur6vTqqwHxeiM7wPQZ-1Y1PlY4Jh_gq4NQ,605
9
+ pynintendoparental/exceptions.py,sha256=zOGZHlBFfdcBNNWHA7t_Ix2Qgd3ON2-SVjmA9dHs578,883
10
+ pynintendoparental/player.py,sha256=Zh3vi0IdOHtn5KW0tT9JigB315ftjQ4uEQylF3D4LWs,2084
11
+ pynintendoparental/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ pynintendoparental/utils.py,sha256=gLMibsEOnKUZJgCQKF4Zk517fawZ3mBqMK6MS2g-Um0,199
13
+ pynintendoparental-2.1.1.dist-info/licenses/LICENSE,sha256=zsxHgHVMnyWq121yND8zBl9Rl9H6EF2K9N51B2ZSm_k,1071
14
+ pynintendoparental-2.1.1.dist-info/METADATA,sha256=jM_7IdBkIF0pNrQgyDCGVK8L974XMZo2ypvEc9c5MVg,2125
15
+ pynintendoparental-2.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ pynintendoparental-2.1.1.dist-info/top_level.txt,sha256=QQ5bAl-Ljso16P8KLf1NHrFmKk9jLT7bVJG_rVlIXWk,19
17
+ pynintendoparental-2.1.1.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- pynintendoparental/__init__.py,sha256=gO3rH9gukrFoACVkdqj_liqcgtHxSZlitE0PrVQZGok,2334
2
- pynintendoparental/_version.py,sha256=_7OlQdbVkK4jad0CLdpI0grT-zEAb-qgFmH5mFzDXiA,22
3
- pynintendoparental/api.py,sha256=LmZei8WPzEhCEoVLXXHiaKRbDEbmGyD6CyfPS4fXxnc,7047
4
- pynintendoparental/application.py,sha256=8zTisF3_COgIzKCLIgLpYdHcX4OiwRQU5NH2WUngvxc,3995
5
- pynintendoparental/authenticator.py,sha256=WPAEAUKmIymIiQUXILYt4B2_3UgYRKEVi6btJRwzjmM,430
6
- pynintendoparental/const.py,sha256=2fq0VmqFetwLq1YBXatlb7tFaDeR0pnsdja4MLFdbDA,2174
7
- pynintendoparental/device.py,sha256=VSK1-fKcXA2AoGCKaVGyhy32T6VXYowuo7upNivaWyk,24521
8
- pynintendoparental/enum.py,sha256=NlkfrZTfiur6vTqqwHxeiM7wPQZ-1Y1PlY4Jh_gq4NQ,605
9
- pynintendoparental/exceptions.py,sha256=8a_7ocrlB0PwPM36Q4FqR-W0lkGXihOs79gGqQIWZoo,881
10
- pynintendoparental/player.py,sha256=rXYgUiy7DhBjosQlADr7Fa_HVdA1e-04oPZiC4Y68oM,1787
11
- pynintendoparental/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- pynintendoparental/utils.py,sha256=gLMibsEOnKUZJgCQKF4Zk517fawZ3mBqMK6MS2g-Um0,199
13
- pynintendoparental-2.0.0.dist-info/licenses/LICENSE,sha256=zsxHgHVMnyWq121yND8zBl9Rl9H6EF2K9N51B2ZSm_k,1071
14
- pynintendoparental-2.0.0.dist-info/METADATA,sha256=5LTsNbTAUk98bovyA4h57PuFT6-iC470Hk98ErArp7Q,1931
15
- pynintendoparental-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
- pynintendoparental-2.0.0.dist-info/top_level.txt,sha256=QQ5bAl-Ljso16P8KLf1NHrFmKk9jLT7bVJG_rVlIXWk,19
17
- pynintendoparental-2.0.0.dist-info/RECORD,,