Reputation: 43
I am making a menu func which adds songs to the player.
def add_song():
song = filedialog.askopenfilename(initialdir='C:\\Users\\Soham\\Music', title="Choose a
song!",filetypes=(("mp3 Files", "*.mp3"), ))
song_name = song.split("/")[-1].split(".")[0]
song_list.insert(END, song_name)
Then afterwards I have a play button which is coded to play the song added -
play_button = Button(controls_frame, image=play_button_img,borderwidth=0, command = play)
play_button.grid(row=0,column=2,padx=5)
So, the func, play()
's code is -
def play():
song = song_list.get(ACTIVE)
pygame.mixer.music.load(song)
pygame.mixer.music.play(loops=0)
But here dong variable in play() is actually just the name of song as it is already split off in add_song().And pygame needs the entire path as the song is not in the same directory as the python file. So pygame cannot open and play the song resulting in the error -
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Soham\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line
1885, in __call__
return self.func(*args)
File "c:\Users\Soham\Desktop\HM MP.py", line 26, in play
pygame.mixer.music.load(song)
pygame.error: Couldn't open 'Avicii - The Nights'
So what can I do about this , is there another way where I can split off the path for displaying the song name creating no problems for pygame
to play the music??
Also, I am using Windows 10 Pro , high end machine and using Python 3.
Upvotes: 3
Views: 621
Reputation: 15098
Since you are inserting the song on to the list box and play it from there, what you could do is, make a dictionary of index starting from 0 as key and values as list of song name and path, so its something like like song_dict = {idx:[song_name,song_path]}
. So each idx will be your selection from the listbox. I have made an example with this, take a look:
from tkinter import *
from tkinter import filedialog
import pygame
root = Tk()
pygame.mixer.init()
song_dict = {} # Empty dict to assign values to it
count = 0 # An idx number to it increase later
def add_song():
global count
song_path = filedialog.askopenfilename(initialdir='C://Users//Soham//Music', title="Choose a song!",filetypes=(("mp3 Files", "*.mp3"), ))
song_name = song_path.split("/")[-1].split(".")[0]
song_dict[count] = [song_name,song_path] # Create the desired dictionary
song_list.insert(END, song_name) # Insert just the song_name to the Listbox
count += 1 # Increase the idx number
def play_song(*args):
idx = song_list.curselection()[0] # Get the index of the selected item
song = song_dict[idx][1] # Get the corresponding song from the dictionary
pygame.mixer.music.load(song) # Load the song
pygame.mixer.music.play(loops=0) # Play the song
song_list = Listbox(root,width=50)
song_list.pack(pady=10)
choose = Button(root,text='Choose song',command=add_song)
choose.pack(pady=10)
song_list.bind('<Double-Button-1>',play_song) # Just double click the desired song to play
root.mainloop()
Just double click the song you want to play. You can also use a button instead of bind()
like you do in your code.
An example of how song_dict
will structure like:
{0: ['Shawn Mendes - Perfectly Wrong', 'C:/PyProjects/sONGS/Shawn Mendes - Perfectly Wrong.mp3'],
1: ['Lil Nas X - Old Town Road (feat', 'C:/PyProjects/sONGS/Lil Nas X - Old Town Road (feat. Billy Ray Cyrus) - Remix.mp3'],
2: ['NF - Time - Edit', 'C:/PyProjects/sONGS/NF - Time - Edit.mp3']}
Though I would also recommend to make a button to ask for directory and take all the mp3 files in that directory and populate the listbox.
If you want to use filedialog.askopenfilenames
then you can edit the function as below:
import os
def add_song():
songs_path = filedialog.askopenfilenames(initialdir='C://Users//Soham//Music', title="Choose a song!")
for count,song in enumerate(songs_path):
song_name = os.path.basename(song)
song_dict[count] = [song_name,song] # Create the desired dictionary
song_list.insert(END, song_name) # Insert just the song_name to the Listbox
In this case you don't need the pre defined count
variable, as we make them from the for
loop.
EDIT:
Instead of using split
, why not just use os.path
, so you can get the basename from the path, like:
import os
song_name = os.path.basename(song_path) # If its tuple then loop through and follow
Upvotes: 2