Criando uma Skill para a Amazon Alexa

Manipulando eventos do player da Alexa

Como citado nos posts anteriores da série, ao ativar o AudioPlayer da Alexa, ela fornece alguns intents específicos para a obtenção do estado da execução. De modo geral, na skill da EximiaCo, utilizamos estes intents para duas tarefas principais: atualizar o estado de reprodução do episódio atual e gerenciar o playback contínuo de episódios.

import ask_sdk_core.utils as ask_utils

from .player import Player
from ask_sdk_core.dispatch_components import AbstractRequestHandler


class PlaybackStartedHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        return ask_utils.is_request_type("AudioPlayer.PlaybackStarted")(handler_input)

    def handle(self, handler_input):
        player = Player(handler_input)
        player.handle_playback_started()

        return handler_input.response_builder.response


class PlaybackNearlyFinishedHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        return ask_utils.is_request_type("AudioPlayer.PlaybackNearlyFinished")(handler_input)

    def handle(self, handler_input):
        player = Player(handler_input)
        player.handle_playback_nearly_finished()

        return handler_input.response_builder.response


class PlaybackStoppedHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        return ask_utils.is_request_type("AudioPlayer.PlaybackStopped")(handler_input)

    def handle(self, handler_input):
        player = Player(handler_input)
        player.handle_playback_stopped()

        return handler_input.response_builder.response


class PlaybackFinishedHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        return ask_utils.is_request_type("AudioPlayer.PlaybackFinished")(handler_input)

    def handle(self, handler_input):
        player = Player(handler_input)
        player.handle_playback_finished()

        return handler_input.response_builder.response

Com o intent AudioPlayer.PlaybackStarted, armazenamos o episódio em execução atual, para que, posteriormente, ele possa ser recuperado durante as possíveis modificações no estado do playback.

def handle_playback_started(self):
    current_token = self.handler_input.request_envelope.request.token
    self.state.set_token(current_token)
    self.state.set_current_episode(current_token)

No intent AudioPlayer.PlaybackNearlyFinished, a Alexa está informando que o episódio está perto do final, dando a possibilidade de definir o próximo episódio a ser executado. É importante reforçar a utilização do token ao enfileirar o episódio. Quando é iniciada a reprodução, é informado o token da execução atual e também o token esperado da execução anterior, para garantir a ordem da reprodução. Caso o token anterior informado não coincida com o existente no episódio anterior (ou o atual, caso não tenha finalizado a reprodução), a diretiva PlayDirective é ignorada.

def handle_playback_nearly_finished(self):
     current_episode = self.state.get_current_episode()
     if current_episode is None:
         return

     previous_episode = current_episode

     if not self.state.get_repeat():
         previous_episode = self.episodes_provider.get_previous(current_episode)

     if previous_episode is None and self.state.get_loop():
         previous_episode = self.episodes_provider.get_latest()

     if previous_episode is None:
         return

     self.handler_input.response_builder.add_directive(
         PlayDirective(
             play_behavior=PlayBehavior.ENQUEUE,
             audio_item=AudioItem(
                 stream=Stream(
                     token=previous_episode["pub"],
                     url=previous_episode["address"],
                     offset_in_milliseconds=0,
                     expected_previous_token=current_episode["pub"]),
                     metadata=None))
         ).set_should_end_session(True)

Quando a execução do episódio é cancelada com um comando como “Pare”, ou “Cancelar”, é invocado o intent AudioPlayer.PlaybackStopped. Neste intent, armazenamos o offset do episódio que está sendo reproduzido. Isto possibilita que a Alexa retome a reprodução do episódio quando for solicitado que ela continue a reprodução.

def handle_playback_stopped(self):
    millis = self.handler_input.request_envelope
.request.offset_in_milliseconds
    self.state.set_offset(millis)

Ao finalizar o episódio, a Alexa invoca o intent AudioPlayer.PlaybackFinished. Neste momento, apenas zeramos o offset do playback. Isso faz com que, ao iniciar um novo episódio, a Alexa comece a reprodução do início, e não do offset supostamente armazenado no estado da execução.

def handle_playback_finished(self):
    self.reset()

Nesta etapa, a skill está pronta. No próximo post da série, falaremos sobre o seu processo de publicação.

Para quem acompanha os drops da EximiaCo, ou para aqueles que irão acompanhar, a nossa skill está disponível no Marketplace da Alexa. Gostaríamos muito de conhecer a sua opinião.

Douglas Picolotto

Sou arquiteto de software, desenvolvedor, apaixonado por tecnologias, metodologias e padrões. Tenho mais de 15 anos de experiência, sempre em empresas que desenvolvem software de vanguarda. Sou apaixonado por Cloud Computing e sou especialista em tecnologias da Amazon.

Talvez você goste também

Carregando posts…

Mais posts da série Criando uma Skill para a Amazon Alexa

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *