import tkinter
import pygame
import time
import re
from tkinter import ttk


class MusicPlayer:
    def __init__(self, cls_root):
        # 初始化变量
        self.root = cls_root
        self.progress_bar = None
        self.play_button = None
        self.pause_button = None
        self.music_file = None
        self.music_length = 0
        self.time = None
        self.time_format = "%n/%a"
        self.pause = True
        self.progress = []
        self.length = []
        self.finish = True
        self.d_value = 0.0
        # 初始化 Pygame
        pygame.init()
        # 初始化上次更新的时间
        self.last_update_time = time.time()
        # 开始更新进度条
        self.current_position = 0.0  # 用于跟踪当前音乐播放的位置
        self.update_progress()

    def load_music(self, music_file):
        self.music_file = music_file
        self.music_length = pygame.mixer.Sound(self.music_file).get_length()  # 获取音乐长度
        pygame.mixer.music.load(self.music_file)

    def bind(self, cls_progress_bar=None, cls_pause_button=None, cls_play_button=None, cls_time=None):
        # 绑定控件
        self.progress_bar = cls_progress_bar
        self.pause_button = cls_pause_button
        self.play_button = cls_play_button
        self.time = cls_time

    def play_music(self, music_file):
        self.finish = False
        self.load_music(music_file)
        self.d_value = 0.0
        pygame.mixer.music.play()
        self.pause = False
        self.current_position = 0.0
        if self.progress_bar is not None:
            self.progress_bar["from_"] = 0
            self.progress_bar["to"] = float(self.music_length)
            self.progress_bar.set(0)

    def stop_music(self):
        pygame.mixer.music.stop()
        pygame.mixer.music.unload()
        self.music_file = None
        self.finish = True
        self.pause = True
        self.current_position = 0.0
        self.music_length = 0
        if self.time is not None:
            self.time["text"] = ""
        if self.progress_bar is not None:
            self.progress_bar["from_"] = 0
            self.progress_bar["to"] = 1
            self.progress_bar.set(0)

    def pause_music(self):
        try:
            if not self.finish:
                if self.pause:
                    pygame.mixer.music.unpause()
                    self.pause = False
                else:
                    pygame.mixer.music.pause()
                    self.pause = True
        except:
            self.play_music()

    def set_progress(self, value):
        if not self.finish:
            # 检查是否距离上次更新超过0.55秒
            if abs(float(value) - self.last_update_time) > 0.55:
                # 将进度条的值直接设置为音乐的播放位置
                self.current_position = float(value)
                self.d_value = float(value) - pygame.mixer.music.get_pos() / 1000
                try:
                    pygame.mixer.music.set_pos(float(value))
                except:
                    self.stop_music()

    def update_progress(self):
        self.current_position = pygame.mixer.music.get_pos() / 1000 + self.d_value
        if not self.pause:
            if self.music_file is not None:
                if self.progress_bar is not None:
                    # 更新进度条
                    self.progress_bar.set(self.current_position)
                    self.last_update_time = self.progress_bar.get()
                # 更新播放时长
                if self.time is not None:
                    self.time["text"] = self.time_format.replace("%n", self.get_progress()).replace("%a",
                                                                                                    self.get_length())
        # 每隔一段时间再次更新进度条
        self.root.after(500, self.update_progress)

    def get_busy(self):
        return not self.pause

    def get_progress(self, state="%m:%s"):
        self.progress = self.get_format(int(self.current_position))
        if len(self.progress[0]) == 1:
            self.progress[0] = "0" + self.progress[0]
        if len(self.progress[1]) == 1:
            self.progress[1] = "0" + self.progress[1]
        if len(self.progress[2]) == 1:
            self.progress[2] = "0" + self.progress[2]
        return_value = state.replace("%s", self.progress[0])
        return_value = return_value.replace("%m", self.progress[1])
        return_value = return_value.replace("%h", self.progress[2])
        return return_value

    @staticmethod
    def get_format(value):
        second = value % 60
        minute = value // 60 % 60
        hour = value // 3600
        return [str(second), str(minute), str(hour)]

    @staticmethod
    def decode_format(value):
        match = re.match(r'(\d+):(\d)', value)
        if match:
            minute = int(match.group(1))
            second = int(match.group(2))
            timestamp = minute * 60 + second
            return timestamp
        else:
            return None

    def get_length(self, state="%m:%s"):
        self.length = self.get_format(int(self.music_length))
        if len(self.length[0]) == 1:
            self.length[0] = "0" + self.length[0]
        if len(self.length[1]) == 1:
            self.length[1] = "0" + self.length[1]
        if len(self.length[2]) == 1:
            self.length[2] = "0" + self.length[2]
        return_value = state.replace("%s", self.length[0])
        return_value = return_value.replace("%m", self.length[1])
        return_value = return_value.replace("%h", self.length[2])
        return return_value

    def set_format_of_time(self, cls_format="%n/%a"):
        self.time_format = cls_format

    def get_finished(self):
        return self.finish


if __name__ == "__main__":
    root = tkinter.Tk()
    player = MusicPlayer(root)
    root.title("音乐播放器")
    progress_bar = ttk.Scale(root, orient="horizontal", from_=0, to=player.music_length, length=2000)
    progress_bar.pack()
    pause_button = ttk.Button(root, text="暂停", command=player.pause_music)
    play_button = ttk.Button(root, text="播放", command=lambda: player.play_music("your_music_file.mp3"))
    stop_button = ttk.Button(root, text="停止", command=player.stop_music)
    pause_button.pack()
    play_button.pack()
    stop_button.pack()
    progress_time = ttk.Label(root, text="")
    progress_time.pack()
    progress_bar["command"] = lambda event: player.set_progress(progress_bar.get())
    player.bind(progress_bar, pause_button, play_button, progress_time)
    player.set_format_of_time()

    root.mainloop()
