熟悉的小伙伴都知道,前段时间写了一篇关于音乐播放器的文章–Python自制一款炫酷音乐播放器。不少小伙伴私信我,对播放器提了一些改进建议,对播放器的一些逻辑bug优化完善。今天音乐播放器3.0版本完成了,大家一起来看看是如何用python自制一款炫酷的音乐播放器的吧~
因为之前已经介绍过了音乐播放器V1.0版本的大致功能,如果有不了解的小伙伴可以先去看看之前版本的音乐播放器大致介绍。【python自制一款炫酷音乐播放器,想听啥随便搜!】下面我们开始介绍音乐播放器V3.0版本新加的部分功能以及制作过程。
直接跳到文末获取源码及exe打包程序。
之前V1.0版本的播放器中,主要完成了播放器的大致界面的设计,主要包括搜索页、播放记录两个子页面,对播放器画面简单的布局;其次播放器的主要核心功能根据输入的搜索音乐关键字自动爬取音乐并且可以进行音乐播放。也实现了音乐播放器的几个常见辅助功能,例如播放方式的切换;音乐播放当前歌曲、上一首、下一首;音乐播放暂停开始;音乐音量控制等。
V3.0版本中,我们主要完善了以下几个核心功能:
V1.0播放器版本中,我们已经对排版有了初步设计。整个分为4块区域,头部区域、中间主体左侧区域、中间主体右侧区域、底部区域。头部区域主要包括关键字音乐搜索和音乐路线来源切换,以及窗体最小化,最大化,关闭功能;中间主体包含左右两侧,左侧用来显示播放音乐封面图,右侧用来显示搜索音乐列表;底部主要来显示当前播放音乐,播放进度条,音量控制,上一首/下一首,暂停/开始,播放方式等附加功能。
V3.0播放器版本中,我们将新增的喜爱的歌曲子页面、本地歌曲子页面添加到中间主体右侧区域,叠加在音乐搜索列表页。对播放器的背景进行透明化,并增加背景图片。这里我们使用的还是原来的pyqt5,核心设计代码如下:
# author:Dragon少年
class Ui_MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.RowLength = 0
t1 = Thread(target=self.action)
t1.setDaemon(True)
t1.start()
self.start()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1023, 758)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_1 = QtWidgets.QLabel(self.centralwidget)
self.label_1.setGeometry(QtCore.QRect(0, 50, 1024, 601))
self.label_1.setText("")
self.label_1.setObjectName("label")
try:
pix_img = QPixmap(str('1.jpg'))
pix = pix_img.scaled(1024, 700, Qt.KeepAspectRatio)
self.label_1.setPixmap(pix)
except:
pass
self.widget_left = QtWidgets.QWidget(self.centralwidget)
self.widget_left.setGeometry(QtCore.QRect(0, 60, 243, 591))
self.label_smallpic = MyQLabel(self.widget_left)
self.label_smallpic.setGeometry(QtCore.QRect(22, 180, 200, 200))
self.label_smallpic.setText("")
self.label_smallpic.setObjectName("label_smallpic")
self.label_smallpic.connect_customized_slot(self.show)
pix_img = QPixmap(str(data + '/backdown.png'))
pix = pix_img.scaled(200, 200, Qt.KeepAspectRatio)
self.label_smallpic.setPixmap(pix)
self.label_pagenum = QtWidgets.QLabel(self.widget_left)
self.label_pagenum.setGeometry(QtCore.QRect(22, 500, 210, 16))
self.label_pagenum.setObjectName("label_pagenum")
self.shuru2 = QtWidgets.QLineEdit(self.widget_left)
self.shuru2.setText('5')
self.shuru2.setGeometry(QtCore.QRect(77, 80, 78, 20))
self.shuru2.setObjectName("shuru2")
self.label_5 = QtWidgets.QLabel(self.widget_left)
self.label_5.setGeometry(QtCore.QRect(11, 80, 54, 21))
self.label_5.setObjectName("label_5")
self.sure = QtWidgets.QPushButton(self.widget_left)
self.sure.setGeometry(QtCore.QRect(165, 80, 67, 23))
self.sure.setObjectName("sure")
self.sure.clicked.connect(self.page)
self.sure.setStyleSheet(
'''QPushButton{background:#3C3F41;border-radius:5px;}QPushButton:hover{background:#F2BCAE;}''')
self.widget_down = QtWidgets.QWidget(self.centralwidget)
self.widget_down.setGeometry(QtCore.QRect(0, 650, 1024, 81))
self.widget_down.setObjectName("widget_down")
self.horizontalSlider = QtWidgets.QSlider(self.widget_down)
self.horizontalSlider.setGeometry(QtCore.QRect(330, 52, 375, 20))
self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
self.horizontalSlider.setObjectName("horizontalSlider")
self.widget_control = QtWidgets.QWidget(self.widget_down)
self.widget_control.setGeometry(QtCore.QRect(264, 0, 485, 51))
self.widget_control.setObjectName("widget_control")
self.label3 = QtWidgets.QLabel(self.widget_down)
self.label3.setGeometry(QtCore.QRect(803, 30, 111, 21))
self.label3.setObjectName("label_3")
self.right_playconsole_layout = QGridLayout() # 播放控制部件网格布局层
self.widget_control.setLayout(self.right_playconsole_layout)
self.console_button_3.setIconSize(QSize(30, 30))
self.right_playconsole_layout.addWidget(self.console_button_4, 0, 0)
self.right_playconsole_layout.addWidget(self.console_button_1, 0, 1)
self.right_playconsole_layout.addWidget(self.console_button_3, 0, 2)
self.right_playconsole_layout.addWidget(self.console_button_2, 0, 3)
self.right_playconsole_layout.addWidget(self.console_button_5, 0, 4)
self.right_playconsole_layout.addWidget(self.console_button_6, 0, 5)
self.right_playconsole_layout.setAlignment(Qt.AlignCenter) # 设置布局内部件居中显示
self.widget_control.setStyleSheet('''
QPushButton{
border:none;
}
''')
self.widget_right = QtWidgets.QWidget(self.centralwidget)
self.widget_right.setGeometry(QtCore.QRect(242, 50, 782, 601))
self.widget_right.setObjectName("widget_right")
self.right_layout = QGridLayout()
self.widget_right.setLayout(self.right_layout) # 设置右侧部件布局为网格
self.tabWidget = QTabWidget(self)
self.tabWidget.setGeometry(QtCore.QRect(242, 50, 782, 610))
op = QGraphicsOpacityEffect()
op.setOpacity(0.9)
self.tab = QWidget()
self.tab.setObjectName("tab")
self.tab_layout = QGridLayout()
self.tab.setLayout(self.tab_layout)
self.listwidget = QListWidget(self.tab)
self.tab.setWindowOpacity(0.8)
self.label361 = QLabel(self)
self.label361.setText("")
self.label361.setStyleSheet("color:#6DDF6D")
self.tab_layout.addWidget(self.label361, 0, 1, 1, 1)
self.button_1235 = QPushButton(icon('fa.download', color='#D0D0D0', font=24), "下载全部")
self.button_1235.clicked.connect(self.downloadalls)
self.button_1235.setStyleSheet(
'''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#303030;}''')
self.tab_layout.addWidget(self.button_1235, 0, 2, 1, 1)
self.button_1236 = QPushButton(icon('fa.trash-o', color='#D0D0D0', font=24), "清空列表")
self.button_1236.clicked.connect(self.dell)
self.button_1236.setStyleSheet(
'''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#303030;}''')
self.tab_layout.addWidget(self.button_1236, 0, 3, 1, 1)
self.listwidget.doubleClicked.connect(lambda: self.change_func(self.listwidget))
self.listwidget.setContextMenuPolicy(Qt.CustomContextMenu)
self.listwidget.customContextMenuRequested[QPoint].connect(self.myListWidgetContext)
self.listwidget.setStyleSheet('''QListWidget{color:black}''')
self.listwidget.setObjectName("listWidget")
#self.tab.setStyleSheet('''QWidget{background:transparent};QListWidget{color:black}''')
self.tab_layout.addWidget(self.listwidget, 1, 0, 1, 4)
self.tabWidget.addTab(self.tab, " 搜索页 ")
self.tab2 = QWidget()
self.tab2.setObjectName("tab")
self.tab2_layout = QGridLayout()
self.tab2.setLayout(self.tab2_layout)
self.listwidget2 = QListWidget(self.tab2)
self.listwidget2.doubleClicked.connect(lambda: self.change_funcse(self.listwidget2))
self.listwidget2.setContextMenuPolicy(Qt.CustomContextMenu)
self.listwidget2.customContextMenuRequested[QPoint].connect(self.myListWidgetContext2)
self.listwidget2.setObjectName("listWidget2")
self.listwidget2.setContextMenuPolicy(3)
self.tab2_layout.addWidget(self.listwidget2, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab2, " 最近播放 ")
self.tab3 = QWidget()
self.tab3.setObjectName("tab")
self.tab3_layout = QGridLayout()
self.tab3.setLayout(self.tab3_layout)
self.label223 = QLabel(self)
# self.label5.setScaledContents(True)
pix_img = QPixmap(str(data + '/backdown.png'))
pix = pix_img.scaled(100, 100, Qt.KeepAspectRatio)
self.label223.setPixmap(pix)
# self.label5.setMaximumSize(1,1)
self.tab3_layout.addWidget(self.label223, 0, 0, 1, 1)
self.button_1237 = QPushButton(icon('fa.play', color='#FFFFFF', font=24), "播放全部")
self.button_1237.clicked.connect(self.allplaylove)
self.button_1237.setStyleSheet(
'''QPushButton{background:#EC4141;border-radius:5px;}QPushButton:hover{background:#E92121;}''')
self.tab3_layout.addWidget(self.button_1237, 0, 1, 1, 1)
self.button_1235 = QPushButton(icon('fa.download', color='#D0D0D0', font=24), "下载全部")
self.button_1235.clicked.connect(self.downloadalllove)
self.button_1235.setStyleSheet(
'''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#303030;}''')
self.tab3_layout.addWidget(self.button_1235, 0, 2, 1, 1)
self.button_1236 = QPushButton(icon('fa.trash-o', color='#D0D0D0', font=24), "清空列表")
self.button_1236.clicked.connect(self.delove)
self.button_1236.setStyleSheet(
'''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#303030;}''')
self.tab3_layout.addWidget(self.button_1236, 0, 3, 1, 1)
self.listwidget3 = QListWidget(self.tab3)
self.listwidget3.doubleClicked.connect(lambda: self.change_funclove(self.listwidget3))
self.listwidget3.setContextMenuPolicy(Qt.CustomContextMenu)
self.listwidget3.customContextMenuRequested[QPoint].connect(self.myListWidgetContext3)
self.listwidget3.setObjectName("listWidget3")
self.tab3_layout.addWidget(self.listwidget3, 1, 0, 1, 4)
self.tabWidget.addTab(self.tab3, " 喜爱的歌 ")
self.tab5 = QWidget()
self.tab5.setObjectName("tab5")
self.tab5_layout = QGridLayout()
self.tab5.setLayout(self.tab5_layout)
self.listwidget5 = QListWidget(self.tab5)
self.listwidget5.doubleClicked.connect(lambda: self.change(self.listwidget5))
self.listwidget5.setContextMenuPolicy(Qt.CustomContextMenu)
self.listwidget5.customContextMenuRequested[QPoint].connect(self.myListWidgetContext5)
self.button_12351 = QPushButton(icon('fa.download', color='#D0D0D0', font=24), "添加目录")
self.button_12351.clicked.connect(self.add)
self.button_12351.setStyleSheet(
'''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#303030;}''')
self.tab5_layout.addWidget(self.button_12351, 0, 2, 1, 1)
self.button_12361 = QPushButton(icon('fa.trash-o', color='#D0D0D0', font=24), "清空列表")
self.button_12361.clicked.connect(self.dellocal)
self.button_12361.setStyleSheet(
'''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#303030;}''')
self.tab5_layout.addWidget(self.button_12361, 0, 3, 1, 1)
self.listwidget5.setObjectName("listWidget5")
self.tab5_layout.addWidget(self.listwidget5, 1, 0, 1, 4)
self.tabWidget.addTab(self.tab5, " 本地歌曲 ")
self.right_layout.addWidget(self.tabWidget, 3, 0, 100, 100)
self.widget_up = QtWidgets.QWidget(self.centralwidget)
self.widget_up.setGeometry(QtCore.QRect(0, 0, 1024, 51))
self.widget_up.setObjectName("widget_up")
self.shuru = QtWidgets.QLineEdit(self.widget_up)
self.shuru.setGeometry(QtCore.QRect(220, 10, 221, 31))
self.shuru.setObjectName("shuru")
self.shuru.returnPressed.connect(self.correct)
self.pushButton_search = QtWidgets.QPushButton(self.widget_up)
self.pushButton_search.setIcon(icon('fa.search', color='white'))
self.pushButton_search.setGeometry(QtCore.QRect(407, 10, 34, 31))
self.pushButton_search.setObjectName("pushButton_search")
self.pushButton_search.clicked.connect(self.correct)
self.pushButton_search.setStyleSheet(
'QPushButton{color:white;border-radius:5px;}QPushButton:hover{background:green;}')
self.cb = QtWidgets.QComboBox(self.widget_up)
self.cb.setGeometry(QtCore.QRect(594, 10, 122, 31))
self.cb.setObjectName("comboBox")
# self.up_layout.addWidget(self.cb, 0, 180, 1, 30)
self.cb.currentIndexChanged[int].connect(self.print)
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(0, 50, 1024, 601))
font = QtGui.QFont()
font.setFamily("Microsoft Himalaya")
self.widget.setFont(font)
self.widget.setObjectName("widget")
self.label_picbig = MyQLabel(self.widget)
self.label_picbig.setGeometry(QtCore.QRect(55, 160, 300, 300))
self.label_picbig.setText("")
self.label_picbig.setObjectName("label_picbig")
self.label_picbig.connect_customized_slot(self.show)
pix_img = QPixmap(str(data + '/backdown.png'))
pix = pix_img.scaled(300, 300, Qt.KeepAspectRatio)
self.label_picbig.setPixmap(pix)
self.label_showname = QtWidgets.QLabel(self.widget)
self.label_showname.setGeometry(QtCore.QRect(440, 10, 1000, 41))
font = QtGui.QFont()
font.setFamily("幼圆")
font.setPointSize(28)
self.label_showname.setFont(font)
self.label_showname.setObjectName("label_showname")
self.label_showsinger = QtWidgets.QLabel(self.widget)
self.label_showsinger.setGeometry(QtCore.QRect(462, 70, 1000, 30))
font = QtGui.QFont()
font.setFamily("幼圆")
font.setPointSize(20)
self.label_showsinger.setFont(font)
self.label_showsinger.setObjectName("label_showsinger")
self.listwidget_lrc = QtWidgets.QListWidget(self.widget)
self.listwidget_lrc.setGeometry(QtCore.QRect(396, 110, 422, 461))
self.left_close = QPushButton("") # 关闭按钮
self.left_close.clicked.connect(MainWindow.close)
self.left_visit = QPushButton("") # 空白按钮
self.left_visit.clicked.connect(MainWindow.big)
self.left_mini = QPushButton("") # 最小化按钮
self.left_mini.clicked.connect(MainWindow.mini)
self.close_layout.addWidget(self.left_mini, 0, 0, 1, 1)
self.close_layout.addWidget(self.left_close, 0, 2, 1, 1)
self.close_layout.addWidget(self.left_visit, 0, 1, 1, 1)
self.left_close.setFixedSize(15, 15) # 设置关闭按钮的大小
self.left_visit.setFixedSize(15, 15) # 设置按钮大小
self.left_mini.setFixedSize(15, 15) # 设置最小化按钮大小
MainWindow.setWindowOpacity(0.95) # 设置窗口透明度
MainWindow.setAttribute(Qt.WA_TranslucentBackground)
MainWindow.setWindowFlag(Qt.FramelessWindowHint) # 隐藏边框
def labelc(self):
self.setCursor(QCursor(Qt.ArrowCursor))
print('surprise')
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_pagenum.setText(_translate("MainWindow", "当前为顺序播放"))
self.label_5.setText(_translate("MainWindow", "加载页数"))
self.sure.setText(_translate("MainWindow", "确定"))
self.label_leftnum.setText(_translate("MainWindow", "00:00:00"))
self.label_2.setText(_translate("MainWindow", "00:00:00"))
self.label_name.setText(_translate("MainWindow", "还没有播放歌曲呢╰(*°▽°*)╯"))
self.label_singer.setText(_translate("MainWindow", "(*/ω\*)"))
self.pushButton_search.setText(_translate("MainWindow", ""))
self.label_showname.setText(_translate("MainWindow", "制作:oys,Dragon少年"))
self.label_showsinger.setText(_translate("MainWindow", "推广:dragon少年,csdn:Dragon少年"))
根据之前版本播放器完成的,输入的关键字和选择音乐来源进行音乐列表爬取并将这些爬取的音乐数据列表显示到搜索页面中,双击列表页面中某一首歌曲,即可实现音乐播放功能。
V3.0播放器版本中,我们增加优化了对当前播放音乐的本地下载、搜索页音乐列表一键下载、喜爱的歌列表一键下载、添加我喜爱的歌曲功能。
下载音乐:
我们可以进行当前播放音乐下载、搜索页音乐列表一键下载、喜爱的歌一键下载。如下图所示:
# author:Dragon少年
# 当前播放音乐下载
def down(self):
if bo == 'local':
downpath = str(filew)
downpath = downpath.replace('/', '\\')
downpath = downpath + SongName[num]
call('explorer /select,{}'.format(downpath))
else:
call('explorer /select,{}'.format(to))
# 下载所有音乐
def downloadall(self, typer):
try:
global typerr
typerr = typer
print(typer)
print(typerr)
self.work = downall()
self.work.start()
self.work.trigger.connect(self.disdownall)
except:
print('默认图片下载错误')
pass
# 下载搜索页列表所有音乐
def downloadalls(self):
self.downloadall('boing')
# 下载喜爱的歌列表所有音乐
def downloadalllove(self):
self.downloadall('love')
添加喜爱的歌:
添加喜爱的歌曲,我们可以通过当前播放音乐的❤标志,也可以通过右键音乐列表进行喜爱的歌曲添加。
# author:Dragon少年
# 通过点击❤标志,对当前播放音乐添加喜爱的歌
def lovesong(self):
if bo == 'boing' or bo == 'boed':
try:
if bo == 'boing':
loves.append(songs[num])
loveurls.append(urls[num])
lovepics.append(pic[num])
lovelrc.append(lrcs[num])
elif bo == 'boed':
loves.append(songed[num])
loveurls.append(urled[num])
lovepics.append(picd[num])
lovelrc.append(lrcd[num])
else:
pass
except:
pass
self.work = firstThread()
self.work.start()
self.work.trigger.connect(self.dispng)
r = 0
self.listwidget3.clear()
for i in loves:
self.listwidget3.addItem(i)
self.listwidget3.item(r).setForeground(Qt.white)
r = r + 1
print(loves)
else:
pass
# 通过右键音乐列表进行喜爱的歌曲添加
def addItem(self):
try:
if list_confident == 'boing':
loves.append(songs[num_m])
loveurls.append(urls[num_m])
lovepics.append(pic[num_m])
lovelrc.append(lrcs[num_m])
else:
loves.append(songed[num_m])
loveurls.append(urled[num_m])
lovepics.append(picd[num_m])
lovelrc.append(lrcd[num_m])
self.work = firstThread()
self.work.start()
self.work.trigger.connect(self.dispng)
except:
pass
r = 0
self.listwidget3.clear()
for i in loves:
self.listwidget3.addItem(i)
self.listwidget3.item(r).setForeground(Qt.white)
r = r + 1
QListwidge点击和播放:
接下来我们需要完善QListwidge的点击和播放模块,通过对列表中的歌曲双击,创建播放线程进行音乐播放。
核心代码:
# author:Dragon少年
# 音乐列表播放
def bofang(self, num):
try:
downloading = True
self.console_button_3.setIcon(qtawesome.icon('fa.pause', color='#F76677', font=18))
pause = False
try:
pygame.mixer.stop()
except:
pass
pygame.mixer.init()
try:
self.Timer = QTimer()
self.Timer.start(500)
except:
pass
try:
self.label.setText('下载中')#调用开头的多线程下载歌曲
self.work = WorkThread()
self.work.start()
self.work.trigger.connect(self.display)
except:
print ('song download error')
downloading = False
pass
except:
time.sleep(0.1)
print ('system error')
pass
#用于接收返回的信号
def display(self,sd):
if sd == 'finish':
self.label.setText(songs[num])
print ('music\{}.mp3'.format(number))
pygame.mixer.music.load('music\{}.mp3'.format(number)) # 载入音乐
pygame.mixer.music.play()
# 播放音乐
else:
self.label.setText('下载错误')
双击播放,上一首和下一首:
# author:Dragon少年
#QlistWidget的双击事件
def change_func(self, listwidget):
global num
item = QListWidgetItem(self.listwidget.currentItem())
print(item.text())
num = int(listwidget.currentRow())
self.label.setText(songs[num])
print(listwidget.currentRow())
self.bofang(num)
#下一首按钮
def nextion(self):
try:
if play == 'shun':
print('shuning')
self.next()
elif play == 'shui':
print('shuiing')
self.shui()
elif play == 'always':
print('alwaysing')
self.next()
except:
print('no')
pass
播放模式:
接下来我们需要完善播放模式选择和循环判断是否要自动下一首,由于每秒钟判断一次,所以要使用多线程,之前由于没有考虑,导致播放切换时会存在异常bug出现。核心代码如下:
# author:Dragon少年
'''
在init里面的循环判断打开方法
t1 = threading.Thread(target=self.action)
t1.setDaemon(True)
t1.start()
'''
#选择播放模式
def playmode(self):
global play
try:
if play == 'shun':
play = 'shui'
print('随机播放')
self.label2.setText("当前为随机播放")
try:
self.console_button_6.setIcon(qtawesome.icon('fa.random', color='#3FC89C', font=18))
print('done')
except:
print('none')
pass
elif play == 'shui':
play = 'always'
print('单曲循环')
self.label2.setText("当前为单曲循环")
try:
self.console_button_6.setIcon(qtawesome.icon('fa.retweet', color='#3FC89C', font=18))
print('done')
except:
print('none')
elif play == 'always':
play = 'shun'
print('顺序播放')
self.label2.setText("当前为顺序播放")
try:
self.console_button_6.setIcon(qtawesome.icon('fa.align-center', color='#3FC89C', font=18))
print('done')
except:
print('none')
except:
print('error')
pass
#循环判断
def action(self):
a = 1
global num
while a < 2:
try:
time.sleep(1)
if not pygame.mixer.music.get_busy() and pause == False and not downloading:
if play == 'shun':
print('shuning')
self.next()
elif play == 'shui':
print('shuiing')
self.shui()
elif play == 'always':
print('alwaysing')
self.always()
except:
print('no')
pass
else:
pygame.mixer.music.stop()
源码及打包exe已上传,关注文末公众号回复【python播放器3】即可获取完整源码
Python往期精彩:
见过仙女蹦迪吗?一起用python做个小仙女代码蹦迪视频
python自制一款炫酷音乐播放器,想听啥随便搜!
斗地主老是输?一起用Python做个AI出牌器,豆子蹭蹭涨!
一起用Python做个车牌自动识别系统,好玩又实用!
桌面太单调?一起用Python做个自定义动态壁纸,竟然还可以放视频!
一起用Python做个自动化弹钢琴脚本,我竟然弹出了《天空之城》!
往期精彩源码均可通过下方公众号获取