【问题标题】:Alexa youtube skill in python flask-askpython flask-ask 中的 Alexa youtube 技能
【发布时间】:2018-07-09 12:42:42
【问题描述】:

我正在使用 Python 中的 flask-ask 框架来开发一个 Alexa-Skill,它只播放 YouTube 视频的音频流而不下载它。

因此我使用pafy

以下函数从 YouTube 视频中获取音频网址:

def get_audio():
    video = pafy.new("https://www.youtube.com/watch?v=ALdKl2HRSoI")
    bestaudio = video.getbestaudio(preftype="m4a")
    playurl = bestaudio.url
    return playurl

这个函数应该播放音频

@ask.intent('StoryIntent')
def story():
    speech = "I am starting to play the story"
    stream_url = get_audio("https://www.youtube.com/watch?v=ALdKl2HRSoI")
    return audio(speech).play(stream_url)

不幸的是,它不适用于我从 pafy 获得的网址。 Alexa什么也没玩。

我打印了从 pafy 获得的 url,它看起来像这样:

Pafy: Youtube-Audio URL

如果我使用stream_url 的以下 URL,一切正常:

Sample Audio-File on S3

我也尝试过: 我从“Pafy:Youtube-Audio URL”下载了音频文件并将其上传到 S3 并使用了 S3 的链接,一切正常。但我不想为我的方法下载 YouTube 视频。

【问题讨论】:

  • 我刚刚意识到 Pafy: Youtube-Audio URL 是一种视频格式。只有当我用 pafy 下载文件时,我才会得到音频格式。有没有办法在不使用 Stream.download() 函数的情况下获取音频文件的 url?

标签: python youtube alexa pafy flask-ask


【解决方案1】:

我知道这个问题已经很老了,但在过去的几天里我尝试了类似的东西,实际上我很沮丧,因为我花了很长时间才找到解决方案。所以也许我可以省去一些麻烦。

与 TO 类似,我尝试创建一个 Alexa Skill 来播放 Youtube 音频。这可以通过 pafy 完成,正如问题中所指出的,使用 bestaudio = video.getbestaudio()。由于我们不打算下载音频,因此无需指定格式。生成的链接将是 .webm 格式,但只有音频部分,可以通过在浏览器中打开链接进行测试。

这是这部分的代码示例:

import pafy

def get_audio(url):
    video = pafy.new(url)
    best = video.getbestaudio()
    return best.url

yt_url = "https://www.youtube.com/watch?v=iu7289s7l64"
audio_url = get_audio(yt_url)
print(audio_url)

这实际上对我来说在本地运行良好。但是,在将代码部署到 AWS Lambda 时,它不起作用。 Alexa 会报告请求的技能响应存在问题,而 CloudWatch 没有显示任何错误或日志输出。

这里有两件事需要注意:

  1. 确保库已打包并上传。 但是,这会在 CloudWatch Logs 中引发错误,并且在添加 pafy 和 youtube-dl 时使用新的 ASK CLI 2.x 时不会出现问题在 requirements.txt 中。在使用旧版本的 ASK CLI (1.x) 时,我遇到了问题,因为 requirements.txt 被忽略了。
  2. 在 AWS 控制台中增加 Lambda 函数的超时时间。 默认设置为 3 秒,在这种情况下很短。长视频的调用似乎最多需要 10 秒,为了安全起见,我将其设置为 30 秒。由于某种原因,这比本地调用需要的时间长得多(如果有人对此有见解,我会很好奇)。然而,这让我陷入了困境。

由于 TO 还询问如何调用音频流,这是我的解决方案:

class StoryIntent(AbstractRequestHandler):

    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_intent_name("StartPlayingIntent")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        yt_url = "https://www.youtube.com/watch?v=iu7289s7l64"
        url = get_audio(yt_url)
        return handler_input.response_builder.speak('I am starting to play the story').add_directive(
            PlayDirective(
                play_behavior=PlayBehavior.REPLACE_ALL,
                audio_item=AudioItem(
                    stream=Stream(
                        token=url,
                        url=url,
                        expected_previous_token=None),
                    metadata=None
                )
            )
        ).set_should_end_session(True)

我不确定在回答这个问题时上面的代码是否有效。到今天为止,基于类的意图很常见,所以我们开始吧。

tl:dr 增加 Lambda 函数的 Timeout,默认是短方式。

【讨论】:

    猜你喜欢
    • 2018-12-03
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 2020-06-24
    相关资源
    最近更新 更多