Pyglet Audio Queue - Python

Viewed 226
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.

1 Answers

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