Input_text / Alexa Intent => youtube search => media_player

I have seen a lot of topics about youtube search and having the results play on a media player but couldn’t find a complete project. I created this python script that will take a search topic as an input and put the url from the first search result from youtube video into a input_text. I then get HA to automate the playing of the url on the media player when the input text changes. I used media extractor to play the urls on the media player.

shell_command:
  youtube: /Library/Frameworks/Python.framework/Versions/3.6/bin/python3 /Users/xxxx/.homeassistant/youtube.py --q="{{ states.input_text.youtubesearch.state  }}"

automation music:
  alias: music
  trigger:
    - platform: state
      entity_id: input_text.youtube
  action:
    - service:  media_player.volume_set
      data:
        entity_id: media_player.speaker
        volume_level: 1
    - service: media_extractor.play_media
      data_template:
        entity_id: media_player.speaker
        media_content_id: "{{  states.input_text.youtube.state }}"
        media_content_type: 'music'

youtube.py

from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.tools import argparser
import time

import argparse
import requests
import simplejson as json


# This sample executes a search request for the specified search term.
# NOTE: To use the sample, you must provide a developer key obtained
#       in the Google APIs Console. Search for "REPLACE_ME" in this code
#       to find the correct place to provide that key..


from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps
# tab of
#   https://cloud.google.com/console
# Please ensure that you have enabled the YouTube Data API for your project.
DEVELOPER_KEY = 'dfgdfdfgfdg'
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"



def get_at(list, index, default=None):
  return list[index] if max(~index, index) < len(list) else default

def youtube_search(options):
  youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
    developerKey=DEVELOPER_KEY)

  # Call the search.list method to retrieve results matching the specified
  # query term.
  search_response = youtube.search().list(
    q=options.q,
    part="id,snippet",
    maxResults=2,
    type="video",
    order="viewCount",
    videoDefinition="high",
 ).execute()
    
  videos_id = []
  videos_title = []
  channels = []
  playlists = [] 

  # Add each result to the appropriate list, and then display the lists of
  # matching videos, channels, and playlists.
  for search_result in search_response.get("items", []):
    if search_result["id"]["kind"] == "youtube#video":
      videos_title.append("%s" % (search_result["snippet"]["title"]))
      videos_id.append("%s" % (search_result["id"]["videoId"]))

        
 # put the url into the input text, change this to [1] for second result videos_id[0]}
    
  url = "http://192.168.2.181:8123/api/states/input_text.youtube"
  data = {"state": "https://www.youtube.com/watch?v="+videos_id[0]}
  headers = {'Content-type': 'application/json'}
  r = requests.post(url, data=json.dumps(data), headers=headers)
#





if __name__ == "__main__":
  argparser.add_argument("--q", help="Search term", default="Rome")
  argparser.add_argument("--max-results", help="Max results", default=2)
  args = argparser.parse_args()

  try:
    youtube_search(args)
  except HttpError as e:
    print ("An HTTP error %d occurred:\n%s" % (e.resp.status, e.content))
3 Likes

hi,
How do I install it?

You need to create a file called youtube.py with the above script and put it on the computer HA runs on. You can then execute the file with HA with the above shell command and it will put the youtube url into input_text.youtube for the above automation to watch.

This automation will watch for the input_text to change with a new search topic and execute the youtube.py script.

automation musicsearch:
  alias: music
  trigger:
    platform: state
    entity_id: input_text.youtubesearch
  action:
    - service: shell_command.youtube

Thank you for sharing. Regarding the media extractor, I never use media extractor component.

  1. Is it alright to use media_player.vlc , this media player attached the 3.5mm speaker of my ha and it is vlc-nox (no graphical for non desktop raspbian and hassbian?
  2. Regarding to the youtube.py the DEVELOPER_KEY = ‘dfgdfdfgfdg’ <== is this the api key, oAuth client ID or service account key?
  3. url = “http://192.168.2.181:8123/api/states/input_text.youtube” <== the ip is the local ha local ip or dns or base on base_url from http ?

Hope this helps

  1. I have a similar setup, to get the youtube url to play on the media player I had to use media extractor. The url won’t work without media extractor. All you have to do is add one media_extractor: to your config and then use its service to play.

  2. You need to get the key from google, its free and I used a gmail account login.
    https://developers.google.com/youtube/v3/getting-started

  3. This is the ip address of the HA with media player on it. It will put the youtube url into a input text on that HA. I use two HA’s so the one that does the search is different that the one that plays the url.

Thank you so much. I will try now.

Is this another automation needed? or only on your first post? also regarding the input_text.youtube

I have to create one inside right?

I created two automation but I think you could use one. The first one checks input_text.youtube which has the url and plays the url. The second one checks input_text.youtubesearch for new search terms and runs the script to create the url.

This is all in one automation. (I had two because its on two different HA’s for me) It might need a delay / wait so it gets a new url before playing.

automation musicsearch:
  alias: music
  trigger:
    platform: state
    entity_id: input_text.youtubesearch
  action:
    - service: shell_command.youtube
#might need a delay here so it gets a new url
    - service:  media_player.volume_set
      data:
        entity_id: media_player.speaker
        volume_level: 1
    - service: media_extractor.play_media
      data_template:
        entity_id: media_player.speaker
        media_content_id: "{{  states.input_text.youtube.state }}"
        media_content_type: 'music'

So I need to create 2 input_text, one is input_text.youtube and second is input_text.youtubesearch ?

Yes, sorry for not mentioning that.

  1. I have relocated the youtube.py to where I kept it and change the shell_command to the file directory but nothing happen.

    shell_command:
    youtube: /Library/Frameworks/Python.framework/Versions/3.6/bin/python3 /home/homeassistant/.homeassistant/youtube.py --q="{{ states.input_text.youtubesearch.state }}"

  2. I have create 2 input_text and put in a group to display on front end.

input_text:
  youtube:
    name: Youtube
    initial: Youtube
  youtubesearch:
    name: Youtube Search
    initial: Youtube Search

group:
  youtube:
  name: Youtube
  entities:
   - input_text.youtube
   - input_text.youtubesearch

automation:
  alias: music
  trigger:
  platform: state
  entity_id: input_text.youtubesearch
    action:
      - service: shell_command.youtube
      - service:  media_player.volume_set
        data:
          entity_id: media_player.ha_speaker
          volume_level: 1
      - service: media_extractor.play_media
        data_template:
          entity_id: media_player.ha_speaker
          media_content_id: "{{  states.input_text.youtube.state }}"
          media_content_type: 'music'

In youtube.py
I have change and put my api key,my ha local ip address

On frontend it loads normally the group I created. Once I put the text example ‘song name’ in the input_text.youtube (the service call) but nothing happened. Is there anything I have to change?

You should try to test youtube.py at command prompt The shell command I had has the location of python3 which is specific to my mac computer.

on your command prompt / terminal / ssh try

python3 /home/homeassistant/.homeassistant/youtube.py --q=“rolling stones”

if this changes the state of input_text.youtube in HA then this should probably work

shell_command:
youtube: python3 /home/homeassistant/.homeassistant/youtube.py --q="{{ states.input_text.youtubesearch.state }}"

you can also try pasting a youtube url into input_text.youtube to check if your media player will play it automatically.

No error. But I can’t get it to work. Maybe I don’t understand clearly,

input_text.youtube == is the result display example http://youtube… ?
input_text.youtubesearch == is where I put the search keyword or song name for youtube.py to generate the http link?
automation, I have only one HA to use so I use your below automation?

Yes, that is how it works. If you are sure youtube.py works (doesn’t give errors when run), then you can go to your browser and put the url you used in the python script.

I use this url . (your might be http://localhost:8123/api/states/input_text.youtube)

http://192.168.2.181:8123/api/states/input_text.youtube

from here in the python script above
url = "http://192.168.2.181:8123/api/states/input_text.youtube"

and put into a browser and what do you get? I get this

{"attributes": {}, "entity_id": "input_text.youtube", "last_changed": "2018-05-05T15:55:01.206930+00:00", "last_updated": "2018-05-05T15:55:01.206930+00:00", "state": "https://www.youtube.com/watch?v=RqcjBLMaWCg"}

This tell me that youtube.py worked and put the found youtube url into input_text.youtube. You can also tell by just putting input_text.youtube on your front end or looking on the state page.

If this is not there, we will need to determine why youtube.py isn’t working.

I ran the above script in a fresh pi and had to install some programs with these commands

to create the script

sudo nano youtube.py

to install dependancies

sudo pip3 install google-api-python-client
sudo pip3 install  simplejson

then i could run this

python3 youtube.py --q=“rolling stones”

and the state of input_text.youtube changed

I rewrote the youtube.py to give better search results and not rely on google api.

youtube.py

import time
import requests
import simplejson as json
import urllib.request
import urllib.parse
import re
from sys import argv

# get the youtube search results

search = argv[1].replace(" ", "+")
query_string = search
html_content = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + query_string)
search_results = re.findall(r'href=\"\/watch\?v=(.{11})', html_content.read().decode())
print("http://www.youtube.com/watch?v=" + search_results[0])

# put info into HA
  
url = "http://192.168.2.181:8125/api/states/input_text.youtube"
data = {"state": "http://www.youtube.com/watch?v=" + search_results[0]} 
headers = {'Content-type': 'application/json'}
r = requests.post(url, data=json.dumps(data), headers=headers)

I got error when run youtube.py from both files. whether with or without google api

Traceback (most recent call last):
File “youtube.py”, line 7, in
import requests <==
ModuleNotFoundError: No module named ‘requests’

try

sudo pip3 install requests

I have some error, i am vietnam
pi@hassbian:~ $ python3 /home/homeassistant/.homeassistant/youtube.py --q=“rollins”
Traceback (most recent call last):
File “/home/homeassistant/.homeassistant/youtube.py”, line 13, in
html_content = urllib.request.urlopen(“https://www.youtube.com/results?search_query=” + query_string)
File “/usr/lib/python3.5/urllib/request.py”, line 163, in urlopen
return opener.open(url, data, timeout)
File “/usr/lib/python3.5/urllib/request.py”, line 466, in open
response = self._open(req, data)
File “/usr/lib/python3.5/urllib/request.py”, line 484, in _open
‘_open’, req)
File “/usr/lib/python3.5/urllib/request.py”, line 444, in _call_chain
result = func(*args)
File “/usr/lib/python3.5/urllib/request.py”, line 1297, in https_open
context=self._context, check_hostname=self._check_hostname)
File “/usr/lib/python3.5/urllib/request.py”, line 1254, in do_open
h.request(req.get_method(), req.selector, req.data, headers)
File “/usr/lib/python3.5/http/client.py”, line 1107, in request
self._send_request(method, url, body, headers)
File “/usr/lib/python3.5/http/client.py”, line 1142, in _send_request
self.putrequest(method, url, **skips)
File “/usr/lib/python3.5/http/client.py”, line 984, in putrequest
self._output(request.encode(‘ascii’))
UnicodeEncodeError: ‘ascii’ codec can’t encode character ‘\u201c’ in position 30: ordinal not in range(128)

Sorry, I can’t help with that error. I would make sure you can reach youtube in a browser in Vietnam.

You can try other peoples apps.

thanks, i has write new code, it worked thanks for repllyed