具体效果如下
需要实现的功能主要的几个有:
1、搜索结果更新至当前音乐的列表,这样播放下一首是搜素结果的下一首
2、自动播放
3、滚动音乐文本
4、音乐进度条
5、根据实际情况生成音乐列表。我这里的是下面的情况,音乐文件的格式是
歌名_歌手.mp3
所以根据需求修改 find_mp3_files 方法,我这里返回的是
[ {"path":音乐文件路径,
"music":歌名,
"singer":歌手},
{"path":音乐文件路径,
"music":歌名,
"singer":歌手},
...]
全部代码在此,试试吧
import fnmatch
import os
import random
import sys
import logging
from PyQt5.QtGui import QPalette, QBrush, QPixmap, QLinearGradient, QColor
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QSlider, QLabel, \
QTableWidget, QLineEdit, QTableWidgetItem
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtCore import QUrl, Qt, QTimer
logging.basicConfig(filename="music.log", filemode="w", format="%(asctime)s %(name)s:%(levelname)s:%(message)s",
datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)
logger = logging.getLogger("music")
KZT = logging.StreamHandler()
KZT.setLevel(logging.INFO)
logger.addHandler(KZT)
class MusicPlayer(QMainWindow):
def __init__(self):
super().__init__()
self.music_path = "F://wyy" # 音乐文件夹,可以有子文件夹
self.start_x = 10
self.x_step = 100
self.start_y = 10
self.y_step = 40
self.window_w, self.window_h = 500, 800
self.music_list = self.find_mp3_files()
self.show_list = self.music_list
self.duration = 1
self.position = 0
self.text = "歌曲未加载"
self.current_index = -1
self.current_music = self.show_list[self.current_index]['music']
self.current_singer = self.show_list[self.current_index]['singer']
self.current_path = self.show_list[self.current_index]['path']
self.status = True
self.update_label = True
self.init_ui()
logger.info("配置加载完成")
def init_ui(self):
self.setWindowTitle("音乐播放器")
self.resize(self.window_w, self.window_h)
self.setMinimumSize(self.window_w, self.window_h)
self.setMaximumSize(self.window_w, self.window_h)
palette = QPalette() # 主界面背景
palette.setBrush(QPalette.Background, QBrush(QPixmap("imgs/21.jpg")))
self.setPalette(palette)
self.player = QMediaPlayer()
self.table_widget = QTableWidget(0, 2, parent=self) # 检测结果列表
self.table_widget.setHorizontalHeaderLabels(['歌手', '歌曲']) # 设置列表头
self.table_widget.verticalHeader().hide() # 隐藏行索引
self.table_widget.move(10, 150)
self.table_widget.resize(500, 600)
self.table_widget.cellClicked.connect(self.line_clicked)
self.table_widget.cellDoubleClicked.connect(self.play_cell)
self.table_widget.setColumnWidth(0, 200)
self.table_widget.setColumnWidth(1, 270)
self.table_widget.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_widget.setStyleSheet("QTableWidget {background-image: url('imgs/11.jpg');}")
self.load_music()
self.play_button = QPushButton("播放", self)
self.play_button.clicked.connect(self.play_current_music)
self.play_button.move(self.start_x, self.start_y)
self.change_button = QPushButton("暂停", self)
self.change_button.clicked.connect(self.change_music_status)
self.change_button.move(self.start_x + self.x_step, self.start_y)
self.play_pre_button = QPushButton("上一首", self)
self.play_pre_button.clicked.connect(self.play_pre)
self.play_pre_button.move(self.start_x, self.start_y + self.y_step)
self.play_next_button = QPushButton("下一首", self)
self.play_next_button.clicked.connect(self.play_next)
self.play_next_button.move(self.start_x + self.x_step, self.start_y + self.y_step)
self.search_text = QLineEdit(self)
self.search_text.resize(200, 30)
self.search_text.move(self.start_x + 3 * self.x_step + 10, self.start_y)
self.search_text.returnPressed.connect(self.search_music)
self.search_btn = QPushButton("搜索", self)
self.search_btn.move(self.start_x + 2 * self.x_step + 10, self.start_y)
self.search_btn.clicked.connect(self.search_music)
self.music_label = QLabel(self.text, self)
self.music_label.resize(self.window_w - self.start_x, 30)
self.music_label.move(self.start_x, self.start_y + 2 * self.y_step)
self.music_label.setAlignment(Qt.AlignCenter)
self.volume_slider = QSlider(Qt.Horizontal, self)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(50)
self.volume_slider.setTickPosition(QSlider.TicksBelow)
self.volume_slider.setTickInterval(10)
self.volume_slider.resize(200, 30)
self.volume_slider.sliderReleased.connect(self.change_volume)
# self.volume_slider.sliderPressed.connect(self.volume_pressed)
self.volume_slider.move(self.start_x + 2 * self.x_step + 50, self.start_y + self.y_step + 10)
self.music_pro_bar = QLabel(self)
self.music_pro_width = self.window_w - self.start_x
self.music_pro_bar.resize(self.music_pro_width, 10)
self.music_pro_bar.move(self.start_x, self.start_y + 2 * self.y_step + 40)
# self.music_pro_bar.setStyleSheet("background:'#123456'")
gradient = QLinearGradient(0, 0, self.music_pro_width, 0)
gradient.setColorAt(0, QColor(0, 0, 0))
gradient.setColorAt(1, QColor(255, 255, 255))
music_pro_bar_palette = QPalette()
music_pro_bar_palette.setBrush(QPalette.Background, gradient)
self.music_pro_bar.setAutoFillBackground(True)
self.music_pro_bar.setPalette(music_pro_bar_palette)
self.timer = QTimer()
self.timer.timeout.connect(self.scroll_text)
self.timer.start(500)
self.player.stateChanged.connect(self.handle_player_status_changed)
self.player.mediaStatusChanged.connect(self.handle_media_status_changed)
self.player.durationChanged.connect(self.update_duration)
self.player.positionChanged.connect(self.update_position)
def play_music(self):
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.current_path)))
self.player.play()
self.text = f"当前播放:{self.current_music} —— {self.current_singer} "
self.music_label.setText(self.text)
logger.info("正在播放:%s - %s", self.current_music, self.current_singer)
def play_current_music(self):
if self.current_index == -1:
self.current_index = 0
self.update_current_music()
logger.info(self.current_index)
self.play_music()
def change_music_status(self):
if self.status:
self.player.pause()
self.status = False
self.change_button.setText('继续')
logger.info("已暂停当前音乐:%s", self.current_music)
else:
self.status = True
self.player.play()
self.change_button.setText('暂停')
logger.info("已继续当前音乐:%s", self.current_music)
def handle_media_status_changed(self, status):
if status == QMediaPlayer.EndOfMedia:
logger.info("播放完毕: %s - %s", self.current_music, self.current_singer)
if not self.show_list:
logger.info("当前列表没有歌曲")
self.reload_music()
self.play_next()
def handle_player_status_changed(self, state):
if state == QMediaPlayer.PlayingState:
self.update_label = True
elif state == QMediaPlayer.StoppedState:
self.update_label = False
def search_music(self):
text = self.search_text.text()
if text:
self.show_list = []
for i in self.music_list:
for j in i.values():
if text in j:
self.show_list.append(i)
break
self.load_music()
logger.info("已查询'%s'相关内容,总计 %d 条", text, len(self.show_list))
else:
logger.info('未查询到相关音乐')
self.reload_music()
def reload_music(self):
logger.info('重新加载列表')
self.music_list = self.find_mp3_files() # 从本地重新加载
self.show_list = self.music_list
self.load_music()
def clear_table(self):
self.table_widget.clearContents()
self.table_widget.setHorizontalHeaderLabels(['歌手', '歌曲']) # 设置列表头
self.table_widget.setRowCount(0)
logger.info("已更新列表")
def line_clicked(self, row, column):
self.current_index = row
self.update_current_music()
logger.info("点击了:%s - %s", self.current_music, self.current_singer)
def play_cell(self, row, column):
logger.info("双击播放:%s - %s", self.current_music, self.current_singer)
self.current_index = row
self.update_current_music()
self.play_music()
def load_music(self):
self.clear_table()
n = 0
for i in self.show_list:
self.table_widget.setRowCount(n + 1)
self.table_widget.setItem(n, 0, QTableWidgetItem(i['singer']))
self.table_widget.setItem(n, 1, QTableWidgetItem(i['music']))
n += 1
logger.info('加载音乐列表完成')
def update_current_music(self):
self.current_path = self.show_list[self.current_index]['path']
self.current_singer = self.show_list[self.current_index]['singer']
self.current_music = self.show_list[self.current_index]['music']
# logger.info("更新当前音乐为:%s - %s", self.current_music, self.current_singer)
def play_pre(self):
logger.info("播放上一首")
if not self.show_list:
logger.info("当前列表没有音乐")
return
find_path = False
for i, j in enumerate(self.show_list):
if self.current_path == j['path']:
if i != 0:
self.current_index = i - 1
else:
self.current_index = -1
find_path = True
break
if not find_path:
logger.info("当前播放歌曲不在当前列表")
self.current_index = -1
self.update_current_music()
self.change_button.setText('暂停')
logger.info("切换音乐:%s - %s", self.current_music, self.current_singer)
self.play_music()
def play_next(self):
logger.info("播放下一首")
if not self.show_list:
logger.info("当前列表没有音乐")
return
find_path = False
for i, j in enumerate(self.show_list):
if self.current_path == j['path']:
if i != len(self.show_list) - 1:
self.current_index = i + 1
else:
self.current_index = 0
find_path = True
break
if not find_path:
logger.info("当前播放歌曲不在当前列表")
self.current_index = 0
self.update_current_music()
self.change_button.setText('暂停')
logger.info("切换音乐为:%s - %s", self.current_music, self.current_singer)
self.play_music()
def change_volume(self):
value = self.volume_slider.value()
self.player.setVolume(value)
logger.info("滑动设置音量为%s", value)
# def volume_pressed(self):
# value = self.volume_slider.value()
# self.player.setVolume(value)
# logger.info("点击设置音量为%s", value)
def set_position(self):
self.music_pro_bar.resize(int(self.position / self.duration * self.music_pro_width), 10)
# c = int(self.position / self.duration * 255)
# h = self.rgb2hex(c, c, c)
# self.music_pro_bar.setStyleSheet(f"background:'{h}'")
def update_duration(self, duration):
if not self.update_label:
return
self.duration = duration
def update_position(self, position):
if not self.update_label:
return
self.position = position
self.set_position()
def scroll_text(self):
current_text = self.music_label.text()
scroll_text = current_text[1:] + current_text[0]
self.music_label.setText(scroll_text)
self.music_label.setStyleSheet(f"color:{self.rgb2hex(*self.random_color())}")
def rgb2hex(self, r, g, b):
return "#{:02x}{:02x}{:02x}".format(r, g, b)
def find_mp3_files(self): # 生成音乐文件列表,根据需求自定义
mp3_files = []
for root, dirs, files in os.walk(self.music_path):
for file in files:
if fnmatch.fnmatch(file, '*.mp3'):
if '_' in file:
r = {'music': file.split('_')[0],
'singer': file.split('_')[1].split('.')[0],
'path': os.path.join(root, file)}
mp3_files.append(r)
return mp3_files
def random_color(self): # 随机颜色
r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
return r, g, b
if __name__ == "__main__":
app = QApplication(sys.argv)
player = MusicPlayer()
player.show()
sys.exit(app.exec_())