gmusicaiy
gmusicaiy copied to clipboard
AIY project update no action.py
Creating the issue since the AIY project has been updated and removed the action.py and main.py. Now the example code in the readme is out dated, I have attempted without testing to create a small example based on your code example and the assistant_library_with_local_commands_demo.py
from playscroll import Player
if text == 'play (your playlist)':
assistant.stop_conversation()
playlist = text.replace("play","").strip()
if Player.load_playlist(playlist) is not None:
aiy.audio.say("Playing " + playlist)
Player.start_playlist()
RPi.GPIO.setmode(RPi.GPIO.BCM)
RPi.GPIO.setup(23, RPi.GPIO.IN)
# Wait for button press to stop
while Player.playing and RPi.GPIO.input(23):
time.sleep(1)
Player.stop()`
There might be a better way to do it but as a quick example that is what I have come up with. Again I have not tested this but I don't see why it wouldn't work.
Thanks for raising this issue, hadn't realised the API had changed so radically. Hopefully I'll be able to find the time to grab the latest AIY image and check out the latest docs.
You probably need to remove any references to "scrollphat" if you don't have it connected to display the currently playing track.
Hope that helps.
On 5 November 2017 at 19:34, dougtran [email protected] wrote:
After enabling I2C, I now have the following error:
Traceback (most recent call last): File "src/aiy_music.py", line 34, in from playscroll import Player File "/home/pi/AIY-voice-kit-python/src/playscroll.py", line 10, in import scrollphat File "/usr/lib/python3/dist-packages/scrollphat/init.py", line 20, in controller = IS31FL3730(smbus, font) File "/usr/lib/python3/dist-packages/scrollphat/IS31FL3730.py", line 21, in init self.set_mode(self.i2cConstants.MODE_5X11)
File "/usr/lib/python3/dist-packages/scrollphat/IS31FL3730.py", line 62, in set_mode self.bus.write_i2c_block_data(self.i2cConstants.I2C_ADDR, self.i2cConstants.CMD_SET_MODE, [self.i2cConstants.MODE_5X11]) OSError: [Errno 121] Remote I/O error
— You are receiving this because you were assigned. Reply to this email directly, view it on GitHub https://github.com/Tom-Archer/gmusicaiy/issues/4#issuecomment-341998689, or mute the thread https://github.com/notifications/unsubscribe-auth/ARfAYzV-2wYQtrSUA3eW7AMpCFWp5t2tks5szg3DgaJpZM4QR653 .
Thank you, I realized that after I re-read the project README. I set the enable_display = False and that fixed that error. However, AIY still doesn't know what to do when I say "play {nameofsound}". Where should the code from joshfokis be inserted in the assistant_library_with_local_commands_demo.py file? Right now, I have the code as follows:
elif event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED and event.args:
print('You said:', event.args['text'])
text = event.args['text'].lower()
if text == 'power off':
assistant.stop_conversation()
power_off_pi()
elif text == 'reboot':
assistant.stop_conversation()
reboot_pi()
elif text == 'ip address':
assistant.stop_conversation()
say_ip()
elif text == 'play (your playlist)':
assistant.stop_conversation()
playlist = text.replace("play","").strip()
if Player.load_playlist(playlist) is not None:
aiy.audio.say("Playing " + playlist)
Player.start_playlist()
RPi.GPIO.setmode(RPi.GPIO.BCM)
RPi.GPIO.setup(23, RPi.GPIO.IN)
# Wait for button press to stop
while Player.playing and RPi.GPIO.input(23):
time.sleep(1)
Player.stop()
That code should be an elif statement after elif text == 'ip address':
That's what I did as shown in my above post.
Sorry I am replying on my phone but your problem is you will need to remove the (your playlist) from the equals statement and set a static playlist or use that to match the playlists in a list.
Aah, that make sense, I was wondering how the code work using the (your playlist) as an argument.
Ok, still not working. This is what I tried. in mpsyt, did a search and saved the playlist as music. Replaced (your playlist" with music, entire line reads.
elif text == 'play music':
When I say "play music", scripts crash and receive the following: TypeError: load_playlist() missing 1 required positional argument: 'name'
I assume I'm not creating the playlist correctly? This is also the first time I'm using mpsyt.
You need to pass a playlist and also Player expects your login info. I am testing this currently to get it to work also. I will update with once I get it going.
Ok, I'm getting two threads mixed up, one from "Play music from Youtube" by mikerr and this one for gmusicaiy. So the playlist, is the Google Music's playlist and need to edit playscroll.py with an actual Google account credentials?
So I got this working and this is what my local commands python file looks like
import logging
import subprocess
import sys
import aiy.assistant.auth_helpers
import aiy.audio
import aiy.voicehat
from google.assistant.library import Assistant
from google.assistant.library.event import EventType
import RPi.GPIO
import time
import playscroll
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)
def music(playlist):
player = playscroll.Player('email address', 'password', 'device id')
if player.load_playlist(playlist) is not None:
aiy.audio.say("Playing " + playlist)
player.start_playlist()
RPi.GPIO.setmode(RPi.GPIO.BCM)
RPi.GPIO.setup(23, RPi.GPIO.IN)
# Wait for button press to stop
while player.playing and RPi.GPIO.input(23):
time.sleep(1)
player.stop()
def power_off_pi():
...
def reboot_pi():
...
def say_ip():
...
def process_event(assistant, event):
status_ui = aiy.voicehat.get_status_ui()
if event.type == EventType.ON_START_FINISHED:
status_ui.status('ready')
if sys.stdout.isatty():
print('Say "OK, Google" then speak, or press Ctrl+C to quit...')
elif event.type == EventType.ON_CONVERSATION_TURN_STARTED:
status_ui.status('listening')
elif event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED and event.args:
print('You said:', event.args['text'])
text = event.args['text'].lower()
if text == 'power off':
assistant.stop_conversation()
power_off_pi()
elif text == 'reboot':
assistant.stop_conversation()
reboot_pi()
elif text == 'ip address':
assistant.stop_conversation()
say_ip()
elif text.split()[0] == 'play':
assistant.stop_conversation()
playlist = text.replace('play','').strip()
music(playlist)
elif event.type == EventType.ON_END_OF_UTTERANCE:
status_ui.status('thinking')
elif event.type == EventType.ON_CONVERSATION_TURN_FINISHED:
status_ui.status('ready')
elif event.type == EventType.ON_ASSISTANT_ERROR and event.args and event.args['is_fatal']:
sys.exit(1)
def main():
credentials = aiy.assistant.auth_helpers.get_assistant_credentials()
with Assistant(credentials) as assistant:
for event in assistant.start():
process_event(assistant, event)
if __name__ == '__main__':
main()
I ran a python shell to get the device ids that are in play music. Once I did that it worked without any issues. Hope this helps.
Thanks, this works! Any chance this can be adapted to play music that are not on the playlist like what mikerr did to play youtube?
@joshfokis You might not need to create an instance of the Player class every time the command is triggered. But otherwise, nice work!
@dougtran It certainly could be adapted, but it's unlikely to be something I have the time (or inclination) to do. Sorry!
Is there going to be an official update to the repo, or will we just use josh's code manually?
I noticed one flaw in this setup and have a quick dirty workaround. If you launch "okay google" but don't give it a response it will hit an error on the line: elif text.split()[0] == 'play': I added a new if to the top to catch a blank answer
if text == '': #Nothing was said but the player will want to still parse and fail aiy.audio.say('I did not hear you. can you repeat that') pass
i had a lot of errors thrown up trying these bits of code, editted together my own 99% working script, but it still crashes shortly after finding the playlist with a segmentation fault. any advice would be great.
import sys
sys.path.append('/home/pi/AIY-projects-python/src/examples/voice')
import logging
import platform
import subprocess
import sys
import playscroll
import time
import RPi.GPIO
from google.assistant.library.event import EventType
from aiy.assistant import auth_helpers
from aiy.assistant.library import Assistant
from aiy.board import Board, Led
from aiy.voice import tts
import aiy.voice.audio
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)
def music(playlist):
player = playscroll.Player('myemail', 'mypassword', 'adeviceid')
if player.load_playlist(playlist) is not None:
tts.say("Playing " + playlist)
player.start_playlist()
RPi.GPIO.setmode(RPi.GPIO.BCM)
RPi.GPIO.setup(23, RPi.GPIO.IN)
# Wait for button press to stop
while player.playing and RPi.GPIO.input(23):
time.sleep(1)
player.stop()
def power_off_pi():
...
def reboot_pi():
...
def say_ip():
...
def process_event(assistant, led, event):
logging.info(event)
if event.type == EventType.ON_START_FINISHED:
led.state = Led.BEACON_DARK # Ready.
print('Say "OK, Google" then speak, or press Ctrl+C to quit...')
elif event.type == EventType.ON_CONVERSATION_TURN_STARTED:
led.state = Led.ON # Listening.
elif event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED and event.args:
print('You said:', event.args['text'])
text = event.args['text'].lower()
if text == '': #Nothing was said but the player will want to still parse and fail aiy.audio.say('I did not hear you. can you repeat that')
pass
if text == 'power off':
assistant.stop_conversation()
power_off_pi()
elif text == 'reboot':
assistant.stop_conversation()
reboot_pi()
elif text == 'ip address':
assistant.stop_conversation()
say_ip()
elif text.split()[0] == 'play':
assistant.stop_conversation()
playlist = text.replace('play','').strip()
music(playlist)
elif event.type == EventType.ON_END_OF_UTTERANCE:
led.state = Led.PULSE_QUICK # Thinking.
elif (event.type == EventType.ON_CONVERSATION_TURN_FINISHED
or event.type == EventType.ON_CONVERSATION_TURN_TIMEOUT
or event.type == EventType.ON_NO_RESPONSE):
led.state = Led.BEACON_DARK # Ready.
elif event.type == EventType.ON_ASSISTANT_ERROR and event.args and event.args['is_fatal']:
sys.exit(1)
def main():
logging.basicConfig(level=logging.INFO)
credentials = auth_helpers.get_assistant_credentials()
with Board() as board, Assistant(credentials) as assistant:
for event in assistant.start():
process_event(assistant, board.led, event)
if __name__ == '__main__':
main()
im using the lastest aiy voicekit image
here's my slightly altered playscroll.py
import gmusicapi
#from gmusicapi import Mobileclient
import vlc
#from vlc import vlc.EventType, Instance
from threading import Thread
import json
import os.path
import time
#enable_display = False
#if enable_display:
# import scrollphat
# scrollphat.set_brightness(5)
class Player(object):
def __init__(self, email, password, device_id):
self.api = gmusicapi.Mobileclient()
self.vlc = vlc.Instance()
self.loaded_tracks = []
self.playing = False
self.thread_running = False
self.api.login(email, password, device_id)
if os.path.isfile("songs.json"):
# Load from file
print("Found songs data.")
with open('songs.json') as input_file:
self.song_library = json.load(input_file)
else:
self.song_library = self.api.get_all_songs()
# Save to file
with open('songs.json', 'w') as output_file:
json.dump(self.song_library, output_file)
def load_playlist(self, name):
name = name.strip().lower()
print("Looking for...", name)
if os.path.isfile("playlists.json"):
# Load from file
print("Found playlist data.")
with open('playlists.json') as input_file:
self.playlists = json.load(input_file)
else:
self.playlists = self.api.get_all_user_playlist_contents()
# Save to file
with open('playlists.json', 'w') as output_file:
json.dump(self.playlists, output_file)
self.loaded_tracks = []
for playlist_dict in self.playlists:
playlist_name = playlist_dict['name'].strip().lower()
if (playlist_name == name) or (name in playlist_name):
print("Found match...", playlist_dict['name'])
for track_dict in playlist_dict['tracks']:
self.loaded_tracks.append(track_dict)
return playlist_dict['name']
else:
print("Found...", playlist_dict['name'])
return None
def end_callback(self, event, track_index):
if track_index < len(self.loaded_tracks):
self.play_song(self.loaded_tracks[track_index])
event_manager = self.player.event_manager()
event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, self.end_callback, track_index + 1)
self.playing = True
else:
self.playing = False
def start_playlist(self):
if len(self.loaded_tracks) > 0:
self.play_song(self.loaded_tracks[0])
if len(self.loaded_tracks) > 1:
event_manager = self.player.event_manager()
event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, self.end_callback, 1)
def play_song(self, song_dict):
stream_url = self.api.get_stream_url(song_dict['trackId'])
self.player = self.vlc.media_player_new()
media = self.vlc.media_new(stream_url)
self.player.set_media(media)
self.player.play()
song_string = ""
if (song_dict['source'] == '2'):
song_string = self.get_song_details(song_dict)
else:
song_string = self.get_local_song_details(song_dict['trackId'])
print("Playing...",song_string)
# if enable_display:
# scrollphat.clear()
# scrollphat.write_string(" "*5+song_string)
# if not self.thread_running:
# thread = Thread(target=self.scroll_string)
# thread.start()
self.playing = True
def scroll_string(self):
self.thread_running = True
while self.thread_running:
scrollphat.scroll()
time.sleep(0.1)
def stop(self):
if self.player != None:
self.player.stop()
#if enable_display:
# scrollphat.clear()
self.thread_running = False
self.playing = False
def get_local_song_details(self, track_id):
for song_dict in self.song_library:
if track_id == song_dict['id']:
return song_dict['albumArtist']+" - "+song_dict['title']
def get_song_details(self, song_dict):
return song_dict['track']['albumArtist']+" - "+song_dict['track']['title']