예제 #1
0
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"))
예제 #2
0
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()