lghorizon 0.9.0.dev3__py3-none-any.whl → 0.9.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.
- lghorizon/__init__.py +71 -2
- lghorizon/const.py +12 -77
- lghorizon/exceptions.py +3 -3
- lghorizon/lghorizon_api.py +42 -12
- lghorizon/lghorizon_device.py +101 -28
- lghorizon/lghorizon_device_state_processor.py +90 -26
- lghorizon/lghorizon_message_factory.py +0 -1
- lghorizon/lghorizon_models.py +250 -69
- lghorizon/lghorizon_mqtt_client.py +278 -66
- lghorizon/lghorizon_recording_factory.py +16 -2
- lghorizon-0.9.1.dist-info/METADATA +189 -0
- lghorizon-0.9.1.dist-info/RECORD +17 -0
- lghorizon-0.9.0.dev3.dist-info/METADATA +0 -41
- lghorizon-0.9.0.dev3.dist-info/RECORD +0 -17
- {lghorizon-0.9.0.dev3.dist-info → lghorizon-0.9.1.dist-info}/WHEEL +0 -0
- {lghorizon-0.9.0.dev3.dist-info → lghorizon-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {lghorizon-0.9.0.dev3.dist-info → lghorizon-0.9.1.dist-info}/top_level.txt +0 -0
lghorizon/lghorizon_models.py
CHANGED
|
@@ -8,7 +8,7 @@ import time
|
|
|
8
8
|
from abc import ABC, abstractmethod
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
from enum import Enum
|
|
11
|
-
from typing import Any, Dict, List, Optional
|
|
11
|
+
from typing import Any, Dict, List, Optional, Callable
|
|
12
12
|
|
|
13
13
|
import backoff
|
|
14
14
|
from aiohttp import ClientResponseError, ClientSession
|
|
@@ -52,7 +52,7 @@ class LGHorizonRecordingState(Enum):
|
|
|
52
52
|
UNKNOWN = "unknown"
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
class LGHorizonRecordingType(Enum):
|
|
55
|
+
class LGHorizonRecordingType(Enum): # type: ignore[no-redef]
|
|
56
56
|
"""Enumeration of LG Horizon recording states."""
|
|
57
57
|
|
|
58
58
|
SINGLE = "single"
|
|
@@ -91,6 +91,12 @@ class LGHorizonMessage(ABC):
|
|
|
91
91
|
def __init__(self, topic: str, payload: dict) -> None:
|
|
92
92
|
"""Abstract base class for LG Horizon messages."""
|
|
93
93
|
self._topic = topic
|
|
94
|
+
"""Initialize the abstract base class for LG Horizon messages.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
topic: The MQTT topic of the message.
|
|
98
|
+
payload: The dictionary payload of the message.
|
|
99
|
+
"""
|
|
94
100
|
self._payload = payload
|
|
95
101
|
|
|
96
102
|
def __repr__(self) -> str:
|
|
@@ -122,7 +128,7 @@ class LGHorizonStatusMessage(LGHorizonMessage):
|
|
|
122
128
|
|
|
123
129
|
|
|
124
130
|
class LGHorizonSourceType(Enum):
|
|
125
|
-
"""Enumeration of LG Horizon
|
|
131
|
+
"""Enumeration of LG Horizon source types."""
|
|
126
132
|
|
|
127
133
|
LINEAR = "linear"
|
|
128
134
|
REVIEWBUFFER = "reviewBuffer"
|
|
@@ -141,7 +147,7 @@ class LGHorizonSource(ABC):
|
|
|
141
147
|
|
|
142
148
|
@property
|
|
143
149
|
@abstractmethod
|
|
144
|
-
def source_type(self) -> LGHorizonSourceType:
|
|
150
|
+
def source_type(self) -> LGHorizonSourceType: # type: ignore[no-redef]
|
|
145
151
|
"""Return the message type."""
|
|
146
152
|
|
|
147
153
|
|
|
@@ -182,7 +188,7 @@ class LGHorizonReviewBufferSource(LGHorizonSource):
|
|
|
182
188
|
|
|
183
189
|
|
|
184
190
|
class LGHorizonNDVRSource(LGHorizonSource):
|
|
185
|
-
"""Represent the
|
|
191
|
+
"""Represent the Network Digital Video Recorder (NDVR) Source of an LG Horizon device."""
|
|
186
192
|
|
|
187
193
|
@property
|
|
188
194
|
def recording_id(self) -> str:
|
|
@@ -223,7 +229,7 @@ class LGHorizonVODSource(LGHorizonSource):
|
|
|
223
229
|
|
|
224
230
|
|
|
225
231
|
class LGHorizonReplaySource(LGHorizonSource):
|
|
226
|
-
"""Represent the
|
|
232
|
+
"""Represent the Replay Source of an LG Horizon device."""
|
|
227
233
|
|
|
228
234
|
@property
|
|
229
235
|
def event_id(self) -> str:
|
|
@@ -237,7 +243,7 @@ class LGHorizonReplaySource(LGHorizonSource):
|
|
|
237
243
|
|
|
238
244
|
|
|
239
245
|
class LGHorizonUnknownSource(LGHorizonSource):
|
|
240
|
-
"""Represent
|
|
246
|
+
"""Represent an unknown source type of an LG Horizon device."""
|
|
241
247
|
|
|
242
248
|
@property
|
|
243
249
|
def source_type(self) -> LGHorizonSourceType:
|
|
@@ -268,6 +274,13 @@ class LGHorizonPlayerState:
|
|
|
268
274
|
"""Return the last speed change time."""
|
|
269
275
|
return self._raw_json.get("lastSpeedChangeTime", 0.0)
|
|
270
276
|
|
|
277
|
+
@property
|
|
278
|
+
def relative_position(
|
|
279
|
+
self,
|
|
280
|
+
) -> int:
|
|
281
|
+
"""Return the last speed change time."""
|
|
282
|
+
return self._raw_json.get("relativePosition", 0.0)
|
|
283
|
+
|
|
271
284
|
@property
|
|
272
285
|
def source(self) -> LGHorizonSource | None: # Added None to the return type
|
|
273
286
|
"""Return the last speed change time."""
|
|
@@ -288,7 +301,7 @@ class LGHorizonPlayerState:
|
|
|
288
301
|
|
|
289
302
|
|
|
290
303
|
class LGHorizonAppsState:
|
|
291
|
-
"""Represent the State of an LG Horizon device."""
|
|
304
|
+
"""Represent the Apps State of an LG Horizon device."""
|
|
292
305
|
|
|
293
306
|
def __init__(self, raw_json: dict) -> None:
|
|
294
307
|
"""Initialize the Apps state."""
|
|
@@ -311,7 +324,7 @@ class LGHorizonAppsState:
|
|
|
311
324
|
|
|
312
325
|
|
|
313
326
|
class LGHorizonUIState:
|
|
314
|
-
"""Represent the State of an LG Horizon device."""
|
|
327
|
+
"""Represent the UI State of an LG Horizon device."""
|
|
315
328
|
|
|
316
329
|
_player_state: LGHorizonPlayerState | None = None
|
|
317
330
|
_apps_state: LGHorizonAppsState | None = None
|
|
@@ -319,6 +332,11 @@ class LGHorizonUIState:
|
|
|
319
332
|
def __init__(self, raw_json: dict) -> None:
|
|
320
333
|
"""Initialize the State."""
|
|
321
334
|
self._raw_json = raw_json
|
|
335
|
+
"""Initialize the UI State.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
raw_json: The raw JSON dictionary containing UI state information.
|
|
339
|
+
"""
|
|
322
340
|
|
|
323
341
|
@property
|
|
324
342
|
def ui_status(self) -> LGHorizonUIStateType:
|
|
@@ -453,6 +471,7 @@ class LGHorizonAuth:
|
|
|
453
471
|
_country_code: str
|
|
454
472
|
_host: str
|
|
455
473
|
_use_refresh_token: bool
|
|
474
|
+
_token_refresh_callback: Callable[str, None] | None # pyright: ignore[reportInvalidTypeForm]
|
|
456
475
|
|
|
457
476
|
def __init__(
|
|
458
477
|
self,
|
|
@@ -474,6 +493,7 @@ class LGHorizonAuth:
|
|
|
474
493
|
self._host = COUNTRY_SETTINGS[country_code]["api_url"]
|
|
475
494
|
self._use_refresh_token = COUNTRY_SETTINGS[country_code]["use_refreshtoken"]
|
|
476
495
|
self._service_config = None
|
|
496
|
+
self._token_refresh_callback = None
|
|
477
497
|
|
|
478
498
|
@property
|
|
479
499
|
def websession(self) -> ClientSession:
|
|
@@ -589,6 +609,8 @@ class LGHorizonAuth:
|
|
|
589
609
|
self.household_id = auth_json["householdId"]
|
|
590
610
|
self.access_token = auth_json["accessToken"]
|
|
591
611
|
self.refresh_token = auth_json["refreshToken"]
|
|
612
|
+
if self._token_refresh_callback:
|
|
613
|
+
self._token_refresh_callback(self.refresh_token)
|
|
592
614
|
self.username = auth_json["username"]
|
|
593
615
|
self.token_expiry = auth_json["refreshTokenExpiry"]
|
|
594
616
|
|
|
@@ -669,6 +691,16 @@ class LGHorizonChannel:
|
|
|
669
691
|
"""Returns the channel number."""
|
|
670
692
|
return self.channel_json["logicalChannelNumber"]
|
|
671
693
|
|
|
694
|
+
@property
|
|
695
|
+
def replay_pre_padding(self) -> int:
|
|
696
|
+
"""Returns the channel number."""
|
|
697
|
+
return self.channel_json.get("replayPrePadding", 0)
|
|
698
|
+
|
|
699
|
+
@property
|
|
700
|
+
def replay_post_padding(self) -> int:
|
|
701
|
+
"""Returns the channel number."""
|
|
702
|
+
return self.channel_json.get("replayPostPadding", 0)
|
|
703
|
+
|
|
672
704
|
@property
|
|
673
705
|
def is_radio(self) -> bool:
|
|
674
706
|
"""Returns if the channel is a radio channel."""
|
|
@@ -820,33 +852,44 @@ class LGHorizonCustomer:
|
|
|
820
852
|
class LGHorizonDeviceState:
|
|
821
853
|
"""Represent current state of a box."""
|
|
822
854
|
|
|
855
|
+
_id: Optional[str]
|
|
823
856
|
_channel_id: Optional[str]
|
|
824
857
|
_channel_name: Optional[str]
|
|
825
|
-
|
|
858
|
+
_show_title: Optional[str]
|
|
859
|
+
_episode_title: Optional[str]
|
|
860
|
+
_season_number: Optional[int]
|
|
861
|
+
_episode_number: Optional[int]
|
|
826
862
|
_image: Optional[str]
|
|
827
863
|
_source_type: LGHorizonSourceType
|
|
828
864
|
_paused: bool
|
|
829
|
-
_sub_title: Optional[str]
|
|
830
865
|
_duration: Optional[float]
|
|
831
866
|
_position: Optional[float]
|
|
832
867
|
_last_position_update: Optional[datetime]
|
|
833
868
|
_state: LGHorizonRunningState
|
|
834
869
|
_speed: Optional[int]
|
|
870
|
+
_start_time: Optional[int]
|
|
871
|
+
_end_time: Optional[int]
|
|
835
872
|
|
|
836
873
|
def __init__(self) -> None:
|
|
837
874
|
"""Initialize the playing info."""
|
|
838
875
|
self._channel_id = None
|
|
839
|
-
self.
|
|
876
|
+
self._show_title = None
|
|
877
|
+
self._episode_title = None
|
|
878
|
+
self._season_number = None
|
|
879
|
+
self._episode_number = None
|
|
840
880
|
self._image = None
|
|
841
881
|
self._source_type = LGHorizonSourceType.UNKNOWN
|
|
882
|
+
self._ui_state_type = LGHorizonUIStateType.UNKNOWN
|
|
842
883
|
self._paused = False
|
|
843
|
-
self.sub_title = None
|
|
844
884
|
self._duration = None
|
|
845
885
|
self._position = None
|
|
846
886
|
self._last_position_update = None
|
|
847
887
|
self._state = LGHorizonRunningState.UNKNOWN
|
|
848
888
|
self._speed = None
|
|
849
889
|
self._channel_name = None
|
|
890
|
+
self._id = None
|
|
891
|
+
self._start_time = None
|
|
892
|
+
self._end_time = None
|
|
850
893
|
|
|
851
894
|
@property
|
|
852
895
|
def state(self) -> LGHorizonRunningState:
|
|
@@ -868,6 +911,16 @@ class LGHorizonDeviceState:
|
|
|
868
911
|
"""Set the channel ID."""
|
|
869
912
|
self._channel_id = value
|
|
870
913
|
|
|
914
|
+
@property
|
|
915
|
+
def id(self) -> Optional[str]:
|
|
916
|
+
"""Return the channel ID."""
|
|
917
|
+
return self._id
|
|
918
|
+
|
|
919
|
+
@id.setter
|
|
920
|
+
def id(self, value: Optional[str]) -> None:
|
|
921
|
+
"""Set the channel ID."""
|
|
922
|
+
self._id = value
|
|
923
|
+
|
|
871
924
|
@property
|
|
872
925
|
def channel_name(self) -> Optional[str]:
|
|
873
926
|
"""Return the channel ID."""
|
|
@@ -879,14 +932,74 @@ class LGHorizonDeviceState:
|
|
|
879
932
|
self._channel_name = value
|
|
880
933
|
|
|
881
934
|
@property
|
|
882
|
-
def
|
|
935
|
+
def show_title(self) -> Optional[str]:
|
|
936
|
+
"""Return the title."""
|
|
937
|
+
return self._show_title
|
|
938
|
+
|
|
939
|
+
@show_title.setter
|
|
940
|
+
def show_title(self, value: Optional[str]) -> None:
|
|
941
|
+
"""Set the title."""
|
|
942
|
+
self._show_title = value
|
|
943
|
+
|
|
944
|
+
@property
|
|
945
|
+
def app_name(self) -> Optional[str]:
|
|
946
|
+
"""Return the title."""
|
|
947
|
+
return self._app_name
|
|
948
|
+
|
|
949
|
+
@app_name.setter
|
|
950
|
+
def app_name(self, value: Optional[str]) -> None:
|
|
951
|
+
"""Set the title."""
|
|
952
|
+
self._app_name = value
|
|
953
|
+
|
|
954
|
+
@property
|
|
955
|
+
def episode_title(self) -> Optional[str]:
|
|
956
|
+
"""Return the title."""
|
|
957
|
+
return self._episode_title
|
|
958
|
+
|
|
959
|
+
@episode_title.setter
|
|
960
|
+
def episode_title(self, value: Optional[str]) -> None:
|
|
961
|
+
"""Set the title."""
|
|
962
|
+
self._episode_title = value
|
|
963
|
+
|
|
964
|
+
@property
|
|
965
|
+
def episode_number(self) -> Optional[int]:
|
|
966
|
+
"""Return the title."""
|
|
967
|
+
return self._episode_number
|
|
968
|
+
|
|
969
|
+
@episode_number.setter
|
|
970
|
+
def episode_number(self, value: Optional[int]) -> None:
|
|
971
|
+
"""Set the title."""
|
|
972
|
+
self._episode_number = value
|
|
973
|
+
|
|
974
|
+
@property
|
|
975
|
+
def season_number(self) -> Optional[int]:
|
|
976
|
+
"""Return the title."""
|
|
977
|
+
return self._season_number
|
|
978
|
+
|
|
979
|
+
@season_number.setter
|
|
980
|
+
def season_number(self, value: Optional[int]) -> None:
|
|
981
|
+
"""Set the title."""
|
|
982
|
+
self._season_number = value
|
|
983
|
+
|
|
984
|
+
@property
|
|
985
|
+
def start_time(self) -> Optional[int]:
|
|
883
986
|
"""Return the title."""
|
|
884
|
-
return self.
|
|
987
|
+
return self._start_time
|
|
885
988
|
|
|
886
|
-
@
|
|
887
|
-
def
|
|
989
|
+
@start_time.setter
|
|
990
|
+
def start_time(self, value: Optional[int]) -> None:
|
|
888
991
|
"""Set the title."""
|
|
889
|
-
self.
|
|
992
|
+
self._start_time = value
|
|
993
|
+
|
|
994
|
+
@property
|
|
995
|
+
def end_time(self) -> Optional[int]:
|
|
996
|
+
"""Return the title."""
|
|
997
|
+
return self._end_time
|
|
998
|
+
|
|
999
|
+
@end_time.setter
|
|
1000
|
+
def end_time(self, value: Optional[int]) -> None:
|
|
1001
|
+
"""Set the title."""
|
|
1002
|
+
self._end_time = value
|
|
890
1003
|
|
|
891
1004
|
@property
|
|
892
1005
|
def image(self) -> Optional[str]:
|
|
@@ -908,6 +1021,16 @@ class LGHorizonDeviceState:
|
|
|
908
1021
|
"""Set the source type."""
|
|
909
1022
|
self._source_type = value
|
|
910
1023
|
|
|
1024
|
+
@property
|
|
1025
|
+
def ui_state_type(self) -> LGHorizonUIStateType:
|
|
1026
|
+
"""Return the source type."""
|
|
1027
|
+
return self._ui_state_type
|
|
1028
|
+
|
|
1029
|
+
@ui_state_type.setter
|
|
1030
|
+
def ui_state_type(self, value: LGHorizonUIStateType) -> None:
|
|
1031
|
+
"""Set the source type."""
|
|
1032
|
+
self._ui_state_type = value
|
|
1033
|
+
|
|
911
1034
|
@property
|
|
912
1035
|
def paused(self) -> bool:
|
|
913
1036
|
"""Return if the media is paused."""
|
|
@@ -915,16 +1038,6 @@ class LGHorizonDeviceState:
|
|
|
915
1038
|
return False
|
|
916
1039
|
return self.speed == 0
|
|
917
1040
|
|
|
918
|
-
@property
|
|
919
|
-
def sub_title(self) -> Optional[str]:
|
|
920
|
-
"""Return the channel title."""
|
|
921
|
-
return self._sub_title
|
|
922
|
-
|
|
923
|
-
@sub_title.setter
|
|
924
|
-
def sub_title(self, value: Optional[str]) -> None:
|
|
925
|
-
"""Set the channel title."""
|
|
926
|
-
self._sub_title = value
|
|
927
|
-
|
|
928
1041
|
@property
|
|
929
1042
|
def duration(self) -> Optional[float]:
|
|
930
1043
|
"""Return the duration of the media."""
|
|
@@ -946,12 +1059,12 @@ class LGHorizonDeviceState:
|
|
|
946
1059
|
self._position = value
|
|
947
1060
|
|
|
948
1061
|
@property
|
|
949
|
-
def last_position_update(self) -> Optional[
|
|
1062
|
+
def last_position_update(self) -> Optional[int]:
|
|
950
1063
|
"""Return the last time the position was updated."""
|
|
951
1064
|
return self._last_position_update
|
|
952
1065
|
|
|
953
1066
|
@last_position_update.setter
|
|
954
|
-
def last_position_update(self, value: Optional[
|
|
1067
|
+
def last_position_update(self, value: Optional[int]) -> None:
|
|
955
1068
|
"""Set the last position update time."""
|
|
956
1069
|
self._last_position_update = value
|
|
957
1070
|
|
|
@@ -974,12 +1087,18 @@ class LGHorizonDeviceState:
|
|
|
974
1087
|
async def reset(self) -> None:
|
|
975
1088
|
"""Reset all playing information."""
|
|
976
1089
|
self.channel_id = None
|
|
977
|
-
self.
|
|
978
|
-
self.
|
|
1090
|
+
self.episode_number = None
|
|
1091
|
+
self.season_number = None
|
|
1092
|
+
self.episode_title = None
|
|
1093
|
+
self.show_title = None
|
|
1094
|
+
self.app_name = None
|
|
979
1095
|
self.image = None
|
|
980
1096
|
self.source_type = LGHorizonSourceType.UNKNOWN
|
|
981
1097
|
self.speed = None
|
|
982
1098
|
self.channel_name = None
|
|
1099
|
+
self.id = None
|
|
1100
|
+
self.start_time = None
|
|
1101
|
+
self.end_time = None
|
|
983
1102
|
await self.reset_progress()
|
|
984
1103
|
|
|
985
1104
|
|
|
@@ -1028,6 +1147,16 @@ class LGHorizonReplayEvent:
|
|
|
1028
1147
|
"""Return the season number."""
|
|
1029
1148
|
return self._raw_json.get("seasonNumber")
|
|
1030
1149
|
|
|
1150
|
+
@property
|
|
1151
|
+
def start_time(self) -> Optional[int]:
|
|
1152
|
+
"""Return the season number."""
|
|
1153
|
+
return self._raw_json.get("startTime", None)
|
|
1154
|
+
|
|
1155
|
+
@property
|
|
1156
|
+
def end_time(self) -> Optional[int]:
|
|
1157
|
+
"""Return the season number."""
|
|
1158
|
+
return self._raw_json.get("endTime", None)
|
|
1159
|
+
|
|
1031
1160
|
@property
|
|
1032
1161
|
def title(self) -> str:
|
|
1033
1162
|
"""Return the title of the event."""
|
|
@@ -1049,10 +1178,6 @@ class LGHorizonReplayEvent:
|
|
|
1049
1178
|
full_title += f": {self.episode_name}"
|
|
1050
1179
|
return full_title
|
|
1051
1180
|
|
|
1052
|
-
def __repr__(self) -> str:
|
|
1053
|
-
"""Return a string representation of the replay event."""
|
|
1054
|
-
return f"LGHorizonReplayEvent(title='{self.title}', channel_id='{self.channel_id}', event_id='{self.event_id}')"
|
|
1055
|
-
|
|
1056
1181
|
|
|
1057
1182
|
class LGHorizonVODType(Enum):
|
|
1058
1183
|
"""Enumeration of LG Horizon VOD types."""
|
|
@@ -1066,6 +1191,11 @@ class LGHorizonVOD:
|
|
|
1066
1191
|
"""LGHorizon video on demand."""
|
|
1067
1192
|
|
|
1068
1193
|
def __init__(self, vod_json) -> None:
|
|
1194
|
+
"""Initialize an LG Horizon VOD object.
|
|
1195
|
+
|
|
1196
|
+
Args:
|
|
1197
|
+
vod_json: The raw JSON dictionary containing VOD information.
|
|
1198
|
+
"""
|
|
1069
1199
|
self._vod_json = vod_json
|
|
1070
1200
|
|
|
1071
1201
|
@property
|
|
@@ -1079,26 +1209,14 @@ class LGHorizonVOD:
|
|
|
1079
1209
|
return self._vod_json["id"]
|
|
1080
1210
|
|
|
1081
1211
|
@property
|
|
1082
|
-
def
|
|
1212
|
+
def season(self) -> Optional[int]:
|
|
1083
1213
|
"""Return the season number of the recording."""
|
|
1084
|
-
return self._vod_json.get("
|
|
1214
|
+
return self._vod_json.get("season", None)
|
|
1085
1215
|
|
|
1086
1216
|
@property
|
|
1087
|
-
def
|
|
1217
|
+
def episode(self) -> Optional[int]:
|
|
1088
1218
|
"""Return the episode number of the recording."""
|
|
1089
|
-
return self._vod_json.get("
|
|
1090
|
-
|
|
1091
|
-
@property
|
|
1092
|
-
def full_episode_title(self) -> Optional[str]:
|
|
1093
|
-
"""Return the ID of the VOD."""
|
|
1094
|
-
if self.vod_type != LGHorizonVODType.EPISODE:
|
|
1095
|
-
return None
|
|
1096
|
-
if not self.season_number and not self.episode_number:
|
|
1097
|
-
return None
|
|
1098
|
-
full_title = f"""S{self.season_number:02d}E{self.episode_number:02d}"""
|
|
1099
|
-
if self.title:
|
|
1100
|
-
full_title += f": {self.title}"
|
|
1101
|
-
return full_title
|
|
1219
|
+
return self._vod_json.get("episode", None)
|
|
1102
1220
|
|
|
1103
1221
|
@property
|
|
1104
1222
|
def title(self) -> str:
|
|
@@ -1117,7 +1235,7 @@ class LGHorizonVOD:
|
|
|
1117
1235
|
|
|
1118
1236
|
|
|
1119
1237
|
class LGHOrizonRelevantEpisode:
|
|
1120
|
-
"""
|
|
1238
|
+
"""Represents a relevant episode within a recording season or show."""
|
|
1121
1239
|
|
|
1122
1240
|
def __init__(self, episode_json: dict) -> None:
|
|
1123
1241
|
"""Abstract base class for LG Horizon recordings."""
|
|
@@ -1178,7 +1296,7 @@ class LGHorizonRecording(ABC):
|
|
|
1178
1296
|
@property
|
|
1179
1297
|
def title(self) -> str:
|
|
1180
1298
|
"""Return the title of the recording."""
|
|
1181
|
-
return self._recording_payload
|
|
1299
|
+
return self._recording_payload.get("title", "unknown")
|
|
1182
1300
|
|
|
1183
1301
|
@property
|
|
1184
1302
|
def channel_id(self) -> str:
|
|
@@ -1194,7 +1312,10 @@ class LGHorizonRecording(ABC):
|
|
|
1194
1312
|
return None
|
|
1195
1313
|
|
|
1196
1314
|
def __init__(self, recording_payload: dict) -> None:
|
|
1197
|
-
"""Abstract base class for LG Horizon recordings.
|
|
1315
|
+
"""Abstract base class for LG Horizon recordings.
|
|
1316
|
+
Args:
|
|
1317
|
+
recording_payload: The raw JSON dictionary containing recording information.
|
|
1318
|
+
"""
|
|
1198
1319
|
self._recording_payload = recording_payload
|
|
1199
1320
|
|
|
1200
1321
|
|
|
@@ -1206,6 +1327,11 @@ class LGHorizonRecordingSingle(LGHorizonRecording):
|
|
|
1206
1327
|
"""Return the episode title of the recording."""
|
|
1207
1328
|
return self._recording_payload.get("episodeTitle", None)
|
|
1208
1329
|
|
|
1330
|
+
@property
|
|
1331
|
+
def episode_id(self) -> Optional[str]:
|
|
1332
|
+
"""Return the episode title of the recording."""
|
|
1333
|
+
return self._recording_payload.get("episodeId", None)
|
|
1334
|
+
|
|
1209
1335
|
@property
|
|
1210
1336
|
def season_number(self) -> Optional[int]:
|
|
1211
1337
|
"""Return the season number of the recording."""
|
|
@@ -1221,29 +1347,39 @@ class LGHorizonRecordingSingle(LGHorizonRecording):
|
|
|
1221
1347
|
"""Return the show ID of the recording."""
|
|
1222
1348
|
return self._recording_payload.get("showId", None)
|
|
1223
1349
|
|
|
1350
|
+
@property
|
|
1351
|
+
def show_title(self) -> Optional[str]:
|
|
1352
|
+
"""Return the show ID of the recording."""
|
|
1353
|
+
return self._recording_payload.get("showTitle", None)
|
|
1354
|
+
|
|
1224
1355
|
@property
|
|
1225
1356
|
def season_id(self) -> Optional[str]:
|
|
1226
1357
|
"""Return the season ID of the recording."""
|
|
1227
1358
|
return self._recording_payload.get("seasonId", None)
|
|
1228
1359
|
|
|
1229
|
-
@property
|
|
1230
|
-
def full_episode_title(self) -> Optional[str]:
|
|
1231
|
-
"""Return the full episode title of the recording."""
|
|
1232
|
-
if not self.season_number and not self.episode_number:
|
|
1233
|
-
return None
|
|
1234
|
-
full_title = f"""S{self.season_number:02d}E{self.episode_number:02d}"""
|
|
1235
|
-
if self.episode_title:
|
|
1236
|
-
full_title += f": {self.episode_title}"
|
|
1237
|
-
return full_title
|
|
1238
|
-
|
|
1239
1360
|
@property
|
|
1240
1361
|
def channel_id(self) -> Optional[str]:
|
|
1241
1362
|
"""Return the channel ID of the recording."""
|
|
1242
1363
|
return self._recording_payload.get("channelId", None)
|
|
1243
1364
|
|
|
1365
|
+
@property
|
|
1366
|
+
def duration(self) -> Optional[int]:
|
|
1367
|
+
"""Return the title."""
|
|
1368
|
+
return self.recording_payload.get("duration", None)
|
|
1369
|
+
|
|
1370
|
+
@property
|
|
1371
|
+
def start_time(self) -> Optional[int]:
|
|
1372
|
+
"""Return the title."""
|
|
1373
|
+
return self.recording_payload.get("startTime", None)
|
|
1374
|
+
|
|
1375
|
+
@property
|
|
1376
|
+
def end_time(self) -> Optional[int]:
|
|
1377
|
+
"""Return the title."""
|
|
1378
|
+
return self.recording_payload.get("endTime", None)
|
|
1379
|
+
|
|
1244
1380
|
|
|
1245
1381
|
class LGHorizonRecordingSeason(LGHorizonRecording):
|
|
1246
|
-
"""
|
|
1382
|
+
"""Represents an LG Horizon recording season."""
|
|
1247
1383
|
|
|
1248
1384
|
_most_relevant_epsode: Optional[LGHOrizonRelevantEpisode]
|
|
1249
1385
|
|
|
@@ -1264,6 +1400,11 @@ class LGHorizonRecordingSeason(LGHorizonRecording):
|
|
|
1264
1400
|
"""Return the season title of the recording."""
|
|
1265
1401
|
return self._recording_payload.get("seasonTitle", "")
|
|
1266
1402
|
|
|
1403
|
+
@property
|
|
1404
|
+
def show_id(self) -> str:
|
|
1405
|
+
"""Return the season title of the recording."""
|
|
1406
|
+
return self._recording_payload.get("showId", "")
|
|
1407
|
+
|
|
1267
1408
|
@property
|
|
1268
1409
|
def most_relevant_episode(self) -> Optional[LGHOrizonRelevantEpisode]:
|
|
1269
1410
|
"""Return the most relevant episode of the season."""
|
|
@@ -1271,7 +1412,7 @@ class LGHorizonRecordingSeason(LGHorizonRecording):
|
|
|
1271
1412
|
|
|
1272
1413
|
|
|
1273
1414
|
class LGHorizonRecordingShow(LGHorizonRecording):
|
|
1274
|
-
"""
|
|
1415
|
+
"""Represents an LG Horizon recording show."""
|
|
1275
1416
|
|
|
1276
1417
|
_most_relevant_epsode: Optional[LGHOrizonRelevantEpisode]
|
|
1277
1418
|
|
|
@@ -1294,7 +1435,7 @@ class LGHorizonRecordingShow(LGHorizonRecording):
|
|
|
1294
1435
|
|
|
1295
1436
|
|
|
1296
1437
|
class LGHorizonRecordingList:
|
|
1297
|
-
"""
|
|
1438
|
+
"""Represents a list of LG Horizon recordings."""
|
|
1298
1439
|
|
|
1299
1440
|
@property
|
|
1300
1441
|
def total(self) -> int:
|
|
@@ -1302,9 +1443,49 @@ class LGHorizonRecordingList:
|
|
|
1302
1443
|
return len(self._recordings)
|
|
1303
1444
|
|
|
1304
1445
|
def __init__(self, recordings: List[LGHorizonRecording]) -> None:
|
|
1305
|
-
"""
|
|
1446
|
+
"""Initialize an LG Horizon recording list.
|
|
1447
|
+
|
|
1448
|
+
Args:
|
|
1449
|
+
recordings: A list of LGHorizonRecording objects.
|
|
1450
|
+
"""
|
|
1306
1451
|
self._recordings = recordings
|
|
1307
1452
|
|
|
1453
|
+
@property
|
|
1454
|
+
def recordings(self) -> List[LGHorizonRecording]:
|
|
1455
|
+
"""Return the total number of recordings."""
|
|
1456
|
+
return self._recordings
|
|
1457
|
+
|
|
1458
|
+
|
|
1459
|
+
class LGHorizonShowRecordingList(LGHorizonRecordingList):
|
|
1460
|
+
"""LGHorizon recording."""
|
|
1461
|
+
|
|
1462
|
+
def __init__(
|
|
1463
|
+
self,
|
|
1464
|
+
show_title: Optional[str],
|
|
1465
|
+
show_image,
|
|
1466
|
+
recordings: List[LGHorizonRecording],
|
|
1467
|
+
) -> None:
|
|
1468
|
+
"""Initialize an LG Horizon show recording list.
|
|
1469
|
+
|
|
1470
|
+
Args:
|
|
1471
|
+
show_title: The title of the show.
|
|
1472
|
+
show_image: The image URL for the show.
|
|
1473
|
+
recordings: A list of LGHorizonRecording objects belonging to the show.
|
|
1474
|
+
"""
|
|
1475
|
+
super().__init__(recordings)
|
|
1476
|
+
self._show_title = show_title
|
|
1477
|
+
self._show_image = show_image
|
|
1478
|
+
|
|
1479
|
+
@property
|
|
1480
|
+
def show_title(self) -> str:
|
|
1481
|
+
"""Title of the show."""
|
|
1482
|
+
return self._show_title
|
|
1483
|
+
|
|
1484
|
+
@property
|
|
1485
|
+
def show_image(self) -> Optional[str]:
|
|
1486
|
+
"""Image of the show."""
|
|
1487
|
+
return self._show_image
|
|
1488
|
+
|
|
1308
1489
|
|
|
1309
1490
|
class LGHorizonRecordingQuota:
|
|
1310
1491
|
"""LGHorizon recording quota."""
|