From b1543eaa204d5be2d200e9d346a62245838a417e Mon Sep 17 00:00:00 2001 From: Rudolf Offereins Date: Wed, 4 Feb 2026 06:25:27 +0000 Subject: [PATCH 1/2] Fix position and duration --- lghorizon/lghorizon_device_state_processor.py | 35 ++++++++-------- main.py | 40 +++++++++++++++++-- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/lghorizon/lghorizon_device_state_processor.py b/lghorizon/lghorizon_device_state_processor.py index e9d9bc3..081c172 100644 --- a/lghorizon/lghorizon_device_state_processor.py +++ b/lghorizon/lghorizon_device_state_processor.py @@ -154,13 +154,11 @@ async def _process_linear_state( device_state.season_number = replay_event.season_number device_state.episode_number = replay_event.episode_number device_state.show_title = replay_event.title - now_in_ms = int(time.time() * 1000) - - device_state.last_position_update = int(time.time() * 1000) + device_state.last_position_update = int(time.time()) device_state.start_time = replay_event.start_time device_state.end_time = replay_event.end_time device_state.duration = replay_event.end_time - replay_event.start_time - device_state.position = now_in_ms - int(replay_event.start_time * 1000) + device_state.position = int(time.time()) - int(replay_event.start_time) # Add random number to url to force refresh join_param = "?" @@ -200,8 +198,10 @@ async def _process_reviewbuffer_state( device_state.season_number = replay_event.season_number device_state.episode_number = replay_event.episode_number device_state.show_title = replay_event.title - device_state.last_position_update = player_state.last_speed_change_time - device_state.position = player_state.relative_position + device_state.last_position_update = int( + player_state.last_speed_change_time / 1000 + ) + device_state.position = int(player_state.relative_position / 1000) device_state.start_time = replay_event.start_time device_state.end_time = replay_event.end_time device_state.duration = replay_event.end_time - replay_event.start_time @@ -237,22 +237,19 @@ async def _process_replay_state( device_state.id = replay_event.event_id # Iets met buffer doen channel = self._channels[replay_event.channel_id] - padding = channel.replay_pre_padding + channel.replay_post_padding device_state.source_type = source.source_type device_state.channel_id = channel.id device_state.episode_title = replay_event.episode_name device_state.season_number = replay_event.season_number device_state.episode_number = replay_event.episode_number device_state.show_title = replay_event.title - device_state.last_position_update = int(time.time() * 1000) + device_state.last_position_update = int( + player_state.last_speed_change_time / 1000 + ) device_state.start_time = replay_event.start_time device_state.end_time = replay_event.end_time - device_state.duration = ( - replay_event.end_time - replay_event.start_time + padding - ) - device_state.position = ( - player_state.relative_position + channel.replay_pre_padding - ) + device_state.duration = replay_event.end_time - replay_event.start_time + device_state.position = int(player_state.relative_position / 1000) # Add random number to url to force refresh device_state.image = await self._get_intent_image_url(replay_event.event_id) @@ -286,8 +283,8 @@ async def _process_vod_state( device_state.show_title = vod.title device_state.duration = vod.duration - device_state.last_position_update = int(time.time() * 1000) - device_state.position = player_state.relative_position + device_state.last_position_update = int(time.time()) + device_state.position = int(player_state.relative_position / 1000) device_state.image = await self._get_intent_image_url(vod.id) @@ -317,8 +314,10 @@ async def _process_ndvr_state( device_state.episode_title = recording.episode_title device_state.season_number = recording.season_number device_state.episode_number = recording.episode_number - device_state.last_position_update = player_state.last_speed_change_time - device_state.position = player_state.relative_position + device_state.last_position_update = int( + player_state.last_speed_change_time / 1000 + ) + device_state.position = int(player_state.relative_position / 1000) if recording.start_time: device_state.start_time = int( dt.fromisoformat( diff --git a/main.py b/main.py index 90aa922..e13c1e1 100644 --- a/main.py +++ b/main.py @@ -4,9 +4,9 @@ import json import logging import sys # Import sys for stdin - import aiohttp -import traceback + +from datetime import datetime from lghorizon.lghorizon_api import LGHorizonApi from lghorizon.lghorizon_models import LGHorizonAuth @@ -28,6 +28,40 @@ async def read_input_and_signal_shutdown(): _LOGGER = logging.getLogger(__name__) +def format_duration(total_seconds): + # Handle None immediately + if total_seconds is None: + return None + + # Store if the value is negative and work with positive numbers for calculation + is_negative = total_seconds < 0 + total_seconds = abs(int(total_seconds)) + + # Efficiently calculate hours, minutes, and seconds + minutes, seconds = divmod(total_seconds, 60) + hours, minutes = divmod(minutes, 60) + + # Determine the base format + if hours > 0: + result = f"{hours}:{minutes:02}:{seconds:02}" + elif minutes > 0: + result = f"{minutes}:{seconds:02}" + else: + result = f"{seconds}" + + # Add the minus sign if it was negative + return f"-{result}" if is_negative else result + + +def convert_timestamp_to_datetime(timestamp): + # Handle None to prevent crashes + if timestamp is None: + return None + + # Convert seconds to a datetime object + return datetime.fromtimestamp(timestamp) + + async def main(): """Main function to run the LG Horizon API test script.""" logging.basicConfig( @@ -54,7 +88,7 @@ async def main(): async def device_callback(device_id: str): device = devices[device_id] print( - f"Device {device.device_id} state changed. Status:\n\nName: {device.device_friendly_name}\nState: {device.device_state.state.value}\nChannel: {device.device_state.channel_name} ({device.device_state.channel_id})\nShow: {device.device_state.show_title}\nEpisode: {device.device_state.episode_title}\nSource type: {device.device_state.source_type.value}\nlast pos update: {device.device_state.last_position_update}\npos: {device.device_state.position}\nstart time: {device.device_state.start_time}\nend time: {device.device_state.end_time}\n\n", + f"Device {device.device_id} state changed. Status:\n\nName: {device.device_friendly_name}\nState: {device.device_state.state.value}\nChannel: {device.device_state.channel_name} ({device.device_state.channel_id})\nShow: {device.device_state.show_title}\nEpisode: {device.device_state.episode_title}\nSource type: {device.device_state.source_type.value}\nlast pos update: {convert_timestamp_to_datetime(device.device_state.last_position_update)}\npos: {format_duration(device.device_state.position)}\nduration: {format_duration(device.device_state.duration)}\nstart time: {device.device_state.start_time}\nend time: {device.device_state.end_time}\n\n", ) try: From 134ef600d27877996c9770de14a46e761701149a Mon Sep 17 00:00:00 2001 From: Rudolf Offereins Date: Wed, 4 Feb 2026 06:35:32 +0000 Subject: [PATCH 2/2] show start time and endtime readable --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index e13c1e1..e5eb563 100644 --- a/main.py +++ b/main.py @@ -88,7 +88,7 @@ async def main(): async def device_callback(device_id: str): device = devices[device_id] print( - f"Device {device.device_id} state changed. Status:\n\nName: {device.device_friendly_name}\nState: {device.device_state.state.value}\nChannel: {device.device_state.channel_name} ({device.device_state.channel_id})\nShow: {device.device_state.show_title}\nEpisode: {device.device_state.episode_title}\nSource type: {device.device_state.source_type.value}\nlast pos update: {convert_timestamp_to_datetime(device.device_state.last_position_update)}\npos: {format_duration(device.device_state.position)}\nduration: {format_duration(device.device_state.duration)}\nstart time: {device.device_state.start_time}\nend time: {device.device_state.end_time}\n\n", + f"Device {device.device_id} state changed. Status:\n\nName: {device.device_friendly_name}\nState: {device.device_state.state.value}\nChannel: {device.device_state.channel_name} ({device.device_state.channel_id})\nShow: {device.device_state.show_title}\nEpisode: {device.device_state.episode_title}\nSource type: {device.device_state.source_type.value}\nlast pos update: {convert_timestamp_to_datetime(device.device_state.last_position_update)}\npos: {format_duration(device.device_state.position)}\nduration: {format_duration(device.device_state.duration)}\nstart time: {convert_timestamp_to_datetime(device.device_state.start_time)}\nend time: {convert_timestamp_to_datetime(device.device_state.end_time)}\n\n", ) try: