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.
lghorizon/__init__.py CHANGED
@@ -2,70 +2,5 @@
2
2
 
3
3
  from .lghorizon_api import LGHorizonApi
4
4
  from .lghorizon_device import LGHorizonDevice
5
- from .lghorizon_models import (
6
- LGHorizonAuth,
7
- LGHorizonChannel,
8
- LGHorizonCustomer,
9
- LGHorizonDeviceState,
10
- LGHorizonProfile,
11
- LGHorizonRecording,
12
- LGHorizonRecordingList,
13
- LGHorizonShowRecordingList,
14
- LGHorizonRecordingSeason,
15
- LGHorizonRecordingSingle,
16
- LGHorizonRecordingShow,
17
- LGHorizonRecordingQuota,
18
- LGHorizonRecordingType,
19
- LGHorizonUIStateType,
20
- LGHorizonMessageType,
21
- LGHorizonRunningState,
22
- LGHorizonRecordingSource,
23
- LGHorizonRecordingState,
24
- LGHorizonSourceType,
25
- LGHorizonPlayerState,
26
- LGHorizonAppsState,
27
- LGHorizonUIState,
28
- LGHorizonProfileOptions,
29
- LGHorizonServicesConfig,
30
- )
31
- from .exceptions import (
32
- LGHorizonApiError,
33
- LGHorizonApiConnectionError,
34
- LGHorizonApiUnauthorizedError,
35
- LGHorizonApiLockedError,
36
- )
37
-
38
- __all__ = [
39
- "LGHorizonApi",
40
- "LGHorizonDevice",
41
- "LGHorizonAuth",
42
- "LGHorizonChannel",
43
- "LGHorizonCustomer",
44
- "LGHorizonDeviceState",
45
- "LGHorizonProfile",
46
- "LGHorizonApiError",
47
- "LGHorizonApiConnectionError",
48
- "LGHorizonApiUnauthorizedError",
49
- "LGHorizonApiLockedError",
50
- "LGHorizonRecordingList",
51
- "LGHorizonRecordingSeason",
52
- "LGHorizonRecordingSingle",
53
- "LGHorizonRecordingShow",
54
- "LGHorizonRecordingQuota",
55
- "LGHorizonRecordingType",
56
- "LGHorizonUIStateType",
57
- "LGHorizonMessageType",
58
- "LGHorizonRunningState",
59
- "LGHorizonRecordingSource",
60
- "LGHorizonRecordingState",
61
- "LGHorizonSourceType",
62
- "LGHorizonPlayerState",
63
- "LGHorizonAppsState",
64
- "LGHorizonUIState",
65
- "LGHorizonProfileOptions",
66
- "LGHorizonProfile",
67
- "LGHorizonAuth",
68
- "LGHorizonServicesConfig",
69
- "LGHorizonRecording",
70
- "LGHorizonShowRecordingList",
71
- ]
5
+ from .lghorizon_models import *
6
+ from .exceptions import *
lghorizon/exceptions.py CHANGED
@@ -6,12 +6,12 @@ class LGHorizonApiError(Exception):
6
6
 
7
7
 
8
8
  class LGHorizonApiConnectionError(LGHorizonApiError):
9
- """Exception for connection-related errors with the LG Horizon API."""
9
+ """Generic LGHorizon exception."""
10
10
 
11
11
 
12
12
  class LGHorizonApiUnauthorizedError(Exception):
13
- """Exception for unauthorized access to the LG Horizon API."""
13
+ """Generic LGHorizon exception."""
14
14
 
15
15
 
16
16
  class LGHorizonApiLockedError(LGHorizonApiUnauthorizedError):
17
- """Exception for locked account errors with the LG Horizon API."""
17
+ """Generic LGHorizon exception."""
@@ -1,7 +1,7 @@
1
1
  """LG Horizon API client."""
2
2
 
3
3
  import logging
4
- from typing import Any, Dict, cast, Callable, Optional
4
+ from typing import Any, Dict, cast
5
5
 
6
6
  from .lghorizon_device import LGHorizonDevice
7
7
  from .lghorizon_models import LGHorizonChannel
@@ -15,11 +15,7 @@ from .lghorizon_models import LGHorizonMessageType
15
15
  from .lghorizon_message_factory import LGHorizonMessageFactory
16
16
  from .lghorizon_models import LGHorizonStatusMessage, LGHorizonUIStatusMessage
17
17
  from .lghorizon_models import LGHorizonRunningState
18
- from .lghorizon_models import (
19
- LGHorizonRecordingList,
20
- LGHorizonRecordingQuota,
21
- LGHorizonShowRecordingList,
22
- )
18
+ from .lghorizon_models import LGHorizonRecordingList, LGHorizonRecordingQuota
23
19
  from .lghorizon_recording_factory import LGHorizonRecordingFactory
24
20
  from .lghorizon_device_state_processor import LGHorizonDeviceStateProcessor
25
21
 
@@ -30,7 +26,7 @@ _LOGGER = logging.getLogger(__name__)
30
26
  class LGHorizonApi:
31
27
  """LG Horizon API client."""
32
28
 
33
- _mqtt_client: LGHorizonMqttClient | None
29
+ _mqtt_client: LGHorizonMqttClient
34
30
  auth: LGHorizonAuth
35
31
  _service_config: LGHorizonServicesConfig
36
32
  _customer: LGHorizonCustomer
@@ -45,18 +41,10 @@ class LGHorizonApi:
45
41
 
46
42
  def __init__(self, auth: LGHorizonAuth, profile_id: str = "") -> None:
47
43
  """Initialize LG Horizon API client."""
48
- """Initialize LG Horizon API client.
49
-
50
- Args:
51
- auth: The authentication object for API requests.
52
- profile_id: The ID of the user profile to use (optional).
53
- """
54
44
  self.auth = auth
55
45
  self._profile_id = profile_id
56
46
  self._channels = {}
57
47
  self._device_state_processor = None
58
- self._mqtt_client = None
59
- self._initialized = False
60
48
 
61
49
  async def initialize(self) -> None:
62
50
  """Initialize the API client."""
@@ -74,20 +62,14 @@ class LGHorizonApi:
74
62
  )
75
63
  self._initialized = True
76
64
 
77
- async def set_token_refresh_callback(
78
- self, token_refresh_callback: Callable[str, None]
79
- ) -> None:
80
- """Set the token refresh callback."""
81
- self.auth.token_refresh_callback = token_refresh_callback
82
-
83
- async def get_devices(self) -> dict[str, LGHorizonDevice]:
65
+ async def get_devices(self) -> Dict[str, LGHorizonDevice]:
84
66
  """Get devices."""
85
67
  if not self._initialized:
86
68
  raise RuntimeError("LGHorizonApi not initialized")
87
69
 
88
70
  return self._devices
89
71
 
90
- async def get_profiles(self) -> dict[str, LGHorizonProfile]:
72
+ async def get_profiles(self) -> Dict[str, LGHorizonProfile]:
91
73
  """Get profile IDs."""
92
74
  if not self._initialized:
93
75
  raise RuntimeError("LGHorizonApi not initialized")
@@ -95,16 +77,14 @@ class LGHorizonApi:
95
77
  return self._customer.profiles
96
78
 
97
79
  async def get_profile_channels(
98
- self, profile_id: Optional[str] = None
80
+ self, profile_id: str
99
81
  ) -> Dict[str, LGHorizonChannel]:
100
82
  """Returns channels to display baed on profile."""
101
83
  # Attempt to retrieve the profile by the given profile_id
102
- if not profile_id:
103
- profile_id = self._profile_id
104
84
  profile = self._customer.profiles.get(profile_id)
105
85
 
106
86
  # If the specified profile is not found, and there are other profiles available,
107
- # default to the first profile in the customer's list if available.
87
+ # default to the first profile in the customer's list.
108
88
  if not profile and self._customer.profiles:
109
89
  _LOGGER.debug(
110
90
  "Profile with ID '%s' not found. Defaulting to first available profile.",
@@ -155,10 +135,6 @@ class LGHorizonApi:
155
135
  self._initialized = False
156
136
 
157
137
  async def _create_mqtt_client(self) -> LGHorizonMqttClient:
158
- """Create and configure the MQTT client.
159
-
160
- Returns: An initialized LGHorizonMqttClient instance.
161
- """
162
138
  mqtt_client = await LGHorizonMqttClient.create(
163
139
  self.auth,
164
140
  self._on_mqtt_connected,
@@ -168,10 +144,8 @@ class LGHorizonApi:
168
144
 
169
145
  async def _on_mqtt_connected(self):
170
146
  """MQTT connected callback."""
171
- await self._mqtt_client.subscribe("#")
172
147
  await self._mqtt_client.subscribe(self.auth.household_id)
173
148
  # await self._mqtt_client.subscribe(self.auth.household_id + "/#")
174
- # await self._mqtt_client.subscribe(self.auth.household_id + "/+/#")
175
149
  await self._mqtt_client.subscribe(
176
150
  self.auth.household_id + "/" + self._mqtt_client.client_id
177
151
  )
@@ -203,16 +177,12 @@ class LGHorizonApi:
203
177
  case LGHorizonMessageType.STATUS:
204
178
  message.__class__ = LGHorizonStatusMessage
205
179
  status_message = cast(LGHorizonStatusMessage, message)
206
- device = self._devices.get(status_message.source, None)
207
- if not device:
208
- return
180
+ device = self._devices[status_message.source]
209
181
  await device.handle_status_message(status_message)
210
182
  case LGHorizonMessageType.UI_STATUS:
211
183
  message.__class__ = LGHorizonUIStatusMessage
212
184
  ui_status_message = cast(LGHorizonUIStatusMessage, message)
213
- device = self._devices.get(ui_status_message.source, None)
214
- if not device:
215
- return
185
+ device = self._devices[ui_status_message.source]
216
186
  if (
217
187
  not device.device_state.state
218
188
  == LGHorizonRunningState.ONLINE_RUNNING
@@ -274,14 +244,14 @@ class LGHorizonApi:
274
244
 
275
245
  async def get_show_recordings(
276
246
  self, show_id: str, channel_id: str
277
- ) -> LGHorizonShowRecordingList: # type: ignore[valid-type]
247
+ ) -> LGHorizonRecordingList:
278
248
  """Retrieve all recordings."""
279
249
  _LOGGER.debug("Retrieving recordings fro show...")
280
250
  service_url = await self._service_config.get_service_url("recordingService")
281
251
  lang = await self._customer.get_profile_lang(self._profile_id)
282
252
  episodes_json = await self.auth.request(
283
253
  service_url,
284
- f"/customers/{self.auth.household_id}/episodes/shows/{show_id}?source=recording&isAdult=false&offset=0&limit=100&profileId={self._profile_id}&language={lang}&channelId={channel_id}&sort=time&sortOrder=asc",
254
+ f"/customers/8436830_nl/episodes/shows/{show_id}?source=recording&isAdult=false&offset=0&limit=100&profileId={self._profile_id}&language={lang}&channelId={channel_id}&sort=time&sortOrder=asc",
285
255
  )
286
256
  recordings = await self._recording_factory.create_episodes(episodes_json)
287
257
  return recordings
@@ -1,7 +1,7 @@
1
1
  """LG Horizon Device."""
2
2
 
3
3
  from __future__ import annotations
4
- import asyncio
4
+
5
5
  import json
6
6
  import logging
7
7
  from typing import Any, Callable, Coroutine, Dict, Optional
@@ -146,6 +146,8 @@ class LGHorizonDevice:
146
146
 
147
147
  async def register_mqtt(self) -> None:
148
148
  """Register the mqtt connection."""
149
+ if not self._mqtt_client.is_connected:
150
+ raise LGHorizonApiConnectionError("MQTT client not connected.")
149
151
  topic = f"{self._auth.household_id}/{self._mqtt_client.client_id}/status"
150
152
  payload = {
151
153
  "source": self._mqtt_client.client_id,
@@ -157,23 +159,14 @@ class LGHorizonDevice:
157
159
  async def set_callback(
158
160
  self, change_callback: Callable[[str], Coroutine[Any, Any, Any]]
159
161
  ) -> None:
160
- """Set a callback function to be called when the device state changes.
161
-
162
- Args:
163
- change_callback: An asynchronous callable that takes the device ID
164
- as an argument.
165
- """
162
+ """Set a callback function."""
166
163
  self._change_callback = change_callback
167
164
  await self.register_mqtt() # type: ignore [assignment] # Callback can be None
168
165
 
169
166
  async def handle_status_message(
170
167
  self, status_message: LGHorizonStatusMessage
171
168
  ) -> None:
172
- """Handle an incoming status message from the set-top box.
173
-
174
- Args:
175
- status_message: The status message received from the device.
176
- """
169
+ """Register a new settop box."""
177
170
  old_running_state = self.device_state.state
178
171
  new_running_state = status_message.running_state
179
172
  if (
@@ -207,11 +200,7 @@ class LGHorizonDevice:
207
200
  self.recording_capacity = payload["used"] # Use the setter
208
201
 
209
202
  async def _trigger_callback(self):
210
- """Trigger the registered callback function.
211
-
212
- This method is called when the device's state changes and a callback is set.
213
- """
214
- if self._change_callback is not None:
203
+ if self._change_callback:
215
204
  _LOGGER.debug("Callback called from box %s", self.device_id)
216
205
  await self._change_callback(self.device_id)
217
206
 
@@ -278,100 +267,38 @@ class LGHorizonDevice:
278
267
  if self._device_state.state == LGHorizonRunningState.ONLINE_RUNNING:
279
268
  await self.send_key_to_box(MEDIA_KEY_RECORD)
280
269
 
281
- async def set_player_position(self, position: int) -> None:
282
- """Set the player position on the settop box."""
283
- payload = {
284
- "source": self.device_id,
285
- "type": "CPE.setPlayerPosition",
286
- "runtimeType": "setPlayerposition",
287
- "id": await make_id(),
288
- "version": "1.3.11",
289
- "status": {"relativePosition": position},
290
- }
291
- payload_str = json.dumps(payload)
292
- await self._mqtt_client.publish_message(
293
- f"{self._auth.household_id}/{self.device_id}", payload_str
294
- )
295
-
296
- async def display_message(self, sourceType: str, message: str) -> None:
297
- """Display a message on the set-top box and repeat it for longer visibility.
298
-
299
- # We sturen de payload 3 keer met een kortere tussentijd
300
-
301
- This method sends the message payload multiple times to ensure it stays
302
- visible on the screen for a longer duration, as the display time for
303
- such messages is typically short.
304
-
305
- Args:
306
- sourceType: The type of source for the message (e.g., "linear").
307
- message: The message string to display.
308
- """
309
- for i in range(3):
310
- payload = {
311
- "id": await make_id(8),
312
- "type": "CPE.pushToTV",
313
- "source": {
314
- "clientId": self._mqtt_client.client_id,
315
- "friendlyDeviceName": f"\n\n{message}",
316
- },
317
- "status": {
318
- "sourceType": sourceType,
319
- "source": {"channelId": "1234"},
320
- "title": "Nieuwe melding",
321
- "relativePosition": 0,
322
- "speed": 1,
323
- },
324
- }
325
-
326
- await self._mqtt_client.publish_message(
327
- f"{self._auth.household_id}/{self.device_id}", json.dumps(payload)
328
- )
329
-
330
- # Omdat de melding 3 seconden blijft staan, wachten we 3 seconden
331
- # voor de volgende 'refresh'.
332
- if i < 2:
333
- await asyncio.sleep(3)
334
-
335
270
  async def set_channel(self, source: str) -> None:
336
271
  """Change te channel from the settopbox."""
337
272
  channel = [src for src in self._channels.values() if src.title == source][0]
338
- payload = {
339
- "id": await make_id(8),
340
- "type": "CPE.pushToTV",
341
- "source": {
342
- "clientId": self._mqtt_client.client_id,
343
- "friendlyDeviceName": "Home Assistant",
344
- },
345
- "status": {
346
- "sourceType": "linear",
347
- "source": {"channelId": channel.id},
348
- "relativePosition": 0,
349
- "speed": 1,
350
- },
351
- }
273
+ payload = (
274
+ '{"id":"'
275
+ + await make_id(8)
276
+ + '","type":"CPE.pushToTV","source":{"clientId":"'
277
+ + self._mqtt_client.client_id
278
+ + '","friendlyDeviceName":"Home Assistant"},'
279
+ + '"status":{"sourceType":"linear","source":{"channelId":"'
280
+ + channel.id
281
+ + '"},"relativePosition":0,"speed":1}}'
282
+ )
352
283
 
353
284
  await self._mqtt_client.publish_message(
354
- f"{self._auth.household_id}/{self.device_id}", json.dumps(payload)
285
+ f"{self._auth.household_id}/{self.device_id}", payload
355
286
  )
356
287
 
357
288
  async def play_recording(self, recording_id):
358
289
  """Play recording."""
359
- payload = {
360
- "id": await make_id(8),
361
- "type": "CPE.pushToTV",
362
- "source": {
363
- "clientId": self._mqtt_client.client_id,
364
- "friendlyDeviceName": "Home Assistant",
365
- },
366
- "status": {
367
- "sourceType": "nDVR",
368
- "source": {"recordingId": recording_id},
369
- "relativePosition": 0,
370
- },
371
- }
372
-
290
+ payload = (
291
+ '{"id":"'
292
+ + await make_id(8)
293
+ + '","type":"CPE.pushToTV","source":{"clientId":"'
294
+ + self._mqtt_client.client_id
295
+ + '","friendlyDeviceName":"Home Assistant"},'
296
+ + '"status":{"sourceType":"nDVR","source":{"recordingId":"'
297
+ + recording_id
298
+ + '"},"relativePosition":0}}'
299
+ )
373
300
  await self._mqtt_client.publish_message(
374
- f"{self._auth.household_id}/{self.device_id}", json.dumps(payload)
301
+ f"{self._auth.household_id}/{self.device_id}", payload
375
302
  )
376
303
 
377
304
  async def send_key_to_box(self, key: str) -> None:
@@ -3,9 +3,6 @@
3
3
  import random
4
4
  import json
5
5
  import urllib.parse
6
- from datetime import datetime as dt, timezone
7
-
8
- import time
9
6
 
10
7
  from typing import cast, Dict, Optional
11
8
 
@@ -18,10 +15,12 @@ from .lghorizon_models import (
18
15
  LGHorizonReplaySource,
19
16
  LGHorizonNDVRSource,
20
17
  LGHorizonReviewBufferSource,
21
- LGHorizonRecordingSource,
22
18
  )
23
19
  from .lghorizon_models import LGHorizonAuth
24
- from .lghorizon_models import LGHorizonReplayEvent, LGHorizonVOD, LGHorizonVODType
20
+ from .lghorizon_models import (
21
+ LGHorizonReplayEvent,
22
+ LGHorizonVOD,
23
+ )
25
24
 
26
25
  from .lghorizon_models import LGHorizonRecordingSingle
27
26
  from .lghorizon_models import LGHorizonChannel
@@ -100,9 +99,6 @@ class LGHorizonDeviceStateProcessor:
100
99
  return
101
100
  await device_state.reset()
102
101
  device_state.source_type = player_state.source_type
103
- device_state.ui_state_type = LGHorizonUIStateType.MAINUI
104
- device_state.speed = player_state.speed
105
-
106
102
  match player_state.source_type:
107
103
  case LGHorizonSourceType.LINEAR:
108
104
  await self._process_linear_state(device_state, player_state)
@@ -120,10 +116,9 @@ class LGHorizonDeviceStateProcessor:
120
116
  device_state: LGHorizonDeviceState,
121
117
  apps_state: LGHorizonAppsState,
122
118
  ) -> None:
123
- device_state.id = apps_state.id
124
- device_state.show_title = apps_state.app_name
119
+ device_state.channel_id = apps_state.id
120
+ device_state.title = apps_state.app_name
125
121
  device_state.image = apps_state.logo_path
126
- device_state.ui_state_type = LGHorizonUIStateType.APPS
127
122
 
128
123
  async def _process_linear_state(
129
124
  self,
@@ -145,22 +140,12 @@ class LGHorizonDeviceStateProcessor:
145
140
  service_path,
146
141
  )
147
142
  replay_event = LGHorizonReplayEvent(event_json)
148
- device_state.id = replay_event.event_id
149
143
  channel = self._channels[replay_event.channel_id]
150
144
  device_state.source_type = source.source_type
151
- device_state.channel_id = channel.id
145
+ device_state.channel_id = channel.channel_number
152
146
  device_state.channel_name = channel.title
153
- device_state.episode_title = replay_event.episode_name
154
- device_state.season_number = replay_event.season_number
155
- device_state.episode_number = replay_event.episode_number
156
- device_state.show_title = replay_event.title
157
- now_in_ms = int(time.time() * 1000)
158
-
159
- device_state.last_position_update = int(time.time() * 1000)
160
- device_state.start_time = replay_event.start_time
161
- device_state.end_time = replay_event.end_time
162
- device_state.duration = replay_event.end_time - replay_event.start_time
163
- device_state.position = now_in_ms - int(replay_event.start_time * 1000)
147
+ device_state.title = replay_event.title
148
+ device_state.sub_title = replay_event.full_episode_title
164
149
 
165
150
  # Add random number to url to force refresh
166
151
  join_param = "?"
@@ -170,6 +155,7 @@ class LGHorizonDeviceStateProcessor:
170
155
  f"{channel.stream_image}{join_param}{str(random.randrange(1000000))}"
171
156
  )
172
157
  device_state.image = image_url
158
+ await device_state.reset_progress()
173
159
 
174
160
  async def _process_reviewbuffer_state(
175
161
  self,
@@ -191,20 +177,13 @@ class LGHorizonDeviceStateProcessor:
191
177
  service_path,
192
178
  )
193
179
  replay_event = LGHorizonReplayEvent(event_json)
194
- device_state.id = replay_event.event_id
195
180
  channel = self._channels[replay_event.channel_id]
196
181
  device_state.source_type = source.source_type
197
- device_state.channel_id = channel.id
182
+ device_state.channel_id = channel.channel_number
198
183
  device_state.channel_name = channel.title
199
- device_state.episode_title = replay_event.episode_name
200
- device_state.season_number = replay_event.season_number
201
- device_state.episode_number = replay_event.episode_number
202
- device_state.show_title = replay_event.title
203
- device_state.last_position_update = player_state.last_speed_change_time
204
- device_state.position = player_state.relative_position
205
- device_state.start_time = replay_event.start_time
206
- device_state.end_time = replay_event.end_time
207
- device_state.duration = replay_event.end_time - replay_event.start_time
184
+ device_state.title = replay_event.title
185
+ device_state.sub_title = replay_event.full_episode_title
186
+
208
187
  # Add random number to url to force refresh
209
188
  join_param = "?"
210
189
  if join_param in channel.stream_image:
@@ -213,6 +192,7 @@ class LGHorizonDeviceStateProcessor:
213
192
  f"{channel.stream_image}{join_param}{str(random.randrange(1000000))}"
214
193
  )
215
194
  device_state.image = image_url
195
+ await device_state.reset_progress()
216
196
 
217
197
  async def _process_replay_state(
218
198
  self,
@@ -234,27 +214,15 @@ class LGHorizonDeviceStateProcessor:
234
214
  service_path,
235
215
  )
236
216
  replay_event = LGHorizonReplayEvent(event_json)
237
- device_state.id = replay_event.event_id
238
- # Iets met buffer doen
239
- channel = self._channels[replay_event.channel_id]
240
- padding = channel.replay_pre_padding + channel.replay_post_padding
241
217
  device_state.source_type = source.source_type
242
- device_state.channel_id = channel.id
243
- device_state.episode_title = replay_event.episode_name
244
- device_state.season_number = replay_event.season_number
245
- device_state.episode_number = replay_event.episode_number
246
- device_state.show_title = replay_event.title
247
- device_state.last_position_update = int(time.time() * 1000)
248
- device_state.start_time = replay_event.start_time
249
- device_state.end_time = replay_event.end_time
250
- device_state.duration = (
251
- replay_event.end_time - replay_event.start_time + padding
252
- )
253
- device_state.position = (
254
- player_state.relative_position + channel.replay_pre_padding
255
- )
218
+ device_state.channel_id = None
219
+ device_state.title = replay_event.title
220
+ if replay_event.full_episode_title:
221
+ device_state.sub_title = replay_event.full_episode_title
222
+
256
223
  # Add random number to url to force refresh
257
224
  device_state.image = await self._get_intent_image_url(replay_event.event_id)
225
+ await device_state.reset_progress()
258
226
 
259
227
  async def _process_vod_state(
260
228
  self,
@@ -276,20 +244,11 @@ class LGHorizonDeviceStateProcessor:
276
244
  service_path,
277
245
  )
278
246
  vod = LGHorizonVOD(vod_json)
279
- device_state.id = vod.id
280
- if vod.vod_type == LGHorizonVODType.EPISODE:
281
- device_state.show_title = vod.series_title
282
- device_state.episode_title = vod.title
283
- device_state.season_number = vod.season
284
- device_state.episode_number = vod.episode
285
- else:
286
- device_state.show_title = vod.title
287
-
247
+ device_state.title = vod.title
248
+ device_state.sub_title = vod.full_episode_title
288
249
  device_state.duration = vod.duration
289
- device_state.last_position_update = int(time.time() * 1000)
290
- device_state.position = player_state.relative_position
291
-
292
250
  device_state.image = await self._get_intent_image_url(vod.id)
251
+ await device_state.reset_progress()
293
252
 
294
253
  async def _process_ndvr_state(
295
254
  self, device_state: LGHorizonDeviceState, player_state: LGHorizonPlayerState
@@ -308,36 +267,13 @@ class LGHorizonDeviceStateProcessor:
308
267
  service_path,
309
268
  )
310
269
  recording = LGHorizonRecordingSingle(recording_json)
311
- device_state.id = recording.id
270
+ device_state.title = recording.title
271
+ device_state.sub_title = recording.full_episode_title
312
272
  device_state.channel_id = recording.channel_id
313
273
  if recording.channel_id:
314
274
  channel = self._channels[recording.channel_id]
315
275
  device_state.channel_name = channel.title
316
276
 
317
- device_state.episode_title = recording.episode_title
318
- device_state.season_number = recording.season_number
319
- device_state.episode_number = recording.episode_number
320
- device_state.last_position_update = player_state.last_speed_change_time
321
- device_state.position = player_state.relative_position
322
- if recording.start_time:
323
- device_state.start_time = int(
324
- dt.fromisoformat(
325
- recording.start_time.replace("Z", "+00:00")
326
- ).timestamp()
327
- )
328
- if recording.end_time:
329
- device_state.end_time = int(
330
- dt.fromisoformat(recording.end_time.replace("Z", "+00:00")).timestamp()
331
- )
332
- if recording.start_time and recording.end_time:
333
- device_state.duration = device_state.end_time - device_state.start_time
334
- if recording.source == LGHorizonRecordingSource.SHOW:
335
- device_state.show_title = recording.title
336
- else:
337
- device_state.show_title = recording.show_title
338
-
339
- device_state.image = await self._get_intent_image_url(recording.id)
340
-
341
277
  async def _get_intent_image_url(self, intent_id: str) -> Optional[str]:
342
278
  """Get intent image url."""
343
279
  service_config = await self._auth.get_service_config()
@@ -22,6 +22,7 @@ class LGHorizonMessageFactory:
22
22
  case LGHorizonMessageType.STATUS:
23
23
  return LGHorizonStatusMessage(payload, topic)
24
24
  case LGHorizonMessageType.UI_STATUS:
25
+ # Placeholder for UI_STATUS message handling
25
26
  return LGHorizonUIStatusMessage(payload, topic)
26
27
  case LGHorizonMessageType.UNKNOWN:
27
28
  return LGHorizonUnknownMessage(payload, topic)