python语言带GUI可视化定时音乐播放器-多时段定时音乐播放器【开机自启版】软件代码
·
# pip install pygame schedule
import os
import sys
import random
import time
import schedule
import threading
import winreg as reg
from pygame import mixer
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
mixer.init()
# 注册表自启项名称(固定,不要修改)
REG_APP_NAME = "定时音乐播放器"
# 当前程序完整路径
CURR_FILE = os.path.realpath(sys.argv[0])
class MusicPlayerGUI:
def __init__(self, root):
self.root = root
self.root.title("多时段定时音乐播放器【开机自启版】")
self.root.geometry("610x560")
self.root.resizable(False, False)
# 配置变量
self.music_path = tk.StringVar(value="./music")
self.play_first = tk.IntVar(value=3)
self.play_second = tk.IntVar(value=2)
self.sleep_min = tk.IntVar(value=5)
self.timing_list = []
self.service_running = False
self.timing_thread = None
self.play_task_running = False
# 开机自启勾选框变量
self.auto_start = tk.BooleanVar()
# 初始化读取注册表,自动勾选已开启自启
self.check_reg_auto_run()
self.build_ui()
self.refresh_music_count()
# ==========开机自启注册表核心函数==========
def check_reg_auto_run(self):
"""启动软件时查询注册表,已有自启则自动勾选复选框"""
try:
key = reg.OpenKey(reg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, reg.KEY_READ)
val = reg.QueryValueEx(key, REG_APP_NAME)[0]
reg.CloseKey(key)
self.auto_start.set(True)
except FileNotFoundError:
self.auto_start.set(False)
def set_auto_startup(self):
"""勾选→添加注册表开机自启;取消→删除注册表自启"""
is_checked = self.auto_start.get()
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
try:
key = reg.OpenKey(reg.HKEY_CURRENT_USER, key_path, 0, reg.KEY_WRITE)
if is_checked:
# 写入:python解释器+脚本全路径,打包exe后自动变成exe路径
if CURR_FILE.lower().endswith(".exe"):
run_cmd = f'"{CURR_FILE}"'
else:
py_exe = sys.executable
run_cmd = f'"{py_exe}" "{CURR_FILE}"'
reg.SetValueEx(key, REG_APP_NAME, 0, reg.REG_SZ, run_cmd)
self.add_log("✅已开启【电脑开机自动启动本软件】")
else:
reg.DeleteValue(key, REG_APP_NAME)
self.add_log("❌已关闭【电脑开机自动启动本软件】")
reg.CloseKey(key)
except Exception as e:
err_msg = f"设置开机自启失败:{str(e)},部分功能需要管理员权限"
messagebox.showerror("错误", err_msg)
self.add_log(err_msg)
self.check_reg_auto_run() # 还原勾选状态
def build_ui(self):
# 1.音乐路径
frame_path = ttk.LabelFrame(self.root, text="音乐文件夹")
frame_path.pack(fill="x", padx=10, pady=4)
ttk.Entry(frame_path, textvariable=self.music_path, width=48).grid(row=0, column=0, padx=5, pady=6)
ttk.Button(frame_path, text="选择目录", command=self.select_folder).grid(row=0, column=1)
# 2.播放参数
frame_play = ttk.LabelFrame(self.root, text="播放参数设置")
frame_play.pack(fill="x", padx=10, pady=4)
ttk.Label(frame_play, text="第一轮播放数:").grid(row=0, column=0, pady=5)
ttk.Spinbox(frame_play, from_=1, to=99, textvariable=self.play_first, width=6).grid(row=0, column=1)
ttk.Label(frame_play, text="第二轮播放数:").grid(row=0, column=2, padx=10)
ttk.Spinbox(frame_play, from_=1, to=99, textvariable=self.play_second, width=6).grid(row=0, column=3)
ttk.Label(frame_play, text="间隔休息(分):").grid(row=1, column=0, pady=5)
ttk.Spinbox(frame_play, from_=1, to=999, textvariable=self.sleep_min, width=6).grid(row=1, column=1)
#3.多组定时
frame_time = ttk.LabelFrame(self.root, text="多组定时(格式HH:MM)")
frame_time.pack(fill="x", padx=10, pady=4)
self.in_h = tk.IntVar(value=9)
self.in_m = tk.IntVar(value=30)
ttk.Label(frame_time, text="时:").grid(row=0, column=0, pady=5)
ttk.Spinbox(frame_time, from_=0, to=23, textvariable=self.in_h, width=4).grid(row=0, column=1)
ttk.Label(frame_time, text="分:").grid(row=0, column=2)
ttk.Spinbox(frame_time, from_=0, to=59, textvariable=self.in_m, width=4).grid(row=0, column=3)
ttk.Button(frame_time, text="添加定时", command=self.add_time).grid(row=0, column=4, padx=5)
ttk.Button(frame_time, text="清空全部定时", command=self.clear_all_time).grid(row=0, column=5)
self.time_text = tk.Text(frame_time, height=3, width=50)
self.time_text.grid(row=1, column=0, columnspan=6, pady=4)
#4.开机自启复选框【新增模块】
frame_auto = ttk.LabelFrame(self.root, text="系统启动设置")
frame_auto.pack(fill="x", padx=10, pady=3)
auto_check = ttk.Checkbutton(frame_auto, text="✅电脑开机自动启动本播放器",
variable=self.auto_start, command=self.set_auto_startup)
auto_check.pack(anchor="w", padx=5, pady=4)
#5.音乐统计
frame_info = ttk.LabelFrame(self.root, text="音乐统计")
frame_info.pack(fill="x", padx=10, pady=4)
self.music_cnt = tk.StringVar(value="歌曲总数:0")
ttk.Label(frame_info, textvariable=self.music_cnt).grid(row=0, column=0, padx=5)
ttk.Button(frame_info, text="刷新统计", command=self.refresh_music_count).grid(row=0, column=1, padx=10)
#6.功能按钮
frame_btn = ttk.Frame(self.root)
frame_btn.pack(pady=6)
self.btn_start = ttk.Button(frame_btn, text="启动定时服务", command=self.start_schedule)
self.btn_start.grid(row=0, column=0, padx=4)
self.btn_stop = ttk.Button(frame_btn, text="停止定时服务", command=self.stop_schedule, state="disabled")
self.btn_stop.grid(row=0, column=1, padx=4)
ttk.Button(frame_btn, text="立即测试播放", command=self.test_play).grid(row=0, column=2, padx=4)
#7.运行日志
frame_log = ttk.LabelFrame(self.root, text="运行日志")
frame_log.pack(fill="both", expand=True, padx=10, pady=4)
self.log_box = tk.Text(frame_log, height=9)
self.log_box.pack(fill="both", expand=True)
def add_log(self, msg):
t = time.strftime("%H:%M:%S")
self.log_box.insert(tk.END, f"[{t}] {msg}\n")
self.log_box.see(tk.END)
self.root.update()
def select_folder(self):
path = filedialog.askdirectory()
if path:
self.music_path.set(path)
self.refresh_music_count()
def add_time(self):
h = self.in_h.get()
m = self.in_m.get()
timestr = f"{h:02d}:{m:02d}"
if timestr not in self.timing_list:
self.timing_list.append(timestr)
self.update_time_display()
self.add_log(f"已添加定时:{timestr}")
def clear_all_time(self):
self.timing_list.clear()
self.update_time_display()
self.add_log("已清空所有定时时间")
def update_time_display(self):
self.time_text.delete(1.0, tk.END)
self.time_text.insert(tk.END, "、".join(self.timing_list))
def get_music(self):
path = self.music_path.get()
suffix = (".mp3", ".wav", ".flac")
mus = []
if not os.path.exists(path):
os.mkdir(path)
self.add_log(f"自动创建目录:{path}")
for f in os.listdir(path):
full = os.path.join(path, f)
if full.lower().endswith(suffix):
mus.append(full)
return mus
def refresh_music_count(self):
cnt = len(self.get_music())
self.music_cnt.set(f"歌曲总数:{cnt}")
def play_single(self, song):
if not self.service_running:
return
mixer.music.load(song)
mixer.music.play()
while mixer.music.get_busy():
time.sleep(0.5)
if not self.service_running:
mixer.music.stop()
self.add_log("收到停止指令,终止当前歌曲")
return
def batch_play(self, mus_list, num):
if not mus_list or not self.service_running:
self.add_log("无音乐或任务已停止!")
return
pick = random.sample(mus_list, min(num, len(mus_list)))
for idx, s in enumerate(pick, 1):
if not self.service_running:
return
self.add_log(f"播放{idx}/{len(pick)}:{os.path.basename(s)}")
self.play_single(s)
def full_task(self):
if not self.service_running:
return
self.play_task_running = True
self.add_log("====到达定时,开始整套播放====")
all_mus = self.get_music()
n1 = self.play_first.get()
n2 = self.play_second.get()
rest = self.sleep_min.get()
self.add_log(f"第一轮随机{n1}首")
self.batch_play(all_mus, n1)
if not self.service_running:
self.add_log("任务中途被终止,本轮结束")
self.play_task_running = False
return
self.add_log(f"首轮结束,休息{rest}分钟")
# 可中断休眠(逐秒等待,停止立刻跳出)
wait_sec = rest * 60
for _ in range(wait_sec):
time.sleep(1)
if not self.service_running:
self.add_log("停止触发,取消休息,终止本轮")
self.play_task_running = False
return
self.add_log(f"休息结束,第二轮{n2}首")
self.batch_play(all_mus, n2)
self.add_log("✅ 本轮播放全部完成\n")
self.play_task_running = False
def schedule_loop(self):
while self.service_running:
schedule.run_pending()
time.sleep(20)
def start_schedule(self):
if self.service_running:
return
if len(self.timing_list) == 0:
messagebox.showwarning("提示", "请先添加定时时间!")
return
schedule.clear()
for t in self.timing_list:
schedule.every().day.at(t).do(self.full_task)
self.service_running = True
self.timing_thread = threading.Thread(target=self.schedule_loop, daemon=True)
self.timing_thread.start()
self.btn_start.config(state="disabled")
self.btn_stop.config(state="normal")
self.add_log(f"定时已开启,每日时段:{self.timing_list}")
def stop_schedule(self):
self.service_running = False
schedule.clear()
mixer.music.stop()
self.btn_start.config(state="normal")
self.btn_stop.config(state="disabled")
self.add_log("🛑 定时服务已关闭,正在终止正在播放/休息任务")
def test_play(self):
def run():
try:
self.full_task()
except Exception as e:
self.add_log(f"播放出错:{str(e)}")
threading.Thread(target=run, daemon=True).start()
if __name__ == "__main__":
win = tk.Tk()
app = MusicPlayerGUI(win)
win.mainloop()
更多推荐

所有评论(0)