MouseTools 4.2.0__tar.gz → 4.3.1__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.
- {mousetools-4.2.0 → mousetools-4.3.1}/PKG-INFO +1 -1
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/api/menu.py +19 -13
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/auth.py +5 -0
- mousetools-4.3.1/mousetools/channels/__init__.py +125 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/calendar/__init__.py +4 -49
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/characters/__init__.py +4 -49
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/facilities/__init__.py +4 -55
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/facilitystatus/__init__.py +25 -42
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/forecastedwaittimes/__init__.py +4 -50
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/decorators.py +2 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/mixins/couchbase.py +5 -2
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/mixins/disney.py +1 -1
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools.egg-info/PKG-INFO +1 -1
- {mousetools-4.2.0 → mousetools-4.3.1}/pyproject.toml +1 -1
- mousetools-4.2.0/mousetools/channels/__init__.py +0 -62
- {mousetools-4.2.0 → mousetools-4.3.1}/LICENSE +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/README.md +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/__init__.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/api/__init__.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/api/search.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/enums.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/channels/facilities/enums.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/enums.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/mixins/__init__.py +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools/resources/environments.bin +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools.egg-info/SOURCES.txt +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools.egg-info/dependency_links.txt +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools.egg-info/requires.txt +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/mousetools.egg-info/top_level.txt +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/setup.cfg +0 -0
- {mousetools-4.2.0 → mousetools-4.3.1}/tests/test_mixins.py +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import typing
|
|
2
3
|
from datetime import datetime, timedelta
|
|
3
4
|
from zoneinfo import ZoneInfo
|
|
@@ -8,7 +9,7 @@ from mousetools.auth import auth_obj
|
|
|
8
9
|
from mousetools.decorators import disney_property, json_property
|
|
9
10
|
from mousetools.mixins.disney import DisneyAPIMixin
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class MenuItem:
|
|
@@ -351,7 +352,17 @@ class Menus(DisneyAPIMixin):
|
|
|
351
352
|
|
|
352
353
|
def refresh(self) -> None:
|
|
353
354
|
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
354
|
-
|
|
355
|
+
no_data_check = self._disney_data is None
|
|
356
|
+
time_since_pull = datetime.now(tz=self._tz) - self._disney_data_pull_time
|
|
357
|
+
old_data_check = time_since_pull > self._refresh_interval
|
|
358
|
+
logger.debug(
|
|
359
|
+
"No data check: %s, Time since last update: %s, Old data check: %s",
|
|
360
|
+
no_data_check,
|
|
361
|
+
time_since_pull,
|
|
362
|
+
old_data_check,
|
|
363
|
+
)
|
|
364
|
+
if no_data_check or old_data_check:
|
|
365
|
+
logger.info("Refreshing menu data %s", self.entity_id)
|
|
355
366
|
self._disney_data = self.get_disney_data(self._menu_service_url)
|
|
356
367
|
self._disney_data_pull_time = datetime.now(tz=self._tz)
|
|
357
368
|
|
|
@@ -396,19 +407,14 @@ class Menus(DisneyAPIMixin):
|
|
|
396
407
|
"""
|
|
397
408
|
return self._disney_data["ancestorLocationLandArea"]
|
|
398
409
|
|
|
399
|
-
@
|
|
400
|
-
def last_refresh(self) -> datetime:
|
|
410
|
+
@disney_property()
|
|
411
|
+
def last_refresh(self) -> typing.Optional[datetime]:
|
|
401
412
|
"""
|
|
402
413
|
The last time the menus were refreshed.
|
|
403
414
|
|
|
404
415
|
Returns:
|
|
405
|
-
(datetime): The last time the menus were refreshed.
|
|
416
|
+
(typing.Optional[datetime]): The last time the menus were refreshed.
|
|
406
417
|
"""
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
refresh_time = isoparse(self._disney_data["lastRefresh"])
|
|
411
|
-
refresh_time = refresh_time.replace(tzinfo=self._tz)
|
|
412
|
-
return refresh_time
|
|
413
|
-
except (KeyError, TypeError, ValueError):
|
|
414
|
-
return self._disney_data_pull_time
|
|
418
|
+
refresh_time = isoparse(self._disney_data["lastRefresh"])
|
|
419
|
+
refresh_time = refresh_time.replace(tzinfo=self._tz)
|
|
420
|
+
return refresh_time
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import json
|
|
3
|
+
import logging
|
|
3
4
|
import typing
|
|
4
5
|
from datetime import datetime, timedelta
|
|
5
6
|
from importlib.resources import as_file, files
|
|
@@ -7,6 +8,8 @@ from importlib.resources import as_file, files
|
|
|
7
8
|
import httpx
|
|
8
9
|
from Crypto.Cipher import AES
|
|
9
10
|
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
10
13
|
|
|
11
14
|
class Authentication:
|
|
12
15
|
def __init__(self):
|
|
@@ -38,6 +41,7 @@ class Authentication:
|
|
|
38
41
|
"client_id": self._environments["authzClientId"],
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
logger.debug("Sending request for authentication token")
|
|
41
45
|
response = httpx.post(
|
|
42
46
|
f"{self._environments['authzServiceUrl']}/token",
|
|
43
47
|
headers=headers,
|
|
@@ -57,6 +61,7 @@ class Authentication:
|
|
|
57
61
|
"""
|
|
58
62
|
|
|
59
63
|
if self.time_of_expire is None or (datetime.now() > self.time_of_expire):
|
|
64
|
+
logger.info("Requesting new authentication token")
|
|
60
65
|
access_token, expires_in = self.authenticate()
|
|
61
66
|
self.time_of_expire = datetime.now() + timedelta(seconds=(expires_in - 10))
|
|
62
67
|
self.access_token = access_token
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import typing
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
from dateutil.parser import isoparse
|
|
7
|
+
|
|
8
|
+
from mousetools.channels.enums import DestinationTimezones, DLRCouchbaseChannels, WDWCouchbaseChannels
|
|
9
|
+
from mousetools.decorators import disney_property
|
|
10
|
+
from mousetools.enums import DestinationShort, EntityType
|
|
11
|
+
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CouchbaseChildChannel(CouchbaseMixin):
|
|
17
|
+
def __init__(self, channel_id: str, lazy_load: bool = True):
|
|
18
|
+
if isinstance(channel_id, Enum):
|
|
19
|
+
channel_id = channel_id.value
|
|
20
|
+
|
|
21
|
+
self.channel_id: str = channel_id
|
|
22
|
+
self.entity_id: str = channel_id.rsplit(".", 1)[-1]
|
|
23
|
+
|
|
24
|
+
self._destination_short: DestinationShort = self.channel_id.split(".")[0]
|
|
25
|
+
self._tz: DestinationTimezones = (
|
|
26
|
+
DestinationTimezones.WALT_DISNEY_WORLD
|
|
27
|
+
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
28
|
+
else DestinationTimezones.DISNEYLAND_RESORT
|
|
29
|
+
)
|
|
30
|
+
self._refresh_interval: timedelta = timedelta(hours=12)
|
|
31
|
+
self._cb_data: typing.Optional[dict] = None
|
|
32
|
+
self._cb_data_pull_time: datetime = datetime.now(tz=self._tz.value)
|
|
33
|
+
if not lazy_load:
|
|
34
|
+
self.refresh()
|
|
35
|
+
|
|
36
|
+
def refresh(self) -> None:
|
|
37
|
+
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
38
|
+
|
|
39
|
+
no_data_check = self._cb_data is None
|
|
40
|
+
time_since_pull = datetime.now(tz=self._tz.value) - self._cb_data_pull_time
|
|
41
|
+
old_data_check = time_since_pull > self._refresh_interval
|
|
42
|
+
logger.debug(
|
|
43
|
+
"No data check: %s, Time since pull: %s, Old data check: %s", no_data_check, time_since_pull, old_data_check
|
|
44
|
+
)
|
|
45
|
+
if no_data_check or old_data_check:
|
|
46
|
+
logger.info("Refreshing %s", self.channel_id)
|
|
47
|
+
self._cb_data = self.get_channel_data(self.channel_id)
|
|
48
|
+
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
49
|
+
|
|
50
|
+
@disney_property()
|
|
51
|
+
def last_update(self) -> typing.Optional[datetime]:
|
|
52
|
+
"""
|
|
53
|
+
The last time disney updated the data.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
(typing.Optional[datetime]): The last time the entity's data was updated, or None if no such data exists.
|
|
57
|
+
"""
|
|
58
|
+
dt = isoparse(self._cb_data["lastUpdate"])
|
|
59
|
+
dt = dt.replace(tzinfo=self._tz.value)
|
|
60
|
+
return dt
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class CouchbaseChannel(CouchbaseMixin):
|
|
64
|
+
def __init__(self, channel_id: typing.Union[WDWCouchbaseChannels, DLRCouchbaseChannels], lazy_load: bool = True):
|
|
65
|
+
"""
|
|
66
|
+
Args:
|
|
67
|
+
channel_id (typing.Union[WDWCouchbaseChannels, DLRCouchbaseChannels]): Channel ID from the enum
|
|
68
|
+
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
69
|
+
"""
|
|
70
|
+
if isinstance(channel_id, Enum):
|
|
71
|
+
channel_id = channel_id.value
|
|
72
|
+
self.channel_id = channel_id
|
|
73
|
+
|
|
74
|
+
self._destination_short: DestinationShort = channel_id.split(".")[0]
|
|
75
|
+
self._tz: DestinationTimezones = (
|
|
76
|
+
DestinationTimezones.WALT_DISNEY_WORLD
|
|
77
|
+
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
78
|
+
else DestinationTimezones.DISNEYLAND_RESORT
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
self._cb_data = None
|
|
82
|
+
self._refresh_interval = timedelta(minutes=10)
|
|
83
|
+
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
84
|
+
|
|
85
|
+
if not lazy_load:
|
|
86
|
+
self.refresh()
|
|
87
|
+
|
|
88
|
+
def refresh(self) -> None:
|
|
89
|
+
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
90
|
+
no_data_check = self._cb_data is None
|
|
91
|
+
time_since_pull = datetime.now(tz=self._tz.value) - self._cb_data_pull_time
|
|
92
|
+
old_data_check = time_since_pull > self._refresh_interval
|
|
93
|
+
logger.debug(
|
|
94
|
+
"No data check: %s, Time since last update: %s, Old data check: %s",
|
|
95
|
+
no_data_check,
|
|
96
|
+
time_since_pull,
|
|
97
|
+
old_data_check,
|
|
98
|
+
)
|
|
99
|
+
if no_data_check or old_data_check:
|
|
100
|
+
logger.info("Refreshing %s", self.channel_id)
|
|
101
|
+
self._cb_data = self.get_channel_changes(self.channel_id)
|
|
102
|
+
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
103
|
+
|
|
104
|
+
def get_children_channel_ids(self) -> list[str]:
|
|
105
|
+
"""Returns a list of child channel ids for the channel."""
|
|
106
|
+
self.refresh()
|
|
107
|
+
|
|
108
|
+
return [i["id"] for i in self._cb_data["results"]]
|
|
109
|
+
|
|
110
|
+
def _get_children_objects_helper(self, class_obj, entity_type: EntityType) -> list:
|
|
111
|
+
self.refresh()
|
|
112
|
+
channels = []
|
|
113
|
+
check_for = f"entitytype={entity_type.value}".lower()
|
|
114
|
+
for i in self._cb_data["results"]:
|
|
115
|
+
if check_for == i["id"].rsplit(";")[-1].lower():
|
|
116
|
+
channels.append(class_obj(i["id"]))
|
|
117
|
+
return channels
|
|
118
|
+
|
|
119
|
+
def __repr__(self):
|
|
120
|
+
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
121
|
+
|
|
122
|
+
def __eq__(self, other) -> bool:
|
|
123
|
+
if isinstance(other, CouchbaseChannel):
|
|
124
|
+
return self.channel_id == other.channel_id
|
|
125
|
+
return False
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import typing
|
|
3
|
-
from datetime import datetime, timedelta
|
|
4
|
-
from enum import Enum
|
|
5
3
|
from zoneinfo import ZoneInfo
|
|
6
4
|
|
|
7
5
|
from dateutil.parser import isoparse
|
|
8
6
|
|
|
9
|
-
from mousetools.channels import CouchbaseChannel
|
|
10
|
-
from mousetools.channels.enums import CouchbaseChannels
|
|
7
|
+
from mousetools.channels import CouchbaseChannel, CouchbaseChildChannel
|
|
8
|
+
from mousetools.channels.enums import CouchbaseChannels
|
|
11
9
|
from mousetools.decorators import disney_property
|
|
12
|
-
from mousetools.enums import DestinationShort
|
|
13
|
-
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
14
10
|
|
|
15
11
|
logger = logging.getLogger(__name__)
|
|
16
12
|
|
|
17
13
|
|
|
18
|
-
class CalendarChildChannel(
|
|
14
|
+
class CalendarChildChannel(CouchbaseChildChannel):
|
|
19
15
|
def __init__(
|
|
20
16
|
self,
|
|
21
17
|
channel_id: str,
|
|
@@ -26,34 +22,11 @@ class CalendarChildChannel(CouchbaseMixin):
|
|
|
26
22
|
channel_id (str): Calendar Channel ID
|
|
27
23
|
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
28
24
|
"""
|
|
29
|
-
|
|
30
|
-
channel_id = channel_id.value
|
|
31
|
-
|
|
32
|
-
self.channel_id: str = channel_id
|
|
33
|
-
self.entity_id: str = channel_id.rsplit(".", 1)[-1]
|
|
34
|
-
|
|
35
|
-
self._destination_short: DestinationShort = self.channel_id.split(".")[0]
|
|
36
|
-
self._tz: DestinationTimezones = (
|
|
37
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
38
|
-
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
39
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
40
|
-
)
|
|
41
|
-
self._refresh_interval: timedelta = timedelta(minutes=30)
|
|
42
|
-
|
|
43
|
-
self._cb_data: typing.Optional[dict] = None
|
|
44
|
-
self._cb_data_pull_time: datetime = datetime.now(tz=self._tz.value)
|
|
45
|
-
if not lazy_load:
|
|
46
|
-
self.refresh()
|
|
25
|
+
super().__init__(channel_id, lazy_load=lazy_load)
|
|
47
26
|
|
|
48
27
|
def __repr__(self):
|
|
49
28
|
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
50
29
|
|
|
51
|
-
def refresh(self) -> None:
|
|
52
|
-
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
53
|
-
if self._cb_data is None or datetime.now(tz=self._tz.value) - self.last_update > self._refresh_interval:
|
|
54
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
55
|
-
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
56
|
-
|
|
57
30
|
@disney_property()
|
|
58
31
|
def calendar_id(self) -> typing.Optional[str]:
|
|
59
32
|
"""The ID of the calendar
|
|
@@ -63,24 +36,6 @@ class CalendarChildChannel(CouchbaseMixin):
|
|
|
63
36
|
"""
|
|
64
37
|
return self._cb_data["id"]
|
|
65
38
|
|
|
66
|
-
@property
|
|
67
|
-
def last_update(self) -> datetime:
|
|
68
|
-
"""The last time the data was updated.
|
|
69
|
-
|
|
70
|
-
Returns:
|
|
71
|
-
(datetime): The last time the entity's data was updated, or None if no such data exists.
|
|
72
|
-
"""
|
|
73
|
-
if self._cb_data is None:
|
|
74
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
75
|
-
|
|
76
|
-
try:
|
|
77
|
-
dt = isoparse(self._cb_data["lastUpdate"])
|
|
78
|
-
dt = dt.replace(tzinfo=self._tz.value)
|
|
79
|
-
return dt
|
|
80
|
-
except (KeyError, ValueError, TypeError):
|
|
81
|
-
logger.debug("No last updated found for %s", self.channel_id)
|
|
82
|
-
return self._cb_data_pull_time
|
|
83
|
-
|
|
84
39
|
@disney_property()
|
|
85
40
|
def all_closed(self) -> typing.Optional[list[dict]]:
|
|
86
41
|
"""The list of closed facilities.
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from enum import Enum
|
|
4
2
|
from typing import Optional
|
|
5
3
|
|
|
6
4
|
from dateutil.parser import isoparse
|
|
7
5
|
|
|
8
|
-
from mousetools.channels import CouchbaseChannel
|
|
9
|
-
from mousetools.channels.enums import CouchbaseChannels
|
|
6
|
+
from mousetools.channels import CouchbaseChannel, CouchbaseChildChannel
|
|
7
|
+
from mousetools.channels.enums import CouchbaseChannels
|
|
10
8
|
from mousetools.decorators import disney_property
|
|
11
|
-
from mousetools.enums import DestinationShort
|
|
12
|
-
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
13
9
|
|
|
14
10
|
logger = logging.getLogger(__name__)
|
|
15
11
|
|
|
16
12
|
|
|
17
|
-
class CharactersChildChannel(
|
|
13
|
+
class CharactersChildChannel(CouchbaseChildChannel):
|
|
18
14
|
def __init__(
|
|
19
15
|
self,
|
|
20
16
|
channel_id: str,
|
|
@@ -25,52 +21,11 @@ class CharactersChildChannel(CouchbaseMixin):
|
|
|
25
21
|
channel_id (str): Forecasted Wait Times Channel ID
|
|
26
22
|
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
27
23
|
"""
|
|
28
|
-
|
|
29
|
-
channel_id = channel_id.value
|
|
30
|
-
|
|
31
|
-
self.channel_id: str = channel_id
|
|
32
|
-
self.entity_id: str = channel_id.rsplit(".", 1)[-1]
|
|
33
|
-
|
|
34
|
-
self._destination_short: DestinationShort = self.channel_id.split(".")[0]
|
|
35
|
-
self._tz: DestinationTimezones = (
|
|
36
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
37
|
-
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
38
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
39
|
-
)
|
|
40
|
-
self._refresh_interval: timedelta = timedelta(minutes=30)
|
|
41
|
-
|
|
42
|
-
self._cb_data: Optional[dict] = None
|
|
43
|
-
self._cb_data_pull_time: Optional[datetime] = datetime.now(tz=self._tz.value)
|
|
44
|
-
if not lazy_load:
|
|
45
|
-
self.refresh()
|
|
24
|
+
super().__init__(channel_id, lazy_load=lazy_load)
|
|
46
25
|
|
|
47
26
|
def __repr__(self):
|
|
48
27
|
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
49
28
|
|
|
50
|
-
def refresh(self) -> None:
|
|
51
|
-
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
52
|
-
if self._cb_data is None or datetime.now(tz=self._tz.value) - self.last_update > self._refresh_interval:
|
|
53
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
54
|
-
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
55
|
-
|
|
56
|
-
@property
|
|
57
|
-
def last_update(self) -> datetime:
|
|
58
|
-
"""The last time the data was updated.
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
(datetime): The last time the entity's data was updated, or None if no such data exists.
|
|
62
|
-
"""
|
|
63
|
-
if self._cb_data is None:
|
|
64
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
65
|
-
|
|
66
|
-
try:
|
|
67
|
-
dt = isoparse(self._cb_data["lastUpdate"])
|
|
68
|
-
dt = dt.replace(tzinfo=self._tz.value)
|
|
69
|
-
return dt
|
|
70
|
-
except (KeyError, TypeError, ValueError):
|
|
71
|
-
logger.debug("No last updated found for %s", self.channel_id)
|
|
72
|
-
return self._cb_data_pull_time
|
|
73
|
-
|
|
74
29
|
@disney_property()
|
|
75
30
|
def name(self) -> Optional[str]:
|
|
76
31
|
"""The name of the entity.
|
|
@@ -2,18 +2,15 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import typing
|
|
4
4
|
from datetime import datetime, time, timedelta
|
|
5
|
-
from enum import Enum
|
|
6
5
|
from zoneinfo import ZoneInfo
|
|
7
6
|
|
|
8
7
|
import httpx
|
|
9
|
-
from dateutil.parser import isoparse
|
|
10
8
|
|
|
11
9
|
from mousetools.api.menu import Menus
|
|
12
|
-
from mousetools.channels import CouchbaseChannel
|
|
10
|
+
from mousetools.channels import CouchbaseChannel, CouchbaseChildChannel
|
|
13
11
|
from mousetools.channels.calendar import CalendarChildChannel
|
|
14
12
|
from mousetools.channels.enums import (
|
|
15
13
|
CouchbaseChannels,
|
|
16
|
-
DestinationTimezones,
|
|
17
14
|
DLRCouchbaseChannels,
|
|
18
15
|
WDWCouchbaseChannels,
|
|
19
16
|
)
|
|
@@ -21,12 +18,11 @@ from mousetools.channels.facilitystatus import FacilityStatusChildChannel
|
|
|
21
18
|
from mousetools.channels.forecastedwaittimes import ForecastedWaitTimesChildChannel
|
|
22
19
|
from mousetools.decorators import disney_property
|
|
23
20
|
from mousetools.enums import DestinationShort, EntityType
|
|
24
|
-
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
25
21
|
|
|
26
22
|
logger = logging.getLogger(__name__)
|
|
27
23
|
|
|
28
24
|
|
|
29
|
-
class FacilityChildChannel(
|
|
25
|
+
class FacilityChildChannel(CouchbaseChildChannel):
|
|
30
26
|
"""Base class for all Facility Child Channels. Subclasses like Attraction, Restaurant, Entertainment, etc. extend this class.
|
|
31
27
|
|
|
32
28
|
Example:
|
|
@@ -51,35 +47,12 @@ class FacilityChildChannel(CouchbaseMixin):
|
|
|
51
47
|
channel_id (str): Facility Channel ID
|
|
52
48
|
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
53
49
|
"""
|
|
54
|
-
|
|
55
|
-
channel_id = channel_id.value
|
|
50
|
+
super().__init__(channel_id, lazy_load=lazy_load)
|
|
56
51
|
|
|
57
|
-
self.
|
|
58
|
-
self.entity_id: str = channel_id.rsplit(".", 1)[-1]
|
|
59
|
-
|
|
60
|
-
self._destination_short: DestinationShort = self.channel_id.split(".")[0]
|
|
61
|
-
self._tz: DestinationTimezones = (
|
|
62
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
63
|
-
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
64
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
65
|
-
)
|
|
66
|
-
self._refresh_interval: timedelta = timedelta(
|
|
67
|
-
hours=12
|
|
68
|
-
) # properties are rarely updated, no need to spam the API
|
|
69
|
-
|
|
70
|
-
self._cb_data: typing.Optional[dict] = None
|
|
71
|
-
self._cb_data_pull_time: datetime = datetime.now(tz=self._tz.value)
|
|
72
|
-
if not lazy_load:
|
|
73
|
-
self.refresh()
|
|
52
|
+
self._refresh_interval = timedelta(weeks=1) # properties are rarely updated
|
|
74
53
|
|
|
75
54
|
self._today_calendar: typing.Optional[CalendarChildChannel] = None
|
|
76
55
|
|
|
77
|
-
def refresh(self) -> None:
|
|
78
|
-
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
79
|
-
if self._cb_data is None or datetime.now(tz=self._tz.value) - self.last_update > self._refresh_interval:
|
|
80
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
81
|
-
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
82
|
-
|
|
83
56
|
def pull_today_calendar(self) -> None:
|
|
84
57
|
"""Pulls today's calendar.
|
|
85
58
|
|
|
@@ -392,30 +365,6 @@ class FacilityChildChannel(CouchbaseMixin):
|
|
|
392
365
|
|
|
393
366
|
return FacilityStatusChildChannel(facility_status_channel_id)
|
|
394
367
|
|
|
395
|
-
@property
|
|
396
|
-
def last_update(self) -> datetime:
|
|
397
|
-
"""
|
|
398
|
-
The last time the data was updated.
|
|
399
|
-
|
|
400
|
-
Returns:
|
|
401
|
-
(datetime): The last time the entity's data was updated, or None if no such data exists.
|
|
402
|
-
"""
|
|
403
|
-
if self._cb_data is None:
|
|
404
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
405
|
-
|
|
406
|
-
try:
|
|
407
|
-
tz = (
|
|
408
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
409
|
-
if "wdw" in self.channel_id
|
|
410
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
411
|
-
)
|
|
412
|
-
dt = isoparse(self._cb_data["lastUpdate"])
|
|
413
|
-
dt = dt.replace(tzinfo=tz.value)
|
|
414
|
-
return dt
|
|
415
|
-
except (KeyError, TypeError, ValueError):
|
|
416
|
-
logger.debug("No last updated found for %s", self.channel_id)
|
|
417
|
-
return self._cb_data_pull_time
|
|
418
|
-
|
|
419
368
|
@disney_property()
|
|
420
369
|
def sponsor_name(self) -> typing.Optional[str]:
|
|
421
370
|
"""The sponsor name of the entity.
|
|
@@ -4,42 +4,24 @@ from datetime import datetime, timedelta
|
|
|
4
4
|
|
|
5
5
|
from dateutil.parser import isoparse
|
|
6
6
|
|
|
7
|
-
from mousetools.channels import CouchbaseChannel
|
|
8
|
-
from mousetools.channels.enums import CouchbaseChannels
|
|
7
|
+
from mousetools.channels import CouchbaseChannel, CouchbaseChildChannel
|
|
8
|
+
from mousetools.channels.enums import CouchbaseChannels
|
|
9
9
|
from mousetools.decorators import disney_property
|
|
10
|
-
from mousetools.enums import
|
|
11
|
-
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
10
|
+
from mousetools.enums import EntityType
|
|
12
11
|
|
|
13
12
|
logger = logging.getLogger(__name__)
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
class FacilityStatusChildChannel(
|
|
15
|
+
class FacilityStatusChildChannel(CouchbaseChildChannel):
|
|
17
16
|
def __init__(self, channel_id: str, lazy_load: bool = True):
|
|
18
17
|
"""
|
|
19
18
|
Args:
|
|
20
19
|
channel_id (typing.Union[WDWCouchbaseChannels, DLRCouchbaseChannels]): Channel ID from the enum
|
|
21
20
|
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
22
21
|
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
self._destination_short: DestinationShort = channel_id.split(".")[0]
|
|
26
|
-
self._tz: DestinationTimezones = (
|
|
27
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
28
|
-
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
29
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
30
|
-
)
|
|
31
|
-
self._refresh_interval: timedelta = timedelta(minutes=10)
|
|
32
|
-
self._cb_data: typing.Optional[dict] = None
|
|
33
|
-
self._cb_data_pull_time: datetime = datetime.now(tz=self._tz.value)
|
|
34
|
-
|
|
35
|
-
if not lazy_load:
|
|
36
|
-
self.refresh()
|
|
22
|
+
super().__init__(channel_id, lazy_load=lazy_load)
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
40
|
-
if self._cb_data is None or datetime.now(tz=self._tz.value) - self.last_update > self._refresh_interval:
|
|
41
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
42
|
-
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
24
|
+
self._refresh_interval: timedelta = timedelta(minutes=10)
|
|
43
25
|
|
|
44
26
|
def get_status(self) -> typing.Optional[str]:
|
|
45
27
|
"""Get the operating status of the facility
|
|
@@ -69,24 +51,6 @@ class FacilityStatusChildChannel(CouchbaseMixin):
|
|
|
69
51
|
logger.debug("No wait time found for %s", self.channel_id)
|
|
70
52
|
return None
|
|
71
53
|
|
|
72
|
-
@property
|
|
73
|
-
def last_update(self) -> datetime:
|
|
74
|
-
"""The last time the data was updated.
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
(datetime): The last time the entity's data was updated, or None if no such data exists.
|
|
78
|
-
"""
|
|
79
|
-
if self._cb_data is None:
|
|
80
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
81
|
-
|
|
82
|
-
try:
|
|
83
|
-
dt = isoparse(self._cb_data["lastUpdate"])
|
|
84
|
-
dt = dt.replace(tzinfo=self._tz.value)
|
|
85
|
-
return dt
|
|
86
|
-
except (KeyError, TypeError, ValueError):
|
|
87
|
-
logger.debug("No last updated found for %s", self.channel_id)
|
|
88
|
-
return self._cb_data_pull_time
|
|
89
|
-
|
|
90
54
|
@disney_property()
|
|
91
55
|
def fast_pass_available(self) -> typing.Optional[bool]:
|
|
92
56
|
return self._cb_data["fastPassAvailable"]
|
|
@@ -157,6 +121,25 @@ class FacilityStatusChannel(CouchbaseChannel):
|
|
|
157
121
|
channels.append(FacilityStatusChildChannel(i["id"]))
|
|
158
122
|
return channels
|
|
159
123
|
|
|
124
|
+
def get_all_statuses(self) -> dict[str, dict[str, typing.Any]]:
|
|
125
|
+
"""Get all statuses for the channel
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
(dict[str, dict[str, typing.Any]]): A dictionary of all statuses for the channel
|
|
129
|
+
"""
|
|
130
|
+
logger.info("Getting all children statuses for %s", self.channel_id)
|
|
131
|
+
children = self.get_children_channels()
|
|
132
|
+
logger.debug("Got %d children for %s", len(children), self.channel_id)
|
|
133
|
+
|
|
134
|
+
statuses = {}
|
|
135
|
+
for child in children:
|
|
136
|
+
tmp = {}
|
|
137
|
+
tmp["status"] = child.get_status()
|
|
138
|
+
tmp["wait_time"] = child.get_wait_time()
|
|
139
|
+
statuses[child.entity_id] = tmp
|
|
140
|
+
|
|
141
|
+
return statuses
|
|
142
|
+
|
|
160
143
|
def get_children_attractions(self) -> list[AttractionFacilityStatusChild]: # type: ignore
|
|
161
144
|
"""Get AttractionFacilityStatusChild Children of a Facility
|
|
162
145
|
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import typing
|
|
3
|
-
from datetime import datetime, timedelta
|
|
4
|
-
from enum import Enum
|
|
5
2
|
|
|
6
3
|
from dateutil.parser import isoparse
|
|
7
4
|
|
|
8
|
-
from mousetools.channels import CouchbaseChannel
|
|
9
|
-
from mousetools.channels.enums import CouchbaseChannels
|
|
10
|
-
from mousetools.enums import DestinationShort
|
|
11
|
-
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
5
|
+
from mousetools.channels import CouchbaseChannel, CouchbaseChildChannel
|
|
6
|
+
from mousetools.channels.enums import CouchbaseChannels
|
|
12
7
|
|
|
13
8
|
logger = logging.getLogger(__name__)
|
|
14
9
|
|
|
15
10
|
|
|
16
|
-
class ForecastedWaitTimesChildChannel(
|
|
11
|
+
class ForecastedWaitTimesChildChannel(CouchbaseChildChannel):
|
|
17
12
|
def __init__(
|
|
18
13
|
self,
|
|
19
14
|
channel_id: str,
|
|
@@ -24,52 +19,11 @@ class ForecastedWaitTimesChildChannel(CouchbaseMixin):
|
|
|
24
19
|
channel_id (str): Forecasted Wait Times Channel ID
|
|
25
20
|
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
26
21
|
"""
|
|
27
|
-
|
|
28
|
-
channel_id = channel_id.value
|
|
29
|
-
|
|
30
|
-
self.channel_id: str = channel_id
|
|
31
|
-
self.entity_id: str = channel_id.rsplit(".", 1)[-1]
|
|
32
|
-
|
|
33
|
-
self._destination_short: DestinationShort = self.channel_id.split(".")[0]
|
|
34
|
-
self._tz: DestinationTimezones = (
|
|
35
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
36
|
-
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
37
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
38
|
-
)
|
|
39
|
-
self._refresh_interval: timedelta = timedelta(minutes=30)
|
|
40
|
-
|
|
41
|
-
self._cb_data: typing.Optional[dict] = None
|
|
42
|
-
self._cb_data_pull_time: datetime = datetime.now(tz=self._tz.value)
|
|
43
|
-
if not lazy_load:
|
|
44
|
-
self.refresh()
|
|
22
|
+
super().__init__(channel_id, lazy_load=lazy_load)
|
|
45
23
|
|
|
46
24
|
def __repr__(self):
|
|
47
25
|
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
48
26
|
|
|
49
|
-
def refresh(self) -> None:
|
|
50
|
-
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
51
|
-
if self._cb_data is None or datetime.now(tz=self._tz.value) - self.last_update > self._refresh_interval:
|
|
52
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
53
|
-
self._cb_data_pull_time = datetime.now(tz=self._tz.value)
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def last_update(self) -> datetime:
|
|
57
|
-
"""The last time the data was updated.
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
(datetime): The last time the entity's data was updated, or None if no such data exists.
|
|
61
|
-
"""
|
|
62
|
-
if self._cb_data is None:
|
|
63
|
-
self._cb_data = self.get_channel_data(self.channel_id)
|
|
64
|
-
|
|
65
|
-
try:
|
|
66
|
-
dt = isoparse(self._cb_data["lastUpdate"])
|
|
67
|
-
dt = dt.replace(tzinfo=self._tz.value)
|
|
68
|
-
return dt
|
|
69
|
-
except (KeyError, TypeError, ValueError):
|
|
70
|
-
logger.debug("No last updated found for %s", self.channel_id)
|
|
71
|
-
return self._cb_data_pull_time
|
|
72
|
-
|
|
73
27
|
def get_forecast(self) -> list[dict]:
|
|
74
28
|
"""Returns a list of forecasted wait times sorted by timestamp
|
|
75
29
|
|
|
@@ -18,6 +18,7 @@ def disney_property(
|
|
|
18
18
|
try:
|
|
19
19
|
return func(self)
|
|
20
20
|
except (KeyError, TypeError, ValueError):
|
|
21
|
+
logger.debug("No data found for disney property %s, returning default value", func.__name__)
|
|
21
22
|
return default_value
|
|
22
23
|
|
|
23
24
|
wrapper.__annotations__ = func.__annotations__
|
|
@@ -34,6 +35,7 @@ def json_property(func: Callable) -> property:
|
|
|
34
35
|
try:
|
|
35
36
|
return func(self)
|
|
36
37
|
except (KeyError, TypeError, ValueError):
|
|
38
|
+
logger.debug("No data found for json property %s", func.__name__)
|
|
37
39
|
return None
|
|
38
40
|
|
|
39
41
|
return wrapper
|
|
@@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class CouchbaseMixin:
|
|
14
|
-
_couchbase_url = "https://" + auth_obj._environments["syncGatewayUrl"].split("//")[1]
|
|
14
|
+
_couchbase_url = "https://" + auth_obj._environments["syncGatewayUrl"].split("//")[1].rstrip("/")
|
|
15
15
|
_headers: dict = auth_obj.get_couchbase_headers()
|
|
16
16
|
|
|
17
17
|
def get_channel_data(self, channel_name: str) -> typing.Union[dict, None]:
|
|
@@ -35,8 +35,9 @@ class CouchbaseMixin:
|
|
|
35
35
|
"json": True,
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
logger.info("Sending request for channel data: %s", channel_name)
|
|
38
39
|
response = httpx.post(self._couchbase_url + "/_bulk_get", json=payload, headers=self._headers)
|
|
39
|
-
logger.debug("Response status: %s", response.status_code)
|
|
40
|
+
logger.debug("Response status for %s: %s", channel_name, response.status_code)
|
|
40
41
|
data = None
|
|
41
42
|
try:
|
|
42
43
|
response.raise_for_status()
|
|
@@ -71,7 +72,9 @@ class CouchbaseMixin:
|
|
|
71
72
|
if since:
|
|
72
73
|
payload["since"] = since
|
|
73
74
|
|
|
75
|
+
logger.info("Sending request for channel changes: %s", channel_name)
|
|
74
76
|
response = httpx.post(self._couchbase_url + "/_changes", json=payload, headers=self._headers)
|
|
77
|
+
logger.debug("Response status for %s: %s", channel_name, response.status_code)
|
|
75
78
|
data = response.raise_for_status().json()
|
|
76
79
|
except httpx.HTTPError as err:
|
|
77
80
|
logger.error("Request failed: %s", err)
|
|
@@ -31,7 +31,7 @@ class DisneyAPIMixin:
|
|
|
31
31
|
response.raise_for_status()
|
|
32
32
|
data = response.json()
|
|
33
33
|
except (httpx.HTTPError, json.decoder.JSONDecodeError) as err:
|
|
34
|
-
logger.
|
|
34
|
+
logger.error("Request failed. Error: %s", err)
|
|
35
35
|
return None
|
|
36
36
|
|
|
37
37
|
return data
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from enum import Enum
|
|
4
|
-
|
|
5
|
-
from mousetools.channels.enums import DestinationTimezones, DLRCouchbaseChannels, WDWCouchbaseChannels
|
|
6
|
-
from mousetools.enums import DestinationShort, EntityType
|
|
7
|
-
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class CouchbaseChannel(CouchbaseMixin):
|
|
11
|
-
def __init__(self, channel_id: typing.Union[WDWCouchbaseChannels, DLRCouchbaseChannels], lazy_load: bool = True):
|
|
12
|
-
"""
|
|
13
|
-
Args:
|
|
14
|
-
channel_id (typing.Union[WDWCouchbaseChannels, DLRCouchbaseChannels]): Channel ID from the enum
|
|
15
|
-
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
16
|
-
"""
|
|
17
|
-
if isinstance(channel_id, Enum):
|
|
18
|
-
channel_id = channel_id.value
|
|
19
|
-
self.channel_id = channel_id
|
|
20
|
-
|
|
21
|
-
self._destination_short: DestinationShort = channel_id.split(".")[0]
|
|
22
|
-
self._tz: DestinationTimezones = (
|
|
23
|
-
DestinationTimezones.WALT_DISNEY_WORLD
|
|
24
|
-
if self._destination_short == DestinationShort.WALT_DISNEY_WORLD
|
|
25
|
-
else DestinationTimezones.DISNEYLAND_RESORT
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
self._cb_data = None
|
|
29
|
-
self._refresh_interval = timedelta(minutes=10)
|
|
30
|
-
self.last_update = datetime.now(tz=self._tz.value)
|
|
31
|
-
|
|
32
|
-
if not lazy_load:
|
|
33
|
-
self.refresh()
|
|
34
|
-
|
|
35
|
-
def refresh(self) -> None:
|
|
36
|
-
"""Pulls initial data if none exists or if it is older than the refresh interval"""
|
|
37
|
-
if self._cb_data is None or datetime.now(tz=self._tz.value) - self.last_update > self._refresh_interval:
|
|
38
|
-
self._cb_data = self.get_channel_changes(self.channel_id)
|
|
39
|
-
self.last_update = datetime.now(tz=self._tz.value)
|
|
40
|
-
|
|
41
|
-
def get_children_channel_ids(self) -> list[str]:
|
|
42
|
-
"""Returns a list of child channel ids for the channel."""
|
|
43
|
-
self.refresh()
|
|
44
|
-
|
|
45
|
-
return [i["id"] for i in self._cb_data["results"]]
|
|
46
|
-
|
|
47
|
-
def _get_children_objects_helper(self, class_obj, entity_type: EntityType) -> list:
|
|
48
|
-
self.refresh()
|
|
49
|
-
channels = []
|
|
50
|
-
check_for = f"entitytype={entity_type.value}".lower()
|
|
51
|
-
for i in self._cb_data["results"]:
|
|
52
|
-
if check_for == i["id"].rsplit(";")[-1].lower():
|
|
53
|
-
channels.append(class_obj(i["id"]))
|
|
54
|
-
return channels
|
|
55
|
-
|
|
56
|
-
def __repr__(self):
|
|
57
|
-
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
58
|
-
|
|
59
|
-
def __eq__(self, other) -> bool:
|
|
60
|
-
if isinstance(other, CouchbaseChannel):
|
|
61
|
-
return self.channel_id == other.channel_id
|
|
62
|
-
return False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|