pyatv icon indicating copy to clipboard operation
pyatv copied to clipboard

End Credits

Open lorenzoCuevas opened this issue 2 years ago • 4 comments

What do you need help with?

Hi,

The last time we talked I had a question about dimming the lights up when the end credits starts rolling. And you suggested to use Asyncio call_later or call_at to check playback time. I wonder if you could give me an example on how to implement it on my code or give me a link on how to implement it since I'm also currently learning the basics of python and I could not find a lot of clear examples online. Here is my code currently:

async def dim_up():
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, lifx. lifxDimUp)

async def dim_down():
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, lifx. lifxDimDown)

class MyPushListener(PushListener):
    def playstatus_update(self, updater, playstatus):
         if playstatus.device_state == playstatus.device_state.Paused:
            print("Paused")
            asyncio.create_task(dim_up())
         elif playstatus.device_state == playstatus.device_state.Playing:
            print("Playing")
            asyncio.create_task(dim_down())
         elif playstatus.device_state == playstatus.device_state.Idle:
            print("stop")
            asyncio.create_task(dim_up())

    def playstatus_error(self, updater, exception):
        print("Got an exception:", exception)

lorenzoCuevas avatar Jan 09 '22 05:01 lorenzoCuevas

The easy solution is to create a background task the polls current media state every second or so and dim up whenever you reach the end credit condition. Generally it would look something like this (purely pseudo code):

import asyncio
from pyatv.const import DeviceState

def is_end_credits(status):
    # Implement condition as to when "end credits" are showing here. The example here
    # corresponds to if 90% of what is playing has been reached.
    return status.position >= 0.9 * status.total_time

# This should run as a task and started whenever connected to a device (and stopped when disconnected)
async def watch_for_end_credits(atv):
    while True:
        # TODO: Error handling if something fails or if device disconnects
        status = await atv.metadata.playing()
        if status.device_state == DeviceState.Playing and is_end_credits(status):
            # TODO: Do not dim up if already dimmed up
            await dim_up()
        await asyncio.sleep(1)

atv = pyatv.connect(...)

# Start this task whenver
task = asyncio.create_task(watch_for_end_credits(atv))
...
# TODO: Cancel task when device disconnects
task.cancel()

Not tested or anything, but general structure should be OK. A more optimized version would be to calculate when the end credits would occur and sleep until then, but that would require a lot more work since you need to abort in case media played is stopped/paused/something else. So this is a lot easier.

postlund avatar Jan 19 '22 11:01 postlund

Okay I'll try this one out, I'll comment back if I have anymore issues.

lorenzoCuevas avatar Jan 24 '22 01:01 lorenzoCuevas

Hi, So for the total time of the playback for the movie, do you use hours or seconds to calculate it? if so could you show me an example of how you would write it in code?

lorenzoCuevas avatar Feb 05 '22 06:02 lorenzoCuevas

Everything is in seconds, so no need to re-calculate anything.

postlund avatar Feb 05 '22 08:02 postlund

Will close due to inactivity, let me know if you need additional help

postlund avatar Jul 13 '23 08:07 postlund