core/homeassistant/components/media_extractor.py

102 lines
3.0 KiB
Python

"""
Decorator service for the media_player.play_media service.
Extracts stream url and sends it to the media_player.play_media
service.
"""
import logging
import os
from homeassistant.components.media_player import (
ATTR_MEDIA_CONTENT_ID, DOMAIN as MEDIA_PLAYER_DOMAIN,
MEDIA_PLAYER_PLAY_MEDIA_SCHEMA, SERVICE_PLAY_MEDIA)
from homeassistant.config import load_yaml_config_file
DOMAIN = 'media_extractor'
DEPENDENCIES = ['media_player']
REQUIREMENTS = ['youtube_dl==2017.7.2']
_LOGGER = logging.getLogger(__name__)
def setup(hass, config):
"""Set up the media_extractor service."""
descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__),
'media_player', 'services.yaml'))
def play_media(call):
"""Get stream url and send it to the media_player.play_media."""
media_url = call.data.get(ATTR_MEDIA_CONTENT_ID)
try:
stream_url = get_media_stream_url(media_url)
except YDException:
_LOGGER.error("Could not retrieve data for the url: %s",
media_url)
return
else:
data = {k: v for k, v in call.data.items()
if k != ATTR_MEDIA_CONTENT_ID}
data[ATTR_MEDIA_CONTENT_ID] = stream_url
hass.async_add_job(
hass.services.async_call(
MEDIA_PLAYER_DOMAIN, SERVICE_PLAY_MEDIA, data)
)
hass.services.register(DOMAIN,
SERVICE_PLAY_MEDIA,
play_media,
description=descriptions[SERVICE_PLAY_MEDIA],
schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA)
return True
class YDException(Exception):
"""General service exception."""
pass
def get_media_stream_url(media_url):
"""Extract stream url from the media url."""
from youtube_dl import YoutubeDL
from youtube_dl.utils import DownloadError, ExtractorError
ydl = YoutubeDL({'quiet': True, 'logger': _LOGGER})
try:
all_media_streams = ydl.extract_info(media_url, process=False)
except DownloadError:
# This exception will be logged by youtube-dl itself
raise YDException()
if 'entries' in all_media_streams:
_LOGGER.warning("Playlists are not supported, "
"looking for the first video")
try:
selected_stream = next(all_media_streams['entries'])
except StopIteration:
_LOGGER.error("Playlist is empty")
raise YDException()
else:
selected_stream = all_media_streams
try:
media_info = ydl.process_ie_result(selected_stream, download=False)
except (ExtractorError, DownloadError):
# This exception will be logged by youtube-dl itself
raise YDException()
format_selector = ydl.build_format_selector('best')
try:
best_quality_stream = next(format_selector(media_info))
except (KeyError, StopIteration):
best_quality_stream = media_info
return best_quality_stream['url']