Merge pull request #270 from dmunozv04/playback-speed

Add support for different playback speeds
This commit is contained in:
David
2025-03-10 13:05:02 +01:00
committed by GitHub
2 changed files with 27 additions and 11 deletions

View File

@@ -76,11 +76,11 @@ class DeviceListener:
# Method called on playback state change # Method called on playback state change
async def __call__(self, state): async def __call__(self, state):
time_start = time.monotonic()
try: try:
self.task.cancel() self.task.cancel()
except BaseException: except BaseException:
pass pass
time_start = time.time()
self.task = asyncio.create_task(self.process_playstatus(state, time_start)) self.task = asyncio.create_task(self.process_playstatus(state, time_start))
# Processes the playback state change # Processes the playback state change
@@ -100,28 +100,34 @@ class DeviceListener:
start_next_segment = None start_next_segment = None
next_segment = None next_segment = None
for segment in segments: for segment in segments:
if position < 2 and (segment["start"] <= position < segment["end"]): segment_start = segment["start"]
segment_end = segment["end"]
is_within_start_range = (
position < 1 < segment_end and segment_start <= position < segment_end
)
is_beyond_current_position = segment_start > position
if is_within_start_range or is_beyond_current_position:
next_segment = segment next_segment = segment
start_next_segment = ( start_next_segment = (
position # different variable so segment doesn't change position if is_within_start_range else segment_start
) )
break break
if segment["start"] > position:
next_segment = segment
start_next_segment = next_segment["start"]
break
if start_next_segment: if start_next_segment:
time_to_next = ( time_to_next = (
start_next_segment - position - (time.time() - time_start) - self.offset (start_next_segment - position - (time.monotonic() - time_start))
) / self.lounge_controller.playback_speed
) - self.offset
await self.skip(time_to_next, next_segment["end"], next_segment["UUID"]) await self.skip(time_to_next, next_segment["end"], next_segment["UUID"])
# Skips to the next segment (waits for the time to pass) # Skips to the next segment (waits for the time to pass)
async def skip(self, time_to, position, uuids): async def skip(self, time_to, position, uuids):
await asyncio.sleep(time_to) await asyncio.sleep(time_to)
self.logger.info("Skipping segment: seeking to %s", position) self.logger.info("Skipping segment: seeking to %s", position)
await asyncio.create_task(self.api_helper.mark_viewed_segments(uuids)) await asyncio.gather(
await asyncio.create_task(self.lounge_controller.seek_to(position)) asyncio.create_task(self.lounge_controller.seek_to(position)),
asyncio.create_task(self.api_helper.mark_viewed_segments(uuids)),
)
async def cancel(self): async def cancel(self):
self.cancelled = True self.cancelled = True

View File

@@ -25,6 +25,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
self.auth.lounge_id_token = None self.auth.lounge_id_token = None
self.api_helper = api_helper self.api_helper = api_helper
self.volume_state = {} self.volume_state = {}
self.playback_speed = 1.0
self.subscribe_task = None self.subscribe_task = None
self.subscribe_task_watchdog = None self.subscribe_task_watchdog = None
self.callback = None self.callback = None
@@ -59,6 +60,7 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
return self.subscribe_task return self.subscribe_task
# Process a lounge subscription event # Process a lounge subscription event
# skipcq: PY-R1000
def _process_event(self, event_type: str, args: List[Any]): def _process_event(self, event_type: str, args: List[Any]):
self.logger.debug(f"process_event({event_type}, {args})") self.logger.debug(f"process_event({event_type}, {args})")
# (Re)start the watchdog # (Re)start the watchdog
@@ -155,6 +157,11 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
elif event_type == "onAutoplayModeChanged": elif event_type == "onAutoplayModeChanged":
create_task(self.set_auto_play_mode(self.auto_play)) create_task(self.set_auto_play_mode(self.auto_play))
elif event_type == "onPlaybackSpeedChanged":
data = args[0]
self.playback_speed = float(data.get("playbackSpeed", "1"))
create_task(self.get_now_playing())
super()._process_event(event_type, args) super()._process_event(event_type, args)
# Set the volume to a specific value (0-100) # Set the volume to a specific value (0-100)
@@ -186,6 +193,9 @@ class YtLoungeApi(pyytlounge.YtLoungeApi):
async def play_video(self, video_id: str) -> bool: async def play_video(self, video_id: str) -> bool:
return await self._command("setPlaylist", {"videoId": video_id}) return await self._command("setPlaylist", {"videoId": video_id})
async def get_now_playing(self):
return await super()._command("getNowPlaying")
# Test to wrap the command function in a mutex to avoid race conditions with # Test to wrap the command function in a mutex to avoid race conditions with
# the _command_offset (TODO: move to upstream if it works) # the _command_offset (TODO: move to upstream if it works)
async def _command(self, command: str, command_parameters: dict = None) -> bool: async def _command(self, command: str, command_parameters: dict = None) -> bool: