class TWave(TestCase): def setUp(self): fn_wav_pcm_2s_16000_08_id3v23 = \ os.path.join(DATA_DIR, "silence-2s-PCM-16000-08-ID3v23.wav") self.wav_pcm_2s_16000_08_ID3v23 = \ WAVE(fn_wav_pcm_2s_16000_08_id3v23) self.tmp_fn_pcm_2s_16000_08_ID3v23 = \ get_temp_copy(fn_wav_pcm_2s_16000_08_id3v23) self.tmp_wav_pcm_2s_16000_08_ID3v23 = \ WAVE(self.tmp_fn_pcm_2s_16000_08_ID3v23) self.fn_wav_pcm_2s_16000_08_notags = \ os.path.join(DATA_DIR, "silence-2s-PCM-16000-08-notags.wav") self.wav_pcm_2s_16000_08_notags = \ WAVE(self.fn_wav_pcm_2s_16000_08_notags) self.tmp_fn_pcm_2s_16000_08_notag = \ get_temp_copy(self.fn_wav_pcm_2s_16000_08_notags) self.tmp_wav_pcm_2s_16000_08_notag = \ WAVE(self.tmp_fn_pcm_2s_16000_08_notag) fn_wav_pcm_2s_44100_16_id3v23 = \ os.path.join(DATA_DIR, "silence-2s-PCM-44100-16-ID3v23.wav") self.wav_pcm_2s_44100_16_ID3v23 = WAVE(fn_wav_pcm_2s_44100_16_id3v23) def test_channels(self): self.failUnlessEqual(self.wav_pcm_2s_16000_08_ID3v23.info.channels, 2) self.failUnlessEqual(self.wav_pcm_2s_44100_16_ID3v23.info.channels, 2) def test_sample_rate(self): self.failUnlessEqual(self.wav_pcm_2s_16000_08_ID3v23.info.sample_rate, 16000) self.failUnlessEqual(self.wav_pcm_2s_44100_16_ID3v23.info.sample_rate, 44100) def test_number_of_samples(self): self.failUnlessEqual( self.wav_pcm_2s_16000_08_ID3v23.info._number_of_samples, 32000) self.failUnlessEqual( self.wav_pcm_2s_44100_16_ID3v23.info._number_of_samples, 88200) def test_bits_per_sample(self): self.failUnlessEqual( self.wav_pcm_2s_16000_08_ID3v23.info.bits_per_sample, 8) self.failUnlessEqual( self.wav_pcm_2s_44100_16_ID3v23.info.bits_per_sample, 16) def test_bitrate(self): self.failUnlessEqual(self.wav_pcm_2s_16000_08_ID3v23.info.bitrate, 64000) self.failUnlessEqual(self.wav_pcm_2s_44100_16_ID3v23.info.bitrate, 352800) def test_length(self): self.failUnlessAlmostEqual(self.wav_pcm_2s_16000_08_ID3v23.info.length, 2.0, 2) self.failUnlessAlmostEqual(self.wav_pcm_2s_44100_16_ID3v23.info.length, 2.0, 2) def test_not_my_file(self): self.failUnlessRaises(InvalidChunk, WAVE, os.path.join(DATA_DIR, "empty.ogg")) def test_pprint(self): self.wav_pcm_2s_44100_16_ID3v23.pprint() def test_mime(self): self.failUnless("audio/wav" in self.wav_pcm_2s_44100_16_ID3v23.mime) self.failUnless("audio/wave" in self.wav_pcm_2s_44100_16_ID3v23.mime) def test_id3_tags(self): id3 = self.wav_pcm_2s_44100_16_ID3v23.tags self.assertEquals(id3["TALB"], "Quod Libet Test Data") self.assertEquals(id3["TCON"], "Silence") self.assertEquals(id3["TIT2"], "Silence") self.assertEquals(id3["TPE1"], ["piman / jzig"]) def test_id3_tags_uppercase_chunk(self): id3 = self.wav_pcm_2s_16000_08_ID3v23 self.assertEquals(id3["TALB"], "Quod Libet Test Data") self.assertEquals(id3["TCON"], "Silence") self.assertEquals(id3["TIT2"], "Silence") self.assertEquals(id3["TPE1"], ["piman / jzig"]) def test_delete(self): self.tmp_wav_pcm_2s_16000_08_ID3v23.delete() self.failIf(self.tmp_wav_pcm_2s_16000_08_ID3v23.tags) self.failUnless(WAVE(self.tmp_fn_pcm_2s_16000_08_ID3v23).tags is None) def test_save_no_tags(self): self.tmp_wav_pcm_2s_16000_08_ID3v23.tags = None self.tmp_wav_pcm_2s_16000_08_ID3v23.save() self.assertTrue(self.tmp_wav_pcm_2s_16000_08_ID3v23.tags is None) def test_add_tags_already_there(self): self.failUnless(self.tmp_wav_pcm_2s_16000_08_ID3v23.tags) self.failUnlessRaises(Exception, self.tmp_wav_pcm_2s_16000_08_ID3v23.add_tags) def test_roundtrip(self): self.failUnlessEqual(self.tmp_wav_pcm_2s_16000_08_ID3v23["TIT2"], ["Silence"]) self.tmp_wav_pcm_2s_16000_08_ID3v23.save() new = WAVE(self.tmp_wav_pcm_2s_16000_08_ID3v23.filename) self.failUnlessEqual(new["TIT2"], ["Silence"]) def test_save_tags(self): from mutagen.id3 import TIT1 tags = self.tmp_wav_pcm_2s_16000_08_ID3v23.tags tags.add(TIT1(encoding=3, text="foobar")) tags.save() new = WAVE(self.tmp_wav_pcm_2s_16000_08_ID3v23.filename) self.failUnlessEqual(new["TIT1"], ["foobar"]) """" Simulate the way Picard writes and update tags """ def test_picard_lifecycle(self): path_tmp_wav_file = \ get_temp_copy(self.fn_wav_pcm_2s_16000_08_notags) from mutagen.id3 import ID3 wav = WAVE(path_tmp_wav_file) id3 = wav.tags """" Picard WaveFile._get_tags: """ self.assertIsNone(id3, "Ensure ID3-tag-header does not exist") """" Picard WaveFile._get_tags: initialize tags """ wav.add_tags() id3 = wav.tags self.assertIsInstance(id3, ID3) """ ID3v2.3 separator """ separator = '/' """ Initialize Picard like metadata tags """ self.__init_id3_tags(id3, major=3) """ Write the Picard like metadata to the empty WAVE-file """ id3.save(path_tmp_wav_file, v23_sep=separator) """ Tags (metadata) have been added; now load the file again """ wav = WAVE(path_tmp_wav_file) id3 = wav.tags self.assertIsInstance(id3, ID3) self.assertEquals(id3["TRCK"], "1/10") self.assertEquals(id3["TPOS"], "1/1") self.assertEquals(id3["TXXX:MusicBrainz Release Group Id"], "e00305af-1c72-469b-9a7c-6dc665ca9adc") self.assertEquals(id3["TXXX:MusicBrainz Album Artist Id"], [ "3fe817fc-966e-4ece-b00a-76be43e7e73c", "984f8239-8fe1-4683-9c54-10ffb14439e9" ]) self.assertEquals(id3["TXXX:CATALOGNUMBER"], ["PRAR931391"]) self.assertEquals(id3["TSRC"], ["NLB931100460", "USMH51100098"]) @staticmethod def __init_id3_tags(id3, major=3): """ Attributes: id3 ID3 Tag object major ID3 major version, e.g.: 3 for ID3v2.3 """ from mutagen.id3 import TRCK, TPOS, TXXX, TPUB, TALB, UFID, TPE2, \ TSO2, TMED, TIT2, TPE1, TSRC, IPLS, TORY, TDAT, TYER id3.add(TRCK(encoding=major, text="1/10")) id3.add(TPOS(encoding=major, text="1/1")) id3.add( TXXX(encoding=major, desc="MusicBrainz Release Group Id", text="e00305af-1c72-469b-9a7c-6dc665ca9adc")) id3.add(TXXX(encoding=major, desc="originalyear", text="2011")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Type", text="album")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Id", text="e7050302-74e6-42e4-aba0-09efd5d431d8")) id3.add(TPUB(encoding=major, text="J&R Adventures")) id3.add(TXXX(encoding=major, desc="CATALOGNUMBER", text="PRAR931391")) id3.add(TALB(encoding=major, text="Don\'t Explain")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Status", text="official")) id3.add(TXXX(encoding=major, desc="SCRIPT", text="Latn")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Release Country", text="US")) id3.add(TXXX(encoding=major, desc="BARCODE", text="804879313915")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Artist Id", text=[ "3fe817fc-966e-4ece-b00a-76be43e7e73c", "984f8239-8fe1-4683-9c54-10ffb14439e9" ])) id3.add(TPE2(encoding=major, text="Beth Hart & Joe Bonamassa")) id3.add(TSO2(encoding=major, text="Hart, Beth & Bonamassa, Joe")) id3.add(TXXX(encoding=major, desc="ASIN", text="B005NPEUB2")) id3.add(TMED(encoding=major, text="CD")) id3.add( UFID(encoding=major, owner="http://musicbrainz.org", data=b"f151cb94-c909-46a8-ad99-fb77391abfb8")) id3.add(TIT2(encoding=major, text="Sinner's Prayer")) id3.add( TXXX(encoding=major, desc="MusicBrainz Artist Id", text=[ "3fe817fc-966e-4ece-b00a-76be43e7e73c", "984f8239-8fe1-4683-9c54-10ffb14439e9" ])) id3.add(TPE1(encoding=major, text=["Beth Hart & Joe Bonamassa"])) id3.add( TXXX(encoding=major, desc="Artists", text=["Beth Hart", "Joe Bonamassa"])) id3.add(TSRC(encoding=major, text=["NLB931100460", "USMH51100098"])) id3.add( TXXX(encoding=major, desc="MusicBrainz Release Track Id", text="d062f484-253c-374b-85f7-89aab45551c7")) id3.add( IPLS(encoding=major, people=[["engineer", "James McCullagh"], ["engineer", "Jared Kvitka"], ["arranger", "Jeff Bova"], ["producer", "Roy Weisman"], ["piano", "Beth Hart"], ["guitar", "Blondie Chaplin"], ["guitar", "Joe Bonamassa"], ["percussion", "Anton Fig"], ["drums", "Anton Fig"], ["keyboard", "Arlan Schierbaum"], ["bass guitar", "Carmine Rojas"], ["orchestra", "The Bovaland Orchestra"], ["vocals", "Beth Hart"], ["vocals", "Joe Bonamassa"]])), id3.add(TORY(encoding=major, text="2011")) id3.add(TYER(encoding=major, text="2011")) id3.add(TDAT(encoding=major, text="2709"))
class MusicPlayer(ThemedTk): def __init__(self, *args, **kwargs): #pre-variable initialization self.versionname = 'Pytone v1.5b' #initialization super(MusicPlayer, self).__init__(theme='equilux') pygame.init() mixer.init() MUSIC_END = pygame.USEREVENT + 1 pygame.mixer.music.set_endevent(MUSIC_END) self.automusicslider = threading.Thread(target=self.musicsliderplace) self.musicloop = threading.Thread(target=self.loopsong) #window layout initialization self.resizable(False, False) self.title(self.versionname) #1.3 release self.configure(background='grey22') self.geometry('1000x600') self.iconbitmap('icon.ico') self.protocol("WM_DELETE_WINDOW", self.ask_quit) self.style = ttk.Style() self.style.configure('TButton', background='grey22') self.style.configure('TScale', background='grey22') #icon initialization self.play_icon = PhotoImage(file='assets/play.png') self.pause_icon = PhotoImage(file='assets/pause.png') self.volume_min_icon = PhotoImage(file='assets/volume-min.png') self.volume_medium_icon = PhotoImage(file='assets/volume-medium.png') self.volume_max_icon = PhotoImage(file='assets/volume-max.png') self.volume_mute_icon = PhotoImage(file='assets/volume-mute.png') self.repeat_icon = PhotoImage(file='assets/repeat.png') self.shuffle_icon = PhotoImage(file='assets/shuffle.png') self.skip_back_icon = PhotoImage(file='assets/skip-back.png') self.skip_forward_icon = PhotoImage(file='assets/skip-forward.png') self.play_icon_active = PhotoImage(file='assets/play_active.png') self.pause_icon_active = PhotoImage(file='assets/pause_active.png') self.volume_min_icon_active = PhotoImage( file='assets/volume-min_active.png') self.volume_medium_icon_active = PhotoImage( file='assets/volume-medium_active.png') self.volume_max_icon_active = PhotoImage( file='assets/volume-max_active.png') self.volume_mute_icon_active = PhotoImage( file='assets/volume-mute_active.png') self.repeat_icon_active = PhotoImage(file='assets/repeat_active.png') self.shuffle_icon_active = PhotoImage(file='assets/shuffle_active.png') self.skip_back_icon_active = PhotoImage( file='assets/skip-back_active.png') self.skip_forward_icon_active = PhotoImage( file='assets/skip-forward_active.png') self.browse_file_icon = PhotoImage(file='assets/browse-file.png') self.browse_file_icon_active = PhotoImage( file='assets/browse-file_active.png') self.explorer_icon = PhotoImage(file='assets/explorer.png') self.explorer_icon_active = PhotoImage( file='assets/explorer_active.png') self.music_icon = PhotoImage(file='assets/music.png') self.music_icon_active = PhotoImage(file='assets/music_active.png') self.mute_icon = PhotoImage(file='assets/mute.png') self.mute_icon_active = PhotoImage(file='assets/mute_active.png') self.disc_icon = PhotoImage(file='assets/disc.png') self.disc_icon_active = PhotoImage(file='assets/disc_active.png') #variable initialization self.songstatus = StringVar() self.v = DoubleVar() self.currentsong = None self.pauseonly = False self.songlength = 1 #post initialization self._widget() self._config() self._layout() def _widget(self): #widget setup self.play_pause_button = Button(self, image=self.play_icon, command=self.play_pause, takefocus=False, relief=FLAT, bg='grey22', activebackground='grey22') self.VolumeSlider = ttk.Scale(self, variable=self.v, from_=0, to=100, orient=HORIZONTAL, command=self.setvolume) self.music_player_scale = ttk.Scale(self, orient=HORIZONTAL, command=self.musicsliderset) self.volume_button = Button(self, image=self.volume_max_icon, relief=FLAT, bg='grey22', activebackground='grey22', command=self.togglemute) self.progress_label_1 = Label(self, text='00:00', bg='grey22', fg='white') self.progress_label_2 = Label(self, text='00:00', bg='grey22', fg='white') self.repeat_button = Button(self, image=self.repeat_icon, bg='grey22', relief=FLAT, activebackground='grey30', command=self.loopshuffletoggle) self.shuffle_button = Button(self, image=self.shuffle_icon, bg='grey22', relief=FLAT, activebackground='grey30', command=self.loopshuffletoggle) self.last_song_button = Button(self, image=self.skip_back_icon, bg='grey22', relief=FLAT, activebackground='grey22', command=self.previous_song) self.next_song_button = Button(self, image=self.skip_forward_icon, bg='grey22', relief=FLAT, activebackground='grey22', command=self.next_song) self.playlist = Listbox(self, relief=FLAT, selectmode=SINGLE, bg="grey20", fg="grey88", font=('Arial', 13), width=82, height=15, selectbackground="grey40", activestyle='none') self.browse_button = Button(self, bg='grey30', fg='grey92', activebackground='grey70', image=self.browse_file_icon, command=self.selectpath, relief=FLAT) self.pathname = Label(self, bg='grey22', fg='white', font=('arial', 10)) self.pathtoggle = Button(self, image=self.explorer_icon, bg='grey22', relief=FLAT, width=500, height=50, command=self.toggleplaylist) self.nowmusictoggle = Button(self, image=self.music_icon, bg='grey30', relief=FLAT, width=500, height=50, command=self.toggleplaylist) self.currentvolume = Label(self, bg='grey22', fg='grey88', relief=FLAT, text='100') self.songname = Label(self, bg='grey22', fg='grey88', relief=FLAT, text='', font=('Arial', 30, 'bold')) self.artistname = Label(self, bg='grey22', fg='grey88', relief=FLAT, text='', font=('Arial', 13)) self.albumname = Label(self, bg='grey22', fg='grey88', relief=FLAT, text='', font=('Arial', 13)) self.discicon = Button(image=self.disc_icon, bg='grey30', relief=FLAT, command=self.songdetail) #widget binding self.playlist.bind('<Button-1>', self.playlistclick) self.playlist.bind('<Double-Button-1>', self.playlistdoubleclick) #24/7 threading self.automusicslider.daemon = True self.musicloop.daemon = True self.automusicslider.start() self.musicloop.start() def _layout(self): #widget placement self.songname.place(relx=0.25, rely=0.47) self.artistname.place(relx=0.25, rely=0.59) self.albumname.place(relx=0.25, rely=0.67) self.play_pause_button.place(relx=0.5, rely=0.85, anchor=CENTER) self.repeat_button.place(relx=0.4, rely=0.85, anchor=CENTER) #self.shuffle_button.place(relx=0.6, rely=0.85, anchor=CENTER) self.music_player_scale.place(relx=0.5, rely=0.95, width=500, anchor=CENTER) self.progress_label_1.place(relx=0.20, rely=0.93) self.progress_label_2.place(relx=0.75, rely=0.93) self.last_song_button.place(relx=0.45, rely=0.85, anchor=CENTER) self.next_song_button.place(relx=0.55, rely=0.85, anchor=CENTER) self.volume_button.place(relx=0.81, rely=0.845) self.VolumeSlider.place(relx=0.85, rely=0.85) self.pathtoggle.place(relx=0.0, rely=0.0) self.nowmusictoggle.place(relx=0.5, rely=0.0) self.currentvolume.place(relx=0.95, rely=0.85) self.discicon.place(relx=0.04, rely=0.44) def playlistclick(self, event): self.loadsong() def playlistdoubleclick(self, event): self.loadsong() self.toggleplaylist() self.play_music() def check_event(self): pass def _config(self): #variable setup self.VolumeSlider.set(100) self.songstatus.set("choosing") #key binding self.bind('<Button-1>', self._flat_button) self.bind('<Enter>', self._button_hover) self.bind('<Leave>', self._button_leave) self.bind('<space>', self.play_pause) def toggleplaylist(self): #toggle playlist and its accessories here if self.playlist.winfo_ismapped() == True: self.playlist.place_forget() self.pathname.place_forget() self.browse_button.place_forget() self.pathtoggle.config(bg='grey22') self.nowmusictoggle.config(bg='grey30') else: self.playlist.place(relx=0.01, rely=0.15) self.playlist.tkraise() self.pathname.place(relx=0.01, rely=0.10) self.browse_button.place(relx=0.96, rely=0.086) self.pathtoggle.config(bg='grey30') self.nowmusictoggle.config(bg='grey22') def setmusiclength(self): #important function on a player (also hard to do) if self.currentsong.endswith('.mp3') == True: self.song = MP3(self.currentsong) self.songinfo = ID3(self.currentsong) self.songlength = self.song.info.length self.songround = round(self.songlength) self.songmins, self.songsecs = divmod(self.songround, 60) self.songmins = str(self.songmins).zfill(2) self.songsecs = str(self.songsecs).zfill(2) self.progress_label_2.config(text=str(self.songmins) + ':' + str(self.songsecs)) try: self.songname.config(text=self.songinfo['TIT2'].text[0]) self.artistname.config(text=self.songinfo['TPE1'].text[0]) self.albumname.config(text=self.songinfo['TALB'].text[0]) except: self.songname.config(text=self.currentsong) self.artistname.config(text='failed to read metadata') self.albumname.config(text='failed to read metadata') if self.currentsong.endswith('.flac') == True: self.song = FLAC(self.currentsong) self.songlength = self.song.info.length self.songround = round(self.songlength) self.songmins, self.songsecs = divmod(self.songround, 60) self.songmins = str(self.songmins).zfill(2) self.songsecs = str(self.songsecs).zfill(2) self.progress_label_2.config(text=str(self.songmins) + ':' + str(self.songsecs)) self.music_player_scale.config(from_=0, to=self.songlength) try: self.songname.config(text=self.song['TITLE']) self.artistname.config(text=self.song['ARTIST']) self.albumname.config(text=self.song['ALBUM']) except: self.songname.config(text=self.currentsong) self.artistname.config(text='failed to read metadata') self.albumname.config(text='failed to read metadata') if self.currentsong.endswith('.ogg') == True: self.song = WAVE(self.currentsong) self.songlength = self.song.info.length self.songround = round(self.songlength) self.songmins, self.songsecs = divmod(self.songround, 60) self.songsecs = str(self.songsecs).zfill(2) self.progress_label_2.config(text=str(self.songmins) + ':' + str(self.songsecs)) def musicsliderset(self, *args): #Also important as user need to choose where to play #self.userlength = self.music_player_scale.get() #print(self.userlength) #mixer.music.set_pos(self.userlength) pass def musicsliderplace(self): for i in range(999999999): self.currenttime = mixer.music.get_pos() self.currenttime, self.currenttimemil = divmod( self.currenttime, 1000) self.currentmin, self.currentsec = divmod(self.currenttime, 60) self.currentmin = str(self.currentmin).zfill(2) self.currentsec = str(self.currentsec).zfill(2) self.progress_label_1.config(text=str(self.currentmin) + ':' + str(self.currentsec)) if self.progress_label_1['text'] == '-1:59': self.progress_label_1.config(text='00:00') self.currentsongpos = int(self.currenttime) / int(self.songlength) self.music_player_scale.set(self.currentsongpos) time.sleep(1) def _button_hover(self, event): try: if type(event.widget) == Button: exec('event.widget.config(image=self.' + re.search( r'assets/(.*?)\.png', root.call(event.widget.cget('image'), 'cget', '-file')).group(1).replace('-', '_') + '_icon_active)') except AttributeError: pass #button hover out animation def _button_leave(self, event): if type(event.widget) == Button: exec('event.widget.config(image=self.' + re.search( r'assets/(.*?)\.png', root.call(event.widget.cget('image'), 'cget', '-file')).group( 1).replace('-', '_').replace('_active', '') + '_icon)') #relief locking def _flat_button(self, event): if type(event.widget) == Button: event.widget.config(relief=FLAT) #music play and pause area def loadsong(self): self.currentsong = self.playlist.get(ACTIVE) #loading bay try: mixer.music.load(self.currentsong) self.play_pause_button.config(image=self.pause_icon_active) self.setmusiclength() except pygame.error: mixer.music.unload() messagebox.showerror(title="ERROR", message="Invalid Music Format!") def play_music(self, *args): mixer.music.play() self.title(self.versionname + ' - Playing ' + self.currentsong) self.check_event() def loopshuffletoggle(self): if self.repeat_button.cget('bg') == 'grey50': self.repeat_button.config(bg='grey22') else: self.repeat_button.config(bg='grey50') def loopsong(self): for i in range(99999999): if pygame.mixer.music.get_busy( ) == False and self.repeat_button.cget('bg') == 'grey50': pygame.mixer.music.play() else: pass time.sleep(1) def play_pause(self): if self.play_pause_button['image'] == str(self.pause_icon_active): mixer.music.pause() self.title(self.versionname + ' - Paused ') self.play_pause_button.config(image=self.play_icon_active) else: mixer.music.unpause() self.title(self.versionname + ' - Playing ' + self.currentsong) self.play_pause_button.config(image=self.pause_icon_active) def next_song(self): selection_indices = self.playlist.curselection() # default next selection is the beginning next_selection = 0 # make sure at least one item is selected if len(selection_indices) > 0: # Get the last selection, remember they are strings for some reason # so convert to int last_selection = int(selection_indices[-1]) # clear current selections self.playlist.selection_clear(selection_indices) # Make sure we're not at the last item if last_selection < self.playlist.size() - 1: next_selection = last_selection + 1 self.playlist.activate(next_selection) self.playlist.selection_set(next_selection) self.play_pause_button.config(image=self.pause_icon_active) self.loadsong() self.play_music() def previous_song(self): selection_indicesb = self.playlist.curselection() # default next selection is the beginning next_selectionb = 0 # make sure at least one item is selected if len(selection_indicesb) > 0: # Get the last selection, remember they are strings for some reason # so convert to int last_selectionb = int(selection_indicesb[-1]) # clear current selections self.playlist.selection_clear(selection_indicesb) # Make sure we're not at the last item if last_selectionb < self.playlist.size() - 1: next_selectionb = last_selectionb - 1 self.playlist.activate(next_selectionb) self.playlist.selection_set(next_selectionb) self.play_pause_button.config(image=self.pause_icon_active) self.loadsong() self.play_music() #volume control def setvolume(self, event): self.volume = self.VolumeSlider.get() self.volumed = self.volume / 100 + 0.00 mixer.music.set_volume(self.volumed) #also write your code here self.currentvolume.config(text=int(self.volume)) if self.volume <= 100: self.volume_button.config(image=self.volume_max_icon) if self.volume <= 70: self.volume_button.config(image=self.volume_medium_icon) if self.volume <= 40: self.volume_button.config(image=self.volume_min_icon) if self.volume == 0: self.volume_button.config(image=self.mute_icon) def togglemute(self): if self.VolumeSlider.get() != 0: #mute self.VolumeSlider.set(0) else: #unmute self.VolumeSlider.set(100) def songdetail(self): detailwindow = Toplevel() detailwindow.geometry('800x500') detailwindow.config(bg='grey22') detailwindow.attributes('-alpha', 0.9) detailwindow.title('Metadata') try: self.detailbox = Label(detailwindow, bg='grey22', fg='white', text=self.song.pprint()) self.detailbox.pack(side=TOP) except: messagebox.showerror(title='Error', message='Failed to read metadata') def selectpath(self): path = filedialog.askdirectory() self.playlist.delete(0, 'end') try: os.chdir(path) songs = os.listdir() filteredsongs = filter(lambda x: x.endswith(('.mp3', '.flac')), songs) self.pathname.config(text='Selected path: ' + path) for s in filteredsongs: self.playlist.insert(END, s) except OSError: self.pathname.config(text='Please choose a path...') def ask_quit(self): if mixer.music.get_busy() == False: root.destroy() elif askokcancel("Exit", "Stop Music?"): mixer.music.stop() root.destroy()