CoderMan
CoderMan

Reputation: 43

I am making a mp3 payer in Python3 (also using Tkinter) but I am facing a dead end

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

Answers (2)

Delrius Euphoria
Delrius Euphoria

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

mukund ghode
mukund ghode

Reputation: 262

You can create a dict having {'song name': 'file path'}

Upvotes: 2

Related Questions