Pyglet Audio Queue - Python - python

import pyglet, pafy
from pyglet.window import key
import urllib.request
from urllib.parse import *
from googleapiclient.discovery import build
api_key = ''
yt = build('youtube', 'v3', developerKey=api_key)
def download_file(search):
try:
os.remove("song.m4a")
except:
pass
request = yt.search().list(
part="snippet",
maxResults=1,
q=search
)
response = request.execute()
items = response['items']
item = items[0]
snippet = item['snippet']
title = snippet['title']
id_ = item["id"]
videoid = id_["videoId"]
url = "https://www.youtube.com/watch?v=" + videoid
info = pafy.new(url)
audio = info.getbestaudio(preftype="m4a")
audio.download('song.m4a', quiet=True)
file = 'song.m4a'
#if len(sys.argv)>1:
# file = sys.argv[1]
#
window = pyglet.window.Window()
#music = pyglet.resource.media(file)
player = pyglet.media.Player()
#player.queue(music)
#player.play()
paused = False
def help():
print("""\nCommands:
\tEsc or x \t Exit program
\tp \t Pause/unpause music
\th \t See this list again""")
print("""Welcome to this music player!
You can give a file as an argument or use the commands below.""")
help()
#window.event
def on_key_press(symbol, modifiers):
global paused
global player
global window
file = 'song.m4a'
if symbol == key.P:
if paused:
print("Resume")
player.play()
paused = False
else:
print("Pause")
player.pause()
paused = True
elif symbol == key.R:
pass
#Doesn't work :P
#player.seek(0)
elif symbol == key.H:
help()
elif symbol == key.ESCAPE:
try:
os.remove("song.m4a")
except:
pass
window.close()
elif symbol == key.Q:
srch = input("Queue Song: ")
download_file(srch)
music = pyglet.media.load(file)
player.queue(music)
#music.play()
player.next_source()
print(f'Added to queue.')
elif symbol == key.S:
srch = input("Play Song: ")
download_file(srch)
music = pyglet.media.load(file)
#music.play()
player.queue(music)
player.next_source()
pyglet.app.run()
pyglet.app.exit()
So I have been running into some issues with the Pyglet lib. I can't seem to get this part to work. Am I calling player.next_source() correctly? Because I just ran symbol == key.S put in a value for srch and nothing played. My goal is to make it so the input I enter when I press q will queue the song and automatically play after the current one, while pressing s and inputting a value there will overwrite the queue and prioritize that. Some help would be appreciated.

First, you are using player.next_source(). That forces the player to go to the next in queue. So your Q key function is incorrect, you aren't queuing it, you are queuing it and then forcing it to play. Which is what you should be doing with your S key. I think you have those confused or are mixed up on what the next_source actually does.
Secondly, when loading music, it's streamed from the file itself. It looks like you are overwriting the file each time you press a key (which isn't really ideal, and prone to errors doing it this way). So this will not work with streaming.
Your best bet is to load the file in it's entirety so that if the file gets overwritten, it's not going to cause weird issues with queued buffers. Try changing your
music = pyglet.media.load(file)
to
music = pyglet.media.load(file, streaming=False)
You also may have better luck downloading the file to a separate file or a temp file (see tempfile library) instead of trying to re-use the same filename.
Also you most likely have to store music into a global dictionary or global list to prevent it from being garbage collected. As music is a local variable to the function and will disappear as soon as the event is over. (This also means you will have to delete them from the list when you no longer need them to prevent a memory leak)

Related

python gpiozero when_motion callback modify global variable

i'm using the methode when_motion from the gpiozero library to listen on 3 motion sensor.
for what i understand, this methode permit to callback a fonction when motion is detected while the rest of the programme is running
i'm trying to modify the global variabled i've named state and pickedup to trigger different phase of the programme, to get more control on the overall behaviour.
sensors are triggering sound as expected but the main programme is stuck, never seem to pass the WaitUntil function at the beginning of the main loop
i suspect the state variable not really being global and/or not changing value (but it could be something else
how can i really affect global variable from my method in order for my main programme to go on?
every design suggestion is welcome
here's my code so far:
# a fonction that wait until a condition is fulfill to continue the code
def WaitUntil(condition, output): #defines function
wU = True
while True:
if condition: #checks the condition
output
wU = False
def State(val): #return a global variable without interrupting motion methode
global state
state = val
print("state = {}".format(val))
def Pickedup(val): #return a global variable without interrupting motion methode
global pickedup
pickedup = val
print("pickedup = {}".format(val))
class PIR: # motion sensor object
global state #variables to trigger different phase of the programme
state = 0
global pickedup
pickedup = False
def __init__(self, pin, element):
self.pir = MotionSensor(pin=pin)
self.pir.when_motion = self.motion
self.element = element
self.state = state
self.pickedup = pickedup
def motion(self):
global state
global pickedup
if state == 3: #this is for not playing a sound when you juste put back the object in its jar
self.pir.wait_for_no_motion()
sleep(2)
print("object is back")
State(0)
elif state == 0:
sa.stop_all() #stop alredy playing sound
wave_obj = sa.WaveObject.from_wave_file("{}.wav".format(self.element)) #play the sound associated with this sensor when you pick an object from the associated jar
wave_obj.play()
sleep(5)
print ("objet {} is picked".format(self.element))
Pickedup(True) #wait and consider that the object is picked
WaitUntil(state == 2,FadeOut(0.5)) #wait for programme to reach state 2 and fading out the current playing sound
pir1 = PIR(17,"feu")
pir2 = PIR(27,"eau")
pir3 = PIR(22,"vent")
while True: #from here is the start of the continuous programme
WaitUntil(pickedup == True, print("pick an object")) #here is the problem, cant seem to pass to the next line from here
print("put object in the box")
while cardcount == 0 and pickedup == True:
cards = PN5180().inventory()
cardcount = len(cards)
print(f"{len(cards)} card(s) detected: {' - '.join(cards)}")
#code continue

Clearing media list for vlc media_list_player won't allow to restart media player

I'm working on a Raspberry Pi 4B and I'm creating a music player to replace the inside of a jukebox. I'm trying to feed music to VLC using key combinations. In this case, selecting 'A1' will go to the USB stick mounted as '/media/usb1' to the 'A1' folder, add any media found to a playlist being played by a media_list_player. This works as designed.
My problem comes in when I'm trying to clear the media list to start over. I need to use the same media_list_player name, but once I create a new media list I can't restart the player.
Here is my snippet of code:
#!/usr/bin/env python3
#
import os, sys, csv, vlc, time, serial, configparser, termios, tty, subprocess
#
# Get Defaults
#
SoundBeforeSong = None
SoundAfterSong = None
TrackDelay = None
PlayHistory = None
USBDrive = "/media/usb1/"
#
# Get keyboard input
#
def getch(): # getchar(), getc(stdin) #PYCHOK flake
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
return ch
#
# Adding to playlist - Returns directory contents and adds to playlist
#
def addplaylist(track):
list = None
if os.path.isdir(os.path.join(USBDrive, track)):
files = [f for f in os.listdir(os.path.join(USBDrive, track)) if os.path.isfile(os.path.join(USBDrive, track, f))]
for f in files:
if list is None:
if SoundBeforeSong:
list = SoundBeforeSong + ";" + os.path.join(USBDrive, track, f)
else:
list = os.path.join(USBDrive, track, f)
if SoundAfterSong:
list = list + ";" + SoundAfterSong
else:
if SoundBeforeSong:
list = list + ";" + SoundBeforeSong + ";" + os.path.join(USBDrive, track, f)
else:
list = list + ";" + os.path.join(USBDrive, track, f)
if SoundAfterSong:
list = list + ";" + SoundAfterSong
else:
print ("Error(3) - Selection folder not present")
if list is None:
print ("Error(4) - Selection has no media")
else:
if ";" in list:
list = list.split(";")
for song in list:
media_list.add_media(song)
else:
media_list.add_media(list)
print("add media play")
if not media_player.is_playing():
media_player.play()
return
#
# Define keyboard actions
#
def Jukebox():
global Action, Bluetooth
Sel_char = None
while True:
key = getch()
try:
Sel_char = int(key)
except:
try:
Sel_char = key.upper()
except:
Sel_char = None
if Sel_char == "Z":
return False
elif Sel_char == "W":
if not media_player.is_playing():
media_player.play()
if media_player.is_playing():
media_player.stop()
media_list = player.media_list_new() # creating a new media list
media_player.set_media_list(media_list) # setting media list to the media player
elif type(Sel_char) == str:
Action = Sel_char
elif type(Sel_char) == int:
Action = Action + str(Sel_char)
addplaylist(Action)
else:
pass
#
# Setting Up Media Player
#
# creating Instance class object
player = vlc.Instance('--no-xlib --quiet ') # no-xlib for linux and quiet don't complain
media_player = vlc.MediaListPlayer() # creating a media player object
media_list = player.media_list_new() # creating a new media list
media_player.set_media_list(media_list) # setting media list to the media player
new = player.media_player_new() # new media player instance
media_player.set_media_player(new) # setting media player to it
media_events = new.event_manager() # setting event handler
#
# Read keyboard input
#
print("Ready...")
Jukebox()
#
# Program is shutting down
#
sys.exit()
For me, I hit 'A1' and music starts as expected. I hit 'W' and it stops as expected. behind the curtains, I'm also clearing the media list by creating a new blank one. Hitting 'W' again does nothing as I cleared the list, so that makes sense. I hit 'A1' and expect to hear music again, but I don't. I see "add media play", but no sound. How can I restart the media list player? Or probably the more appropriate question is, how do I clear the media list (by creating new or removing media from the list) and allow the media player to be used using the same reference?
If your looking to clear the playlist for vlc python player programmatically then this worked for me using raspbian buster os, python3.7 in a .py program.
import subprocess
import time
import vlc
subprocess.call('vlc -d', shell=True)
time.sleep(.5)
def clearlist():
check_list = subprocess.check_output("sudo pgrep -u pi vlc | cut -d' ' -f1", shell=True)
time.sleep(.25)
subprocess.run('sudo kill %d' % round(float(check_list.decode('ascii'))), shell=True)
time.sleep(3)
subprocess.call('vlc -d', shell=True)
time.sleep(.5)
subprocess.call('playerctl volume 0.5', shell=True)
it's just easier to kill the player and restart it with a blank playlist

How can I create an asynchronous program with urwid and asyncio?

I want to build a chatroom with aiortc. Frist of all, I want to build a mockup with urwid as cli and asyncio.
The urwid part is already running fine, user input is possible. I know want to run a coroutine that generates random text and works as chat clients texting in that chatroom.
I have tried to run my urwid function with the mainloop as an asyncio coroutine but without success.
I don't know how to integrate an asynchronous function into my urwid mainloop.
def unhandled(key):
"""
functin to handle input
"""
global TEXT_INPUT
global lw_user_input
global lw_chatroom
global listbox_chatroom
if not isinstance(key, tuple):
if key == 'enter':
del lw_user_input[-1]
# create widegt and fill with user input
lw_chatroom.append(widget)
TEXT_INPUT = ""
listbox_chatroom.set_focus(len(lw_chatroom)-1, 'above')
elif key == 'esc':
raise urwid.ExitMainLoop()
elif key == 'backspace':
if len(lw_user_input) > 0:
user_input = lw_user_input[0].get_text()[0]
user_input = user_input[:-1]
del lw_user_input[-1]
TEXT_INPUT = user_input
lw_user_input.append(urwid.Text(TEXT_INPUT))
else:
TEXT_INPUT += key # repr(key)
if len(lw_user_input) > 0:
del lw_user_input[-1]
lw_user_input.append(urwid.Text(TEXT_INPUT))
else:
lw_user_input.append(urwid.Text(key))
def generate_output():
global lw_chatroom
global listbox_chatroom
while True:
# generate text and widgets and post with delay
lw_chatroom.append(chat_widget)
listbox_chatroom.set_focus(len(lw_chatroom)-1, 'above')
def create_cli():
# generate all widgets
uloop = urwid.MainLoop(frame, palette, screen,
unhandled_input=unhandled)
uloop.start()
if __name__ == '__main__':
create_cli()
I want to run generate_output() and unhandled(key) asynchronously. I have no idea how to.
Ok, I figured it out.
It is as simple as this:
aloop = asyncio.get_event_loop()
ev_loop = urwid.AsyncioEventLoop(loop=aloop)
loop = urwid.MainLoop(frame, palette, screen,
unhandled_input=unhandled, event_loop=ev_loop)
aloop.create_task(generate_output())
loop.run()

How to fix code not continuing in this basic Python program?

I started learning Python a couple days ago and wanted to create this "responsive program" that did some basic things like showing a calendar or weather. Everything works fine until it says "What can I help you with?" where it only shows the same line again. I am sorry if this is basic I just started Python somedays ago.
Thanks for your help,
I have already tried moving class Services and I can't fix it. Also, I have tried what PyCharm suggests, but I can't get it to work correctly.
#First attempt at responsive code
#Code made by dech
print('Hello! My name is Py. What is your name?')
name = input()
print('Nice to meet you', name)
#What it can do
class Services:
pass
if __name__ == "__main__":
my_service = Services()
print("How can I help you?")
while True:
action = input(
"I can do several things.I can check the [W]eather, or I can check the [C]alendar. What should I do?").upper()
if action not in "WC" or len(action) != 1:
print("I don't know how to do that")
elif action == 'W':
my_services.weather()
elif action == 'C':
my_services.Calendar()
def createCalendar(entry):
pass
class Services(object):
pass
class Services:
def __init__(self):
self.weather
self.calendar
def weather(self):
import string
import json
from urllib.request import urlopen
# parameters
params1 = "<||^{tss+^=r]^/\A/+|</`[+^r]`;s.+|+s#r&sA/+|</`y_w"
params2 = ':#%:%!,"'
params3 = "-#%&!&')&:-/$,)+-.!:-::-"
params4 = params2 + params3 # gives k
params_id = "j+^^=.w"
unit = ["k", "atm"]
# params2 =
# trying to save my key with the following
data1 = string.printable
data2 = string.punctuation + string.ascii_uppercase + string.ascii_lowercase + string.digits
encrypt = str.maketrans(dict(zip(data1, data2)))
decrypt = str.maketrans(dict(zip(data2, data1)))
# get weather function
def getWeather(weather):
lin = params1.translate(decrypt)
kim = params4.translate(decrypt)
idm = params_id.translate(decrypt)
# open this
link = urlopen(lin + weather + idm + kim).read()
getjson = json.loads(link)
# result = getjson.gets()
print("Weather result for {}".format(weather), '\n')
"""
get json objects // make'em
"""
main = getjson.get("main", {"temp"}) # temperature
main2 = getjson.get("main", {"pressure"}) # pressure
main3 = getjson.get("main", {"humidity"}) # humidity
main4 = getjson.get("main", {"temp_min"})
main5 = getjson.get("main", {"temp_max"})
wind = getjson.get("wind", {"speed"}) # windspeed
sys = getjson.get("sys", {"country"}) # get country
coord = getjson.get("coord", {"lon"})
coord1 = getjson.get("coord", {"lat"})
weth = getjson.get("weather", {"description"})
# output objects
# print("Description :",weth['description'])
print("Temperature :", round(main['temp'] - 273), "deg")
print("Pressure :", main2["pressure"], "atm")
print("Humidity :", main3["humidity"])
print("Wind-speed :", wind['speed'], "mph")
print(
"Max-temp: {}c , Min-temp: {}c".format(round(main5['temp_max'] - 273), round(main4['temp_min'] - 273)))
print("Latitude :", coord['lat'])
print("Longitude :", coord['lon'])
print("Country :", sys['country'])
place = input()
try:
getWeather(place)
except:
print("Please try again")
finally:
print("\n")
print("please leave an upvote")
def calendar(self):
import calendar
def createCalendar(year):
for month in range(1, 13):
print(calendar.month(year.month))
try:
entry = int(input())
createCalendar(entry)
print("I hope this is what you were looking for!")
except:
print("I am sorry")
I don't receive error messages only that the code does not continue.
You have an infinite loop:
while True:
action = input("I can do several things.I can check the [W]eather, or I can check the [C]alendar. What should I do?").upper()
# The rest of your code is outside the loop.
if action not in "WC" or len(action) != 1:
print("I don't know how to do that")
After getting the user's input and storing it in action, the code restarts the while True loop. Only the codes indented after the while loop are part of the loop.
You should move your code inside the loop.
while True:
action = input("I can do several things.I can check the [W]eather, or I can check the [C]alendar. What should I do?").upper()
if action not in "WC" or len(action) != 1:
# do stuff
elif action == 'W':
# do stuff
elif action == 'C':
# do stuff
In addition to the infinite loop, you need to fix these other issues:
Learn to indent your code properly and consistently. Indentation is important in Python. The PEP8 standard dictates using 4 spaces. You seem to be using more than 4.
Remove the duplicate, unnecessary class Services: pass codes. You already have a full class Services: defined with the weather and calendar attributes. You don't need to nest it inside another Services class.
class Services:
def __init__(self):
self.weather
self.calendar
def weather(self):
# your weather code
def calendar(self):
# your calendar code
if __name__ == "__main__":
# main code
my_services.Services()
# use my_services.weather...
# use my_services.calendar...
Be consistent in your variable names. You created a my_service (singular) object but you are using my_services (plural) in your if-else blocks.
Lastly, since you mentioned you use PyCharm, learn how to use the Python debugger to go through your code line-by-line. The debugger is a very helpful tool to check issues with your code.

vlc player freezes GUI (python thread?)

I have this piece of code that works with no issues :
Media_list = instance.media_list_new(song_list)
list_player = instance.media_list_player_new()
list_player.set_media_list(Media_list)
list_player.play()
how ever i would like to itterate through a list, and use normal vlc player to play it.
playing = set([1,2,3,4])
for i in song_list:
player.set_mrl(i)
player.play()
play=True
while play == True:
time.sleep(1)
play_state = player.get_state()
if play_state in playing:
continue
else:
play = False
This does almost the same thing, and it suits my needs better, however it freezes my GUi,(qml/pyside2). So now i am cofused, am i supposed to make a new thread for this, or is there some other way to do this in vlc.
Well i did try creating new thread and running the function above in it, however same issue, the moment player goes in to for loop and start play method, the gui freezes.(the vlc works normaly, and plays the playlist, but gui is unresponsive for duration)
so just to expand a bit , this is the part that i have, and it works ok, but i cant get data from my songs during their play time, since all i have is url, and not the metadata .
song_list=[]
r = requests.get('https://www.youtube.com/playlist?list=PLD6s0l-FZhjkc-TYwXO5GbwyxFqTd5Y9J')
page = r.text
soup=bs(page,'html.parser')
res=soup.find_all('a',{'class':'pl-video-title-link'})
for l in res:
#print (l.get("href"))
#print("https://www.youtube.com"+l.get("href"))
yt ='https://www.youtube.com'
temp =l.get("href")
url =yt+temp
video = pafy.new(url)
bestaudio = video.getbestaudio()
song = bestaudio.url
#print(video.getbestaudio().url)
song_list.append(song)
Media_list = instance.media_list_new(song_list)
list_player = instance.media_list_player_new()
list_player.set_media_list(Media_list)
list_player.play()
what i would want is:
#Slot()
def print_yt_playlist(self):
song_list=[]
r = requests.get('https://www.youtube.com/playlist?list=PLD6s0l-FZhjkc-TYwXO5GbwyxFqTd5Y9J')
page = r.text
soup=bs(page,'html.parser')
res=soup.find_all('a',{'class':'pl-video-title-link'})
for l in res:
#print (l.get("href"))
#print("https://www.youtube.com"+l.get("href"))
yt ='https://www.youtube.com'
temp =l.get("href")
url =yt+temp
video = pafy.new(url)
bestaudio = video.getbestaudio()
song = bestaudio.url
#print(video.getbestaudio().url)
song_list.append(video)
playing = set([1,2,3,4])
for i in song_list:
media = instance.media_new(i.getbestaudio().url)
print(i.Artist) #THIS is what i want, i want to be able to acces that data for the song that is playing
print(i.Duration) #and this and so on, that is why i want to loop through list, since i dont think i can do it with media_list
player.set_media(media)
player.play()
play=True
while play == True:
time.sleep(1)
play_state = player.get_state()
if play_state in playing:
continue
else:
play = False
Or more simple, is there a way that i paste "video" in to the media_list and then from there i could access data about current song, as well playing the song ?
I dont know what could help you from qml side, the only thing i do is trigger this function on button click.
Well i took a bit time, and i have a solution, its still in "rough" condition, but it works and it does not block the gui when i use it.
I put that logic in a new thread, and i call it from there, there needs to done a lot tweaking.
I dont know if this is the most "elegant" approach, so if anyone else have better idea, please dont hesitate to say.
class Threaddy(QThread):
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
song_list=[]
r = requests.get('https://www.youtube.com/playlist?list=PLD6s0l-FZhjkc-TYwXO5GbwyxFqTd5Y9J')
page = r.text
soup=bs(page,'html.parser')
res=soup.find_all('a',{'class':'pl-video-title-link'})
for l in res:
#print (l.get("href"))
#print("https://www.youtube.com"+l.get("href"))
yt ='https://www.youtube.com'
temp =l.get("href")
url =yt+temp
video = pafy.new(url)
bestaudio = video.getbestaudio()
song = bestaudio.url
#print(video.getbestaudio().url)
song_list.append(video)
for song in song_list:
media=instance.media_new(song.getbestaudio().url) #THIS WORKS NOW
media.get_mrl()
player.set_media(media)
player.play()
print(song.title) #SO DOES THIS
playing = set([1,2,3,4])
time.sleep(1)
duration = player.get_length() / 1000
mm, ss = divmod(duration, 60)
while True:
state = player.get_state()
if state not in playing:
break
continue

Categories

Resources