MouseTools 4.0.2__tar.gz → 4.1.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.
- {mousetools-4.0.2 → mousetools-4.1.0}/PKG-INFO +24 -2
- {mousetools-4.0.2 → mousetools-4.1.0}/README.md +23 -1
- mousetools-4.1.0/mousetools/api/search.py +58 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/channels/__init__.py +8 -2
- mousetools-4.1.0/mousetools/channels/calendar/__init__.py +311 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/channels/enums.py +1 -4
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/channels/facilities/__init__.py +230 -68
- mousetools-4.1.0/mousetools/channels/facilities/enums.py +32 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/channels/facilitystatus/__init__.py +11 -12
- mousetools-4.1.0/mousetools/enums.py +34 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools.egg-info/PKG-INFO +24 -2
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools.egg-info/SOURCES.txt +3 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/pyproject.toml +1 -1
- mousetools-4.0.2/mousetools/channels/facilities/enums.py +0 -30
- {mousetools-4.0.2 → mousetools-4.1.0}/LICENSE +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/__init__.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/api/__init__.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/api/menu.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/auth.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/mixins/__init__.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/mixins/couchbase.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/mixins/disney.py +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools/resources/environments.bin +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools.egg-info/dependency_links.txt +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools.egg-info/requires.txt +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/mousetools.egg-info/top_level.txt +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/setup.cfg +0 -0
- {mousetools-4.0.2 → mousetools-4.1.0}/tests/test_mixins.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mousetools
|
|
3
|
-
Version: 4.0
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: An unofficial Python wrapper for Disney's API
|
|
5
5
|
Author: Scott Caratozzolo
|
|
6
6
|
License-Expression: MIT
|
|
@@ -25,7 +25,7 @@ Dynamic: license-file
|
|
|
25
25
|
|
|
26
26
|
# MouseTools
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
 
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
An unofficial Python wrapper for the Disney API. Data is pulled directly from Disney. This package supports Walt Disney World and Disneyland Resort.
|
|
@@ -110,8 +110,30 @@ print(mk.description)
|
|
|
110
110
|
# "Enter a Land Where Fantasy Reigns"
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
There is also a search functionality to help find the channels you want.
|
|
114
|
+
```python
|
|
115
|
+
from mousetools.api.search import Search
|
|
116
|
+
from mousetools.enums import DestinationShort
|
|
117
|
+
|
|
118
|
+
search = Search(DestinationShort.WALT_DISNEY_WORLD)
|
|
119
|
+
print(search("pirates", max_results=1))
|
|
120
|
+
# [{'channel_id': 'wdw.facilities.1_0.en_us.attraction.80010177;entityType=Attraction',
|
|
121
|
+
# 'entity_id': '80010177;entityType=Attraction',
|
|
122
|
+
# 'name': 'Pirates of the Caribbean',
|
|
123
|
+
# 'search_score': 3507.1604}]
|
|
124
|
+
```
|
|
125
|
+
|
|
113
126
|
### License
|
|
114
127
|
This project is distributed under the MIT license. For more information see [LICENSE](https://gitlab.com/caratozzoloxyz/public/MouseTools/-/blob/master/LICENSE?ref_type=heads)
|
|
115
128
|
|
|
116
129
|
### Disclaimer
|
|
117
130
|
This project is in no way affiliated with The Walt Disney Company and all use of Disney Services is subject to the [Disney Terms of Use](https://disneytermsofuse.com/).
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
### About Project
|
|
134
|
+
|
|
135
|
+
<a href='https://ko-fi.com/scaratozzolo' target='_blank'>
|
|
136
|
+
<img src='https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=kofi&logoColor=white&link=https%3A%2F%2Fko-fi.com%2Fscaratozzolo border='0' alt='Support my projects' />
|
|
137
|
+
</a>
|
|
138
|
+
|
|
139
|
+
MouseTools is a passion project I've been working on since 2018 when I was first learning Python. The package has evolved and been rewritten multiple times as I've become a better developer and as the Disney API has changed. There is a lot of time exploring Disney's API and figuring out how all the pieces work before any code is even written. I work on this project when I have time or when I have an idea for another project that could use this data.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MouseTools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
 
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
An unofficial Python wrapper for the Disney API. Data is pulled directly from Disney. This package supports Walt Disney World and Disneyland Resort.
|
|
@@ -85,8 +85,30 @@ print(mk.description)
|
|
|
85
85
|
# "Enter a Land Where Fantasy Reigns"
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
There is also a search functionality to help find the channels you want.
|
|
89
|
+
```python
|
|
90
|
+
from mousetools.api.search import Search
|
|
91
|
+
from mousetools.enums import DestinationShort
|
|
92
|
+
|
|
93
|
+
search = Search(DestinationShort.WALT_DISNEY_WORLD)
|
|
94
|
+
print(search("pirates", max_results=1))
|
|
95
|
+
# [{'channel_id': 'wdw.facilities.1_0.en_us.attraction.80010177;entityType=Attraction',
|
|
96
|
+
# 'entity_id': '80010177;entityType=Attraction',
|
|
97
|
+
# 'name': 'Pirates of the Caribbean',
|
|
98
|
+
# 'search_score': 3507.1604}]
|
|
99
|
+
```
|
|
100
|
+
|
|
88
101
|
### License
|
|
89
102
|
This project is distributed under the MIT license. For more information see [LICENSE](https://gitlab.com/caratozzoloxyz/public/MouseTools/-/blob/master/LICENSE?ref_type=heads)
|
|
90
103
|
|
|
91
104
|
### Disclaimer
|
|
92
105
|
This project is in no way affiliated with The Walt Disney Company and all use of Disney Services is subject to the [Disney Terms of Use](https://disneytermsofuse.com/).
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
### About Project
|
|
109
|
+
|
|
110
|
+
<a href='https://ko-fi.com/scaratozzolo' target='_blank'>
|
|
111
|
+
<img src='https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=kofi&logoColor=white&link=https%3A%2F%2Fko-fi.com%2Fscaratozzolo border='0' alt='Support my projects' />
|
|
112
|
+
</a>
|
|
113
|
+
|
|
114
|
+
MouseTools is a passion project I've been working on since 2018 when I was first learning Python. The package has evolved and been rewritten multiple times as I've become a better developer and as the Disney API has changed. There is a lot of time exploring Disney's API and figuring out how all the pieces work before any code is even written. I work on this project when I have time or when I have an idea for another project that could use this data.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import Optional, Union
|
|
2
|
+
|
|
3
|
+
from mousetools.auth import auth_obj
|
|
4
|
+
from mousetools.channels.enums import DLRCouchbaseChannels, WDWCouchbaseChannels
|
|
5
|
+
from mousetools.enums import DestinationShort
|
|
6
|
+
from mousetools.mixins.disney import DisneyAPIMixin
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Search(DisneyAPIMixin):
|
|
10
|
+
_search_service_base = auth_obj._environments["searchServiceUrl"]
|
|
11
|
+
|
|
12
|
+
def __init__(self, destination: Union[DestinationShort, str]):
|
|
13
|
+
"""
|
|
14
|
+
Args:
|
|
15
|
+
destination (Union[DestinationShort, str]): Search the facilities for this destination
|
|
16
|
+
"""
|
|
17
|
+
if isinstance(destination, DestinationShort):
|
|
18
|
+
destination = destination.value
|
|
19
|
+
self.destination = destination
|
|
20
|
+
self._facilities_channel = (
|
|
21
|
+
WDWCouchbaseChannels.FACILITIES.value
|
|
22
|
+
if destination == DestinationShort.WALT_DISNEY_WORLD
|
|
23
|
+
else DLRCouchbaseChannels.FACILITIES.value
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def search(self, query: str, max_results: int = 10) -> Optional[list[dict]]:
|
|
27
|
+
"""Send a request to the search service
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
query (str): Search query
|
|
31
|
+
max_results (int, optional): Maximum number of results to return in the list. Defaults to 10.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
(Optional[list[dict]]): List of results
|
|
35
|
+
"""
|
|
36
|
+
api_data = self.get_disney_data(
|
|
37
|
+
f"{self._search_service_base}/mobileapi/v1/entities/search?q={query}&brand={self.destination}"
|
|
38
|
+
)
|
|
39
|
+
our_results = []
|
|
40
|
+
for i in api_data.get("results", [])[:max_results]:
|
|
41
|
+
tmp = {}
|
|
42
|
+
tmp["entity_id"] = i["id"]
|
|
43
|
+
tmp["name"] = i["title"][0]
|
|
44
|
+
tmp["search_score"] = i["score"]
|
|
45
|
+
tmp["channel_id"] = f"{self._facilities_channel}.{i['id'].rsplit('=')[-1].lower()}.{i['id']}"
|
|
46
|
+
our_results.append(tmp)
|
|
47
|
+
return our_results
|
|
48
|
+
|
|
49
|
+
def __call__(self, *args, **kwargs) -> Optional[list[dict]]:
|
|
50
|
+
"""Call the search function
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
(Optional[list[dict]]): List of results
|
|
54
|
+
"""
|
|
55
|
+
return self.search(*args, **kwargs)
|
|
56
|
+
|
|
57
|
+
def __repr__(self):
|
|
58
|
+
return f"Search(destination='{self.destination}')"
|
|
@@ -2,7 +2,8 @@ import typing
|
|
|
2
2
|
from datetime import datetime, timedelta
|
|
3
3
|
from enum import Enum
|
|
4
4
|
|
|
5
|
-
from mousetools.channels.enums import
|
|
5
|
+
from mousetools.channels.enums import DestinationTimezones, DLRCouchbaseChannels, WDWCouchbaseChannels
|
|
6
|
+
from mousetools.enums import DestinationShort
|
|
6
7
|
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
7
8
|
|
|
8
9
|
|
|
@@ -44,4 +45,9 @@ class CouchbaseChannel(CouchbaseMixin):
|
|
|
44
45
|
return [i["id"] for i in self._cb_data["results"]]
|
|
45
46
|
|
|
46
47
|
def __repr__(self):
|
|
47
|
-
return f"{self.__class__.__name__}({self.channel_id})"
|
|
48
|
+
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
49
|
+
|
|
50
|
+
def __eq__(self, other) -> bool:
|
|
51
|
+
if isinstance(other, CouchbaseChannel):
|
|
52
|
+
return self.channel_id == other.channel_id
|
|
53
|
+
return False
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import typing
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from zoneinfo import ZoneInfo
|
|
6
|
+
|
|
7
|
+
from dateutil.parser import isoparse
|
|
8
|
+
|
|
9
|
+
from mousetools.channels import CouchbaseChannel
|
|
10
|
+
from mousetools.channels.enums import CouchbaseChannels, DestinationTimezones
|
|
11
|
+
from mousetools.enums import DestinationShort
|
|
12
|
+
from mousetools.mixins.couchbase import CouchbaseMixin
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CalendarChildChannel(CouchbaseMixin):
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
channel_id: str,
|
|
21
|
+
lazy_load: bool = True,
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
Args:
|
|
25
|
+
channel_id (str): Calendar Channel ID
|
|
26
|
+
lazy_load (bool, optional): If True, will not pull data until a method or property is called. Defaults to True.
|
|
27
|
+
"""
|
|
28
|
+
if isinstance(channel_id, Enum):
|
|
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: typing.Optional[dict] = None
|
|
43
|
+
self._cb_data_pull_time: typing.Optional[datetime] = datetime.now(tz=self._tz.value)
|
|
44
|
+
if not lazy_load:
|
|
45
|
+
self.refresh()
|
|
46
|
+
|
|
47
|
+
def __repr__(self):
|
|
48
|
+
return f"{self.__class__.__name__}(channel_id='{self.channel_id}')"
|
|
49
|
+
|
|
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 calendar_id(self) -> typing.Optional[str]:
|
|
58
|
+
"""The ID of the calendar
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
(typing.Optional[str]): The ID of the calendar, or None if no such data exists.
|
|
62
|
+
"""
|
|
63
|
+
self.refresh()
|
|
64
|
+
try:
|
|
65
|
+
return self._cb_data["id"]
|
|
66
|
+
except KeyError:
|
|
67
|
+
logger.debug("No id found for %s", self.channel_id)
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def last_update(self) -> typing.Optional[datetime]:
|
|
72
|
+
"""The last time the data was updated.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
(typing.Optional[datetime]): The last time the entity's data was updated, or None if no such data exists.
|
|
76
|
+
"""
|
|
77
|
+
if self._cb_data is None:
|
|
78
|
+
self._cb_data = self.get_channel_data(self.channel_id)
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
dt = isoparse(self._cb_data["lastUpdate"])
|
|
82
|
+
dt = dt.replace(tzinfo=self._tz.value)
|
|
83
|
+
return dt
|
|
84
|
+
except KeyError:
|
|
85
|
+
logger.debug("No last updated found for %s", self.channel_id)
|
|
86
|
+
return self._cb_data_pull_time
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def all_closed(self) -> typing.Optional[list[dict]]:
|
|
90
|
+
"""The list of closed facilities.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
(typing.Optional[list[dict]]): The list of closed facilities, or None if no such data exists.
|
|
94
|
+
"""
|
|
95
|
+
self.refresh()
|
|
96
|
+
try:
|
|
97
|
+
return self._cb_data["closed"]
|
|
98
|
+
except KeyError:
|
|
99
|
+
logger.debug("No closed found for %s", self.channel_id)
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def all_facility_schedules(self) -> typing.Optional[dict[str, list[dict]]]:
|
|
104
|
+
"""The list of facility schedules.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
(typing.Optional[dict[str, list[dict]]]): The list of facility schedules, or None if no such data exists.
|
|
108
|
+
"""
|
|
109
|
+
self.refresh()
|
|
110
|
+
try:
|
|
111
|
+
return self._cb_data["facilitySchedules"]
|
|
112
|
+
except KeyError:
|
|
113
|
+
logger.debug("No facility schedules found for %s", self.channel_id)
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def all_meal_periods(self) -> typing.Optional[dict[str, list[dict]]]:
|
|
118
|
+
"""The list of meal periods.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
(typing.Optional[dict[str, list[dict]]]): The list of meal periods, or None if no such data exists.
|
|
122
|
+
"""
|
|
123
|
+
self.refresh()
|
|
124
|
+
try:
|
|
125
|
+
return self._cb_data["mealPeriods"]
|
|
126
|
+
except KeyError:
|
|
127
|
+
logger.debug("No meal periods found for %s", self.channel_id)
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def all_park_hours(self) -> typing.Optional[list[dict]]:
|
|
132
|
+
"""The list of park hours.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
(typing.Optional[list[dict]]): The list of park hours, or None if no such data exists.
|
|
136
|
+
"""
|
|
137
|
+
self.refresh()
|
|
138
|
+
try:
|
|
139
|
+
return self._cb_data["parkHours"]
|
|
140
|
+
except KeyError:
|
|
141
|
+
logger.debug("No park hours found for %s", self.channel_id)
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def all_private_events(self) -> typing.Optional[list[dict]]:
|
|
146
|
+
"""The list of private events.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
(typing.Optional[list[dict]]): The list of private events, or None if no such data exists.
|
|
150
|
+
"""
|
|
151
|
+
self.refresh()
|
|
152
|
+
try:
|
|
153
|
+
return self._cb_data["privateEvents"]
|
|
154
|
+
except KeyError:
|
|
155
|
+
logger.debug("No private events found for %s", self.channel_id)
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def all_refurbishments(self) -> typing.Optional[list[dict]]:
|
|
160
|
+
"""The list of refurbishments.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
(typing.Optional[list[dict]]): The list of refurbishments, or None if no such data exists.
|
|
164
|
+
"""
|
|
165
|
+
self.refresh()
|
|
166
|
+
try:
|
|
167
|
+
return self._cb_data["refurbishments"]
|
|
168
|
+
except KeyError:
|
|
169
|
+
logger.debug("No refurbishments found for %s", self.channel_id)
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def timezone(self) -> ZoneInfo:
|
|
174
|
+
"""The timezone of the calendar.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
(ZoneInfo): The timezone of the calendar.
|
|
178
|
+
"""
|
|
179
|
+
return self._tz.value
|
|
180
|
+
|
|
181
|
+
def get_park_hours(self, entity_id: str) -> dict:
|
|
182
|
+
"""Get the park hours for the given entity
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
entity_id (str): entity id of the facility
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
dict: park hours broken up into their schedule types (Operating, Early Entry, etc.)
|
|
189
|
+
"""
|
|
190
|
+
hours = {}
|
|
191
|
+
if self.all_park_hours:
|
|
192
|
+
for i in self.all_park_hours:
|
|
193
|
+
if entity_id in i["facilityId"]:
|
|
194
|
+
hours[i["scheduleType"]] = {}
|
|
195
|
+
hours[i["scheduleType"]]["start"] = isoparse(i["startTime"]).astimezone(self._tz.value)
|
|
196
|
+
hours[i["scheduleType"]]["end"] = isoparse(i["endTime"]).astimezone(self._tz.value)
|
|
197
|
+
return hours
|
|
198
|
+
|
|
199
|
+
def get_meal_periods(self, entity_id: str) -> dict:
|
|
200
|
+
"""Get the meal periods for the given entity
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
entity_id (str): entity id of the facility
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
dict: meal periods
|
|
207
|
+
"""
|
|
208
|
+
periods = {}
|
|
209
|
+
if self.all_meal_periods:
|
|
210
|
+
restaurant = self.all_meal_periods.get(entity_id, [])
|
|
211
|
+
for i in restaurant:
|
|
212
|
+
meal_period = i["facilityId"]
|
|
213
|
+
periods[meal_period] = {}
|
|
214
|
+
periods[meal_period]["start"] = isoparse(i["startTime"]).astimezone(self._tz.value)
|
|
215
|
+
periods[meal_period]["end"] = isoparse(i["endTime"]).astimezone(self._tz.value)
|
|
216
|
+
periods[meal_period]["schedule_type"] = i["scheduleType"]
|
|
217
|
+
return periods
|
|
218
|
+
|
|
219
|
+
def get_refurbishment(self, entity_id: str) -> dict:
|
|
220
|
+
"""Get the refurbishment info for the given entity
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
entity_id (str): entity id of the facility
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
dict: refurbishments
|
|
227
|
+
"""
|
|
228
|
+
refurbishments = {}
|
|
229
|
+
if self.all_refurbishments:
|
|
230
|
+
for i in self.all_refurbishments:
|
|
231
|
+
if entity_id in i["facilityId"]:
|
|
232
|
+
refurbishments["start"] = isoparse(i["startTime"]).astimezone(self._tz.value)
|
|
233
|
+
refurbishments["end"] = isoparse(i["endTime"]).astimezone(self._tz.value)
|
|
234
|
+
return refurbishments
|
|
235
|
+
|
|
236
|
+
def get_closed(self, entity_id: str) -> dict:
|
|
237
|
+
"""Get the closed info for the given entity
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
entity_id (str): entity id of the facility
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
dict: closed
|
|
244
|
+
"""
|
|
245
|
+
closed = {}
|
|
246
|
+
if self.all_closed:
|
|
247
|
+
for i in self.all_closed:
|
|
248
|
+
if entity_id in i["facilityId"]:
|
|
249
|
+
closed["start"] = isoparse(i["startTime"]).astimezone(self._tz.value)
|
|
250
|
+
closed["end"] = isoparse(i["endTime"]).astimezone(self._tz.value)
|
|
251
|
+
return closed
|
|
252
|
+
|
|
253
|
+
def get_facility_schedule(self, entity_id: str) -> list[dict]:
|
|
254
|
+
"""Get the schedule info for the given entity
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
entity_id (str): entity id of the facility
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
(list[dict]): schedules
|
|
261
|
+
"""
|
|
262
|
+
schedules = []
|
|
263
|
+
if self.all_facility_schedules:
|
|
264
|
+
facility = self.all_facility_schedules.get(entity_id, [])
|
|
265
|
+
for i in facility:
|
|
266
|
+
tmp = {}
|
|
267
|
+
tmp["start"] = isoparse(i["startTime"]).astimezone(self._tz.value)
|
|
268
|
+
tmp["end"] = isoparse(i["endTime"]).astimezone(self._tz.value)
|
|
269
|
+
tmp["schedule_type"] = i["scheduleType"]
|
|
270
|
+
schedules.append(tmp)
|
|
271
|
+
return sorted(schedules, key=lambda i: i["start"])
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class CalendarChannel(CouchbaseChannel):
|
|
275
|
+
def __init__(self, *args, **kwargs):
|
|
276
|
+
super().__init__(*args, **kwargs)
|
|
277
|
+
|
|
278
|
+
self.available_calendars = {}
|
|
279
|
+
self.refresh_calendars()
|
|
280
|
+
|
|
281
|
+
def refresh_calendars(self):
|
|
282
|
+
"""Refreshes the available calendars."""
|
|
283
|
+
available_calendars = {}
|
|
284
|
+
for i in self.get_children_channels():
|
|
285
|
+
available_calendars[i.entity_id] = i
|
|
286
|
+
|
|
287
|
+
self.available_calendars = available_calendars
|
|
288
|
+
|
|
289
|
+
def get_children_channels(self) -> typing.Generator[CalendarChildChannel, None, None]:
|
|
290
|
+
"""Gets a list of children channels for the channel.
|
|
291
|
+
|
|
292
|
+
Yields:
|
|
293
|
+
typing.Generator[CalendarChildChannel, None, None]: A generator of CalendarChildChannel
|
|
294
|
+
"""
|
|
295
|
+
self.refresh()
|
|
296
|
+
for i in self._cb_data["results"]:
|
|
297
|
+
if CouchbaseChannels.CALENDAR in i["id"]:
|
|
298
|
+
yield CalendarChildChannel(i["id"])
|
|
299
|
+
|
|
300
|
+
def get_calendar(self, day: int, month: int) -> typing.Optional[CalendarChildChannel]:
|
|
301
|
+
"""Get the calendar for the given day and month
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
day (int): day of the month
|
|
305
|
+
month (int): month of the year
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
typing.Optional[CalendarChildChannel]: calendar for the given day and month
|
|
309
|
+
"""
|
|
310
|
+
self.refresh_calendars()
|
|
311
|
+
return self.available_calendars.get(f"{day:02}-{month:02}", None)
|