lghorizon 0.9.0__py3-none-any.whl → 0.9.0b0__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.
@@ -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, Callable
11
+ from typing import Any, Dict, List, Optional
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): # type: ignore[no-redef]
55
+ class LGHorizonRecordingType(Enum):
56
56
  """Enumeration of LG Horizon recording states."""
57
57
 
58
58
  SINGLE = "single"
@@ -91,12 +91,6 @@ 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
- """
100
94
  self._payload = payload
101
95
 
102
96
  def __repr__(self) -> str:
@@ -128,7 +122,7 @@ class LGHorizonStatusMessage(LGHorizonMessage):
128
122
 
129
123
 
130
124
  class LGHorizonSourceType(Enum):
131
- """Enumeration of LG Horizon source types."""
125
+ """Enumeration of LG Horizon message types."""
132
126
 
133
127
  LINEAR = "linear"
134
128
  REVIEWBUFFER = "reviewBuffer"
@@ -147,7 +141,7 @@ class LGHorizonSource(ABC):
147
141
 
148
142
  @property
149
143
  @abstractmethod
150
- def source_type(self) -> LGHorizonSourceType: # type: ignore[no-redef]
144
+ def source_type(self) -> LGHorizonSourceType:
151
145
  """Return the message type."""
152
146
 
153
147
 
@@ -188,7 +182,7 @@ class LGHorizonReviewBufferSource(LGHorizonSource):
188
182
 
189
183
 
190
184
  class LGHorizonNDVRSource(LGHorizonSource):
191
- """Represent the Network Digital Video Recorder (NDVR) Source of an LG Horizon device."""
185
+ """Represent the ReviewBuffer Source of an LG Horizon device."""
192
186
 
193
187
  @property
194
188
  def recording_id(self) -> str:
@@ -229,7 +223,7 @@ class LGHorizonVODSource(LGHorizonSource):
229
223
 
230
224
 
231
225
  class LGHorizonReplaySource(LGHorizonSource):
232
- """Represent the Replay Source of an LG Horizon device."""
226
+ """Represent the VOD Source of an LG Horizon device."""
233
227
 
234
228
  @property
235
229
  def event_id(self) -> str:
@@ -243,7 +237,7 @@ class LGHorizonReplaySource(LGHorizonSource):
243
237
 
244
238
 
245
239
  class LGHorizonUnknownSource(LGHorizonSource):
246
- """Represent an unknown source type of an LG Horizon device."""
240
+ """Represent the Linear Source of an LG Horizon device."""
247
241
 
248
242
  @property
249
243
  def source_type(self) -> LGHorizonSourceType:
@@ -274,13 +268,6 @@ class LGHorizonPlayerState:
274
268
  """Return the last speed change time."""
275
269
  return self._raw_json.get("lastSpeedChangeTime", 0.0)
276
270
 
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
-
284
271
  @property
285
272
  def source(self) -> LGHorizonSource | None: # Added None to the return type
286
273
  """Return the last speed change time."""
@@ -301,7 +288,7 @@ class LGHorizonPlayerState:
301
288
 
302
289
 
303
290
  class LGHorizonAppsState:
304
- """Represent the Apps State of an LG Horizon device."""
291
+ """Represent the State of an LG Horizon device."""
305
292
 
306
293
  def __init__(self, raw_json: dict) -> None:
307
294
  """Initialize the Apps state."""
@@ -324,7 +311,7 @@ class LGHorizonAppsState:
324
311
 
325
312
 
326
313
  class LGHorizonUIState:
327
- """Represent the UI State of an LG Horizon device."""
314
+ """Represent the State of an LG Horizon device."""
328
315
 
329
316
  _player_state: LGHorizonPlayerState | None = None
330
317
  _apps_state: LGHorizonAppsState | None = None
@@ -332,11 +319,6 @@ class LGHorizonUIState:
332
319
  def __init__(self, raw_json: dict) -> None:
333
320
  """Initialize the State."""
334
321
  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
- """
340
322
 
341
323
  @property
342
324
  def ui_status(self) -> LGHorizonUIStateType:
@@ -471,7 +453,6 @@ class LGHorizonAuth:
471
453
  _country_code: str
472
454
  _host: str
473
455
  _use_refresh_token: bool
474
- _token_refresh_callback: Callable[str, None] | None # pyright: ignore[reportInvalidTypeForm]
475
456
 
476
457
  def __init__(
477
458
  self,
@@ -493,7 +474,6 @@ class LGHorizonAuth:
493
474
  self._host = COUNTRY_SETTINGS[country_code]["api_url"]
494
475
  self._use_refresh_token = COUNTRY_SETTINGS[country_code]["use_refreshtoken"]
495
476
  self._service_config = None
496
- self._token_refresh_callback = None
497
477
 
498
478
  @property
499
479
  def websession(self) -> ClientSession:
@@ -609,8 +589,6 @@ class LGHorizonAuth:
609
589
  self.household_id = auth_json["householdId"]
610
590
  self.access_token = auth_json["accessToken"]
611
591
  self.refresh_token = auth_json["refreshToken"]
612
- if self._token_refresh_callback:
613
- self._token_refresh_callback(self.refresh_token)
614
592
  self.username = auth_json["username"]
615
593
  self.token_expiry = auth_json["refreshTokenExpiry"]
616
594
 
@@ -691,16 +669,6 @@ class LGHorizonChannel:
691
669
  """Returns the channel number."""
692
670
  return self.channel_json["logicalChannelNumber"]
693
671
 
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
-
704
672
  @property
705
673
  def is_radio(self) -> bool:
706
674
  """Returns if the channel is a radio channel."""
@@ -852,44 +820,33 @@ class LGHorizonCustomer:
852
820
  class LGHorizonDeviceState:
853
821
  """Represent current state of a box."""
854
822
 
855
- _id: Optional[str]
856
823
  _channel_id: Optional[str]
857
824
  _channel_name: Optional[str]
858
- _show_title: Optional[str]
859
- _episode_title: Optional[str]
860
- _season_number: Optional[int]
861
- _episode_number: Optional[int]
825
+ _title: Optional[str]
862
826
  _image: Optional[str]
863
827
  _source_type: LGHorizonSourceType
864
828
  _paused: bool
829
+ _sub_title: Optional[str]
865
830
  _duration: Optional[float]
866
831
  _position: Optional[float]
867
832
  _last_position_update: Optional[datetime]
868
833
  _state: LGHorizonRunningState
869
834
  _speed: Optional[int]
870
- _start_time: Optional[int]
871
- _end_time: Optional[int]
872
835
 
873
836
  def __init__(self) -> None:
874
837
  """Initialize the playing info."""
875
838
  self._channel_id = None
876
- self._show_title = None
877
- self._episode_title = None
878
- self._season_number = None
879
- self._episode_number = None
839
+ self._title = None
880
840
  self._image = None
881
841
  self._source_type = LGHorizonSourceType.UNKNOWN
882
- self._ui_state_type = LGHorizonUIStateType.UNKNOWN
883
842
  self._paused = False
843
+ self.sub_title = None
884
844
  self._duration = None
885
845
  self._position = None
886
846
  self._last_position_update = None
887
847
  self._state = LGHorizonRunningState.UNKNOWN
888
848
  self._speed = None
889
849
  self._channel_name = None
890
- self._id = None
891
- self._start_time = None
892
- self._end_time = None
893
850
 
894
851
  @property
895
852
  def state(self) -> LGHorizonRunningState:
@@ -911,16 +868,6 @@ class LGHorizonDeviceState:
911
868
  """Set the channel ID."""
912
869
  self._channel_id = value
913
870
 
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
-
924
871
  @property
925
872
  def channel_name(self) -> Optional[str]:
926
873
  """Return the channel ID."""
@@ -932,74 +879,14 @@ class LGHorizonDeviceState:
932
879
  self._channel_name = value
933
880
 
934
881
  @property
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]:
882
+ def title(self) -> Optional[str]:
986
883
  """Return the title."""
987
- return self._start_time
884
+ return self._title
988
885
 
989
- @start_time.setter
990
- def start_time(self, value: Optional[int]) -> None:
886
+ @title.setter
887
+ def title(self, value: Optional[str]) -> None:
991
888
  """Set the title."""
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
889
+ self._title = value
1003
890
 
1004
891
  @property
1005
892
  def image(self) -> Optional[str]:
@@ -1021,16 +908,6 @@ class LGHorizonDeviceState:
1021
908
  """Set the source type."""
1022
909
  self._source_type = value
1023
910
 
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
-
1034
911
  @property
1035
912
  def paused(self) -> bool:
1036
913
  """Return if the media is paused."""
@@ -1038,6 +915,16 @@ class LGHorizonDeviceState:
1038
915
  return False
1039
916
  return self.speed == 0
1040
917
 
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
+
1041
928
  @property
1042
929
  def duration(self) -> Optional[float]:
1043
930
  """Return the duration of the media."""
@@ -1059,12 +946,12 @@ class LGHorizonDeviceState:
1059
946
  self._position = value
1060
947
 
1061
948
  @property
1062
- def last_position_update(self) -> Optional[int]:
949
+ def last_position_update(self) -> Optional[datetime]:
1063
950
  """Return the last time the position was updated."""
1064
951
  return self._last_position_update
1065
952
 
1066
953
  @last_position_update.setter
1067
- def last_position_update(self, value: Optional[int]) -> None:
954
+ def last_position_update(self, value: Optional[datetime]) -> None:
1068
955
  """Set the last position update time."""
1069
956
  self._last_position_update = value
1070
957
 
@@ -1087,18 +974,12 @@ class LGHorizonDeviceState:
1087
974
  async def reset(self) -> None:
1088
975
  """Reset all playing information."""
1089
976
  self.channel_id = None
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
977
+ self.title = None
978
+ self.sub_title = None
1095
979
  self.image = None
1096
980
  self.source_type = LGHorizonSourceType.UNKNOWN
1097
981
  self.speed = None
1098
982
  self.channel_name = None
1099
- self.id = None
1100
- self.start_time = None
1101
- self.end_time = None
1102
983
  await self.reset_progress()
1103
984
 
1104
985
 
@@ -1147,16 +1028,6 @@ class LGHorizonReplayEvent:
1147
1028
  """Return the season number."""
1148
1029
  return self._raw_json.get("seasonNumber")
1149
1030
 
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
-
1160
1031
  @property
1161
1032
  def title(self) -> str:
1162
1033
  """Return the title of the event."""
@@ -1178,6 +1049,10 @@ class LGHorizonReplayEvent:
1178
1049
  full_title += f": {self.episode_name}"
1179
1050
  return full_title
1180
1051
 
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
+
1181
1056
 
1182
1057
  class LGHorizonVODType(Enum):
1183
1058
  """Enumeration of LG Horizon VOD types."""
@@ -1191,11 +1066,6 @@ class LGHorizonVOD:
1191
1066
  """LGHorizon video on demand."""
1192
1067
 
1193
1068
  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
- """
1199
1069
  self._vod_json = vod_json
1200
1070
 
1201
1071
  @property
@@ -1209,14 +1079,26 @@ class LGHorizonVOD:
1209
1079
  return self._vod_json["id"]
1210
1080
 
1211
1081
  @property
1212
- def season(self) -> Optional[int]:
1082
+ def season_number(self) -> Optional[int]:
1213
1083
  """Return the season number of the recording."""
1214
- return self._vod_json.get("season", None)
1084
+ return self._vod_json.get("seasonNumber", None)
1215
1085
 
1216
1086
  @property
1217
- def episode(self) -> Optional[int]:
1087
+ def episode_number(self) -> Optional[int]:
1218
1088
  """Return the episode number of the recording."""
1219
- return self._vod_json.get("episode", None)
1089
+ return self._vod_json.get("episodeNumber", None)
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
1220
1102
 
1221
1103
  @property
1222
1104
  def title(self) -> str:
@@ -1235,7 +1117,7 @@ class LGHorizonVOD:
1235
1117
 
1236
1118
 
1237
1119
  class LGHOrizonRelevantEpisode:
1238
- """Represents a relevant episode within a recording season or show."""
1120
+ """LGHorizon recording."""
1239
1121
 
1240
1122
  def __init__(self, episode_json: dict) -> None:
1241
1123
  """Abstract base class for LG Horizon recordings."""
@@ -1296,7 +1178,7 @@ class LGHorizonRecording(ABC):
1296
1178
  @property
1297
1179
  def title(self) -> str:
1298
1180
  """Return the title of the recording."""
1299
- return self._recording_payload.get("title", "unknown")
1181
+ return self._recording_payload["title"]
1300
1182
 
1301
1183
  @property
1302
1184
  def channel_id(self) -> str:
@@ -1312,10 +1194,7 @@ class LGHorizonRecording(ABC):
1312
1194
  return None
1313
1195
 
1314
1196
  def __init__(self, recording_payload: dict) -> None:
1315
- """Abstract base class for LG Horizon recordings.
1316
- Args:
1317
- recording_payload: The raw JSON dictionary containing recording information.
1318
- """
1197
+ """Abstract base class for LG Horizon recordings."""
1319
1198
  self._recording_payload = recording_payload
1320
1199
 
1321
1200
 
@@ -1327,11 +1206,6 @@ class LGHorizonRecordingSingle(LGHorizonRecording):
1327
1206
  """Return the episode title of the recording."""
1328
1207
  return self._recording_payload.get("episodeTitle", None)
1329
1208
 
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
-
1335
1209
  @property
1336
1210
  def season_number(self) -> Optional[int]:
1337
1211
  """Return the season number of the recording."""
@@ -1347,39 +1221,29 @@ class LGHorizonRecordingSingle(LGHorizonRecording):
1347
1221
  """Return the show ID of the recording."""
1348
1222
  return self._recording_payload.get("showId", None)
1349
1223
 
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
-
1355
1224
  @property
1356
1225
  def season_id(self) -> Optional[str]:
1357
1226
  """Return the season ID of the recording."""
1358
1227
  return self._recording_payload.get("seasonId", None)
1359
1228
 
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
+
1360
1239
  @property
1361
1240
  def channel_id(self) -> Optional[str]:
1362
1241
  """Return the channel ID of the recording."""
1363
1242
  return self._recording_payload.get("channelId", None)
1364
1243
 
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
-
1380
1244
 
1381
1245
  class LGHorizonRecordingSeason(LGHorizonRecording):
1382
- """Represents an LG Horizon recording season."""
1246
+ """LGHorizon recording."""
1383
1247
 
1384
1248
  _most_relevant_epsode: Optional[LGHOrizonRelevantEpisode]
1385
1249
 
@@ -1400,11 +1264,6 @@ class LGHorizonRecordingSeason(LGHorizonRecording):
1400
1264
  """Return the season title of the recording."""
1401
1265
  return self._recording_payload.get("seasonTitle", "")
1402
1266
 
1403
- @property
1404
- def show_id(self) -> str:
1405
- """Return the season title of the recording."""
1406
- return self._recording_payload.get("showId", "")
1407
-
1408
1267
  @property
1409
1268
  def most_relevant_episode(self) -> Optional[LGHOrizonRelevantEpisode]:
1410
1269
  """Return the most relevant episode of the season."""
@@ -1412,7 +1271,7 @@ class LGHorizonRecordingSeason(LGHorizonRecording):
1412
1271
 
1413
1272
 
1414
1273
  class LGHorizonRecordingShow(LGHorizonRecording):
1415
- """Represents an LG Horizon recording show."""
1274
+ """LGHorizon recording."""
1416
1275
 
1417
1276
  _most_relevant_epsode: Optional[LGHOrizonRelevantEpisode]
1418
1277
 
@@ -1435,7 +1294,7 @@ class LGHorizonRecordingShow(LGHorizonRecording):
1435
1294
 
1436
1295
 
1437
1296
  class LGHorizonRecordingList:
1438
- """Represents a list of LG Horizon recordings."""
1297
+ """LGHorizon recording."""
1439
1298
 
1440
1299
  @property
1441
1300
  def total(self) -> int:
@@ -1443,49 +1302,9 @@ class LGHorizonRecordingList:
1443
1302
  return len(self._recordings)
1444
1303
 
1445
1304
  def __init__(self, recordings: List[LGHorizonRecording]) -> None:
1446
- """Initialize an LG Horizon recording list.
1447
-
1448
- Args:
1449
- recordings: A list of LGHorizonRecording objects.
1450
- """
1305
+ """Abstract base class for LG Horizon recordings."""
1451
1306
  self._recordings = recordings
1452
1307
 
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
-
1489
1308
 
1490
1309
  class LGHorizonRecordingQuota:
1491
1310
  """LGHorizon recording quota."""