Youtube app - play straight away

There is a great app made by @azogue that take the input text string and then passes the results of the search to the input select so a user can select a video to be played

But is there a way to remove the input select and just play the video with most view counts?

"""
A very simple Appdaemon app to query youtube videos with text from an
`input_text`, populate an `input_select` with the results obtained,
and play them in a Kodi `media_player` when selected.
You need a Youtube API Key to run the search!
The config needed to run this app:
```yaml
ytb_search:
  module: youtube_search
  class: YoutubeSearch
  input_select: input_select.youtube_videos
  input_text: input_text.q_youtube
  media_player: media_player.kodi
  youtube_key: 123456789012345678901234567890123456789
```
"""

import appdaemon.appapi as appapi
import requests


URL_BASE = 'https://www.googleapis.com/youtube/v3/search'
KODI_YOUTUBE_PLUGIN_MASK = "plugin://plugin.video.youtube/play/?video_id={}"
DEFAULT_ACTION = 'No video'

def query_youtube_videos(str_query, max_results=20, is_normal_query=True,
                         order_by_date=False, youtube_key=None):
    params = dict(order='date' if order_by_date else 'relevance',
                  part='snippet', key=youtube_key, maxResults=max_results)
    if is_normal_query:
        params.update({'q': str_query})
    else:
        params.update({str_query.split('=')[0].strip():
                       str_query.split('=')[1].strip()})

    data = requests.get(URL_BASE, params=params).json()
    found = []
    for item in data['items']:
        if item['id']['kind'] == 'youtube#video':
            found.append((item['id']['videoId'], item['snippet']['title']))
    return found


# noinspection PyClassHasNoInit
class YoutubeSearch(appapi.AppDaemon):
    """App that listens to the input text and select."""

    _ids_options = None
    _youtube_key = None

    _input_select = None
    _input_text = None
    _media_player = None

    def initialize(self):
        """Set up App."""
        self._input_select = self.args.get('input_select')
        self._input_text = self.args.get('input_text')
        self._media_player = self.args.get('media_player', 'media_player.kodi')
        self._youtube_key = self.args.get('youtube_key')
        self.listen_state(self.new_youtube_query, self._input_text)
        self.listen_state(self.video_selection, self._input_select)
        self._ids_options = {DEFAULT_ACTION: None}

    # noinspection PyUnusedLocal
    def new_youtube_query(self, entity, attribute, old, new, kwargs):
        """Query videos with input_text."""
        self.log('New youtube query with "{}"'.format(new))
        found = query_youtube_videos(new,
                                     max_results=20,
                                     is_normal_query=True,
                                     order_by_date=False,
                                     youtube_key=self._youtube_key)
        self.log('YOUTUBE QUERY FOUND:\n{}'.format(found))

        # Update input_select values:
        self._ids_options.update({name: v_id for v_id, name in found})
        labels = [f[1] for f in found]
        self.log('NEW OPTIONS:\n{}'.format(labels))
        self.call_service('input_select/set_options',
                          entity_id=self._input_select,
                          options=[DEFAULT_ACTION] + labels)

    # noinspection PyUnusedLocal
    def video_selection(self, entity, attribute, old, new, kwargs):
        """Play the selected video from a previous query."""
        self.log('SELECTED OPTION: {} (from {})'.format(new, old))
        try:
            selected = self._ids_options[new]
        except KeyError:
            self.error('Selection "{}" not in memory (doing nothing)'
                       .format(new), 'WARNING')
            return

        if selected:
            self.log('PLAY MEDIA: {} [id={}]'.format(new, selected))
            self.call_service(
                'media_player/play_media', entity_id=self._media_player,
                media_content_type="video",
                media_content_id=KODI_YOUTUBE_PLUGIN_MASK.format(selected))

yeah off course.

in the callback new_youtube_query you need to remove the part where the input_select is filled (call_service)
and add the part that is inside the videoselection for the first found.

but this app is still for AD 2.0, so if you run 3.0 then you need to update the app also.

1 Like

Wish i learned python at school :slight_smile: What if i set the max_results to 1 and then rewrite as you said?
Did i get correctly the merge?

def new_youtube_query(self, entity, attribute, old, new, kwargs):
    self.log('New youtube query with "{}"'.format(new))
    found = query_youtube_videos(new,
                                 max_results=20,
                                 is_normal_query=True,
                                 order_by_date=False,
                                 youtube_key=self._youtube_key)
    self.log('YOUTUBE QUERY FOUND:\n{}'.format(found))

    # Update input_select values:
    self._ids_options.update({name: v_id for v_id, name in found})
    labels = [f[1] for f in found]
    self.log('NEW OPTIONS:\n{}'.format(labels))
		
		#From the video_selection
    self.log('PLAY MEDIA: {} [id={}]'.format(new, selected))
    self.call_service(
        'media_player/play_media', entity_id=self._media_player,
        media_content_type="video",
        media_content_id=KODI_YOUTUBE_PLUGIN_MASK.format(selected))

you did get the right parts.
but in the first function the options for the select are gathered and put as a list in the variable labels.
then that variable is used to fill the input select.

in the second function in the first part the selected media is retrieved from the variable new and put in the variable selected which is used to send to the mediaplayer.

so i think the line

selected = self._ids_options[new]

is needed. but we have no variable new but we want the first 1 that normally would have been send to the input_select.
so the first 1 from the list labels (and in python the first 1 is 0)
so the line would be

selected = self._ids_options[labels[0]]

that line needs to go before the call service mediaplayer and then i think it should work.

i havent been to school for 30 years and only got to know about python 2 years ago.
the trick is to use google a lot and to start small :wink:
here is a good start to learn how to work with apps.

1 Like

So just go like this?

def new_youtube_query_best(self, entity, attribute, old, new, kwargs):
    """Query videos with input_text."""
    self.log('New youtube query with "{}"'.format(new))
    found = query_best_youtube_video(new,
                                 max_results=1,
                                 is_normal_query=True,
                                 order_by_date=False,
                                 youtube_key=self._youtube_key)
    self.log('YOUTUBE QUERY FOUND:\n{}'.format(found))
    self.log('SELECTED OPTION: {} (from {})'.format(new, old))
    selected = self._ids_options[labels[0]]
    self.log('PLAY MEDIA: {} [id={}]'.format(new, selected))
    self.call_service(
            'media_player/play_media', entity_id=self._media_player,
            media_content_type="video",
            media_content_id=KODI_YOUTUBE_PLUGIN_MASK.format(selected))

no now you did delete a lot that is needed.
what you had before was good with the extra line i gave you.

1 Like

@ReneTode BIG BIG thanks!

Some more fiddling and errors in log and now it’s working. I have done some renaming of the functions so it can work together with the original code from azogue

Now the only thing to figure out how to Pass the text from dialogflow to home assistant

And this will be a really cool feature… “Ok google watch something” and there you go. Tv fires up and plays…

Here is the fully working code in case someone stumbles upon this topic

"""
A very simple Appdaemon app to query youtube videos with text from an
`input_text`, populate an `input_select` with the results obtained,
and play them in a Kodi `media_player` when selected.
You need a Youtube API Key to run the search!
The config needed to run this app:
```yaml
ytb_search:
  module: youtube_searchbest
  class: YoutubeSearch_best
  input_text: input_text.q_youtube
  media_player: media_player.kodi
  youtube_key: 123456789012345678901234567890123456789
```
"""

import appdaemon.appapi as appapi
import requests


URL_BASE = 'https://www.googleapis.com/youtube/v3/search'
KODI_YOUTUBE_PLUGIN_MASK = "plugin://plugin.video.youtube/play/?video_id={}"
DEFAULT_ACTION = 'No video'

def query_best_youtube_video(str_query, max_results=20, is_normal_query=True,
                         order_by_date=False, youtube_key=None):
    params = dict(order='date' if order_by_date else 'relevance',
                  part='snippet', key=youtube_key, maxResults=max_results)
    if is_normal_query:
        params.update({'q': str_query})
    else:
        params.update({str_query.split('=')[0].strip():
                       str_query.split('=')[1].strip()})

    data = requests.get(URL_BASE, params=params).json()
    found = []
    for item in data['items']:
        if item['id']['kind'] == 'youtube#video':
            found.append((item['id']['videoId'], item['snippet']['title']))
    return found


# noinspection PyClassHasNoInit
class YoutubeSearch_best(appapi.AppDaemon):
    """App that listens to the input text and select."""

    _ids_options = None
    _youtube_key = None

    # _input_select = None
    _input_text = None
    _media_player = None

    def initialize(self):
        """Set up App."""
        # self._input_select = self.args.get('input_select')
        self._input_text = self.args.get('input_text')
        self._media_player = self.args.get('media_player', 'media_player.kodi')
        self._youtube_key = self.args.get('youtube_key')
        self.listen_state(self.new_youtube_query_best, self._input_text)
        # self.listen_state(self.video_selection_best, self._input_select)
        self._ids_options = {DEFAULT_ACTION: None}

    # noinspection PyUnusedLocal
    def new_youtube_query_best(self, entity, attribute, old, new, kwargs):
        self.log('New youtube query with "{}"'.format(new))
        found = query_best_youtube_video(new,
                                 max_results=20,
                                 is_normal_query=True,
                                 order_by_date=False,
                                 youtube_key=self._youtube_key)
        self.log('YOUTUBE QUERY FOUND:\n{}'.format(found))

    # Update input_select values:
        self._ids_options.update({name: v_id for v_id, name in found})
        labels = [f[1] for f in found]
        self.log('NEW OPTIONS:\n{}'.format(labels))
		
		#From the video_selection
        selected = self._ids_options[labels[0]]
        self.log('PLAY MEDIA: {} [id={}]'.format(new, selected))
        self.call_service(
            'media_player/play_media', entity_id=self._media_player,
            media_content_type="video",
            media_content_id=KODI_YOUTUBE_PLUGIN_MASK.format(selected))
2 Likes

i cant help you with the google part.
i have no GH and i dont use intents in HA
i communicate with alexa through appdaemon

i say “alexa ask AD to search for …”
and i get the top 6 videos on my dashboard and then i can chose which one to play.