Posts: 966
Threads: 104
Joined: Sep 2019
Oct-14-2021, 09:38 AM
(This post was last modified: Oct-14-2021, 10:45 AM by menator01.
Edit Reason: Added code to move listbox highlight
)
Still plan on tweaking and trying to shorten the code but, here is what I have working for now.
#! /usr/bin/env python3
from functools import partial
import sys
from PyQt5.QtCore import Qt, QUrl, QDir
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QGridLayout, \
QFrame, QGraphicsDropShadowEffect, QGraphicsView, QGraphicsScene, QLabel, \
QPushButton, QHBoxLayout, QStyle, QListWidget, QFileDialog
from PyQt5.QtGui import QGradient, QFont, QColor, QCursor, QIcon
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('PyQt Music Player')
self.player = QMediaPlayer()
self.playlist = QMediaPlaylist(self.player)
self.player.setPlaylist(self.playlist)
self.url = QUrl()
# Setup the container
container = QGridLayout()
# Add the widgets
container.addWidget(self._header(), 0, 0, 1, 3)
container.addWidget(self._status(), 1, 0, 1, 1)
container.addWidget(self._track(), 1, 1, 1, 1)
container.addWidget(self._button(), 1, 2, 1, 1)
container.addWidget(self._left(), 2, 0, 2, 1)
container.addWidget(self._right(), 2, 1, 1, 2)
container.addLayout(self._buttons(), 3, 1, 1, 2)
container.addWidget(self._footer(), 4, 0, 1, 3)
widget = QWidget()
widget.setLayout(container)
self.setCentralWidget(widget)
self.playlist.currentIndexChanged.connect(partial(self._update_index))
def _header(self):
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(3)
shadow.setOffset(3, 3)
scene = QGraphicsScene()
view = QGraphicsView()
view.setMinimumSize(800, 100)
view.setMaximumHeight(100)
view.setScene(scene)
gradient = QGradient(QGradient.RichMetal)
scene.setBackgroundBrush(gradient)
font = QFont('comic sans ms', 40, QFont.Bold)
text = scene.addText('PyQt5 Music Player')
text.setDefaultTextColor(QColor(250,250,250))
text.setFont(font)
text.setGraphicsEffect(shadow)
return view
def _update_index(self):
self.music_list.setCurrentRow(self.playlist.currentIndex())
if self.playlist.currentIndex() < 0:
self.music_list.setCurrentRow(0)
def _status(self):
self.status = QLabel('Status: Stopped')
self.status.setFrameShape(QFrame.Box)
self.status.setFrameShadow(QFrame.Sunken)
self.status.setStyleSheet('padding: 5px')
self.status.setMaximumHeight(40)
return self.status
def _track(self):
self.track = QLabel('Track: No track is playing')
self.track.setFrameShape(QFrame.Box)
self.track.setFrameShadow(QFrame.Sunken)
self.track.setStyleSheet('padding: 5px')
self.track.setMaximumHeight(40)
return self.track
def _button(self):
button = QPushButton('Open Folder')
button.setCursor(QCursor(Qt.PointingHandCursor))
button.released.connect(self._get_files)
button.setStyleSheet('''
QPushButton{border: 1px solid gray; padding: 5px; border-style: outset;
background-color: silver;}
QPushButton:hover{ background-color: lightgray; padding: 5px;
border-style: outset; border: 1px solid gray; font-weight: bold;}
QPushButton:pressed {border: 2px solid gray; padding: 5px;
background-color: silver; border-style: inset; font-weight: bold;}
''')
return button
def _get_files(self):
files = QFileDialog.getOpenFileNames(None, 'Audio File Formats', filter='(*.mp3 *.wav *.ogg)')
for file in files[0]:
self.playlist.addMedia(QMediaContent(self.url.fromLocalFile(file)))
file = file.split('/')
self.music_list.addItem(str(file[-1][:-4]))
self.music_list.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
def _left(self):
frame = QFrame()
frame.setFrameShape(frame.Box)
frame.setFrameShadow(frame.Sunken)
frame.setMinimumHeight(300)
return frame
def _right(self):
self.music_list = QListWidget()
self.music_list.setFrameShape(QFrame.Box)
self.music_list.setFrameShadow(QFrame.Sunken)
self.music_list.setStyleSheet('background-color: snow;')
return self.music_list
def _exit(self):
sys.exit()
def _buttons(self):
layout = QHBoxLayout()
buttons = {
'Play': partial(self._command, action='play'), 'Stop': partial(self._command, action='stop'),
'Next': partial(self._command, action='next'), 'Prev': partial(self._command, action='prev'),
'Clear List': partial(self._command, action='clear'), 'Exit':partial(self._exit)
}
for button, cmd in buttons.items():
btn = QPushButton(button)
btn.setCursor(Qt.PointingHandCursor)
btn.released.connect(cmd)
if button == 'Exit':
btn.setStyleSheet('''
QPushButton{background-color: firebrick; color: black;}
QPushButton:hover{background-color: tomato; color: red;
font-weight: bold;}
QPushButton:pressed{background-color: red; color: white; font-weight: normal;}
''')
elif button == 'Clear List':
btn.setStyleSheet('''
QPushButton{background-color: darkorange;}
QPushButton:hover{background-color: orange; color: red; font-weight: bold;}
''')
else:
btn.setStyleSheet('''
QPushButton{background-color: skyblue;}
QPushButton:hover{background-color: lightskyblue; font-weight: bold;}
QPushButton:pressed{background-color: dodgerblue; font-weight: bold;}
''')
layout.addWidget(btn)
return layout
def _command(self, action=None):
if action == 'play':
self.player.play()
elif action == 'stop':
self.player.stop()
elif action == 'next':
self.playlist.next()
self.player.play()
elif action == 'prev':
self.playlist.previous()
self.player.play()
elif action == 'clear':
self.music_list.clear()
self.player.stop()
self.playlist.clear()
self.playlist.setCurrentIndex(0)
self.music_list.setCurrentRow(self.playlist.currentIndex())
if action == 'stop' or action == 'clear':
self.status.setText('Status: Stopped')
else:
if self.music_list.currentItem():
self.track.setText(f'Track: {self.music_list.currentItem().text().title()}')
self.status.setText('Status: Now Playing')
else:
pass
def _footer(self):
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(3)
shadow.setOffset(3, 3)
scene = QGraphicsScene()
view = QGraphicsView()
view.setMinimumSize(800, 40)
view.setMaximumHeight(40)
view.setScene(scene)
gradient = QGradient(QGradient.RichMetal)
scene.setBackgroundBrush(gradient)
font = QFont('comic sans ms', 10, QFont.Bold)
text = scene.addText('my-python.org - 10/10/2021')
text.setDefaultTextColor(QColor(250,250,250))
text.setFont(font)
text.setGraphicsEffect(shadow)
return view
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
main()
Posts: 11,872
Threads: 474
Joined: Sep 2016
There's a bunch of qt5 audio examples here: https://doc.qt.io/qt-5/audiooverview.html
perhaps there's something useful for your app.
Posts: 988
Threads: 15
Joined: Dec 2016
Posts: 966
Threads: 104
Joined: Sep 2019
Thanks for the links guys. Actually I referenced a lot of the code from the qt docs. They are very helpful.
Posts: 966
Threads: 104
Joined: Sep 2019
The above code had issues with the prev/next buttons(worked when I posted). Anyhow I re-wrote the code and all is working now(fingers crossed).
from functools import partial
import os
import sys
from PyQt5.QtCore import Qt, QUrl, QDir
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QGridLayout, \
QFrame, QGraphicsDropShadowEffect, QGraphicsView, QGraphicsScene, QLabel, \
QPushButton, QHBoxLayout, QStyle, QListWidget, QFileDialog, QSlider, QVBoxLayout
from PyQt5.QtGui import QGradient, QFont, QColor, QCursor, QIcon, QPixmap
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist, \
QMediaMetaData
class Window(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('PyQt5 Music Player')
# Create a containers
btn_box = QHBoxLayout()
btn_box2 = QHBoxLayout()
container = QGridLayout()
info_container = QGridLayout()
frame = QFrame()
frame.setFrameShape(QFrame.Box)
frame.setFrameShadow(QFrame.Sunken)
frame.setLayout(info_container)
# Create some variables
self.dir = f'{QDir.currentPath()}'
self.url = QUrl()
self.player = QMediaPlayer()
self.content = QMediaContent()
self.playlist = QMediaPlaylist(self.player)
self.player.setPlaylist(self.playlist)
# Used to changed to notify self.update that the playlist index has changed.
# Will update the highlighted line in the listbox
self.playlist.currentIndexChanged.connect(self.update)
# Signal that the metadate has changed
self.player.metaDataChanged.connect(self.meta_data)
# Labels for the track information
self.artist = QLabel('Artist: ')
self.album_title = QLabel('Album: ')
self.track_title = QLabel('Track: ')
self.released = QLabel('Released: ')
self.genre = QLabel('Genre: ')
self.art = QLabel()
# Add track information to the info container
info_container.addWidget(self.artist, 0, 0, 1, 1)
info_container.addWidget(self.album_title, 1, 0, 1, 1)
info_container.addWidget(self.track_title, 2, 0, 1, 1)
info_container.addWidget(self.released, 3, 0, 1, 1)
info_container.addWidget(self.genre, 4, 0, 1, 1)
info_container.addWidget(self.art, 5, 0, 1, 1)
# Create the status and track labels
self.status = QLabel('Status: ')
self.status.setFrameShape(QFrame.Box)
self.status.setFrameShadow(QFrame.Sunken)
self.track = QLabel('Track: ')
self.track.setFrameShape(QFrame.Box)
self.track.setFrameShadow(QFrame.Sunken)
# Define and create the listbox
self.musiclist = QListWidget()
self.musiclist.setFrameShape(QFrame.Box)
self.musiclist.setFrameShadow(QFrame.Sunken)
self.musiclist.setStyleSheet('background-color: snow;')
# Used for track play when double clicked
self.musiclist.itemDoubleClicked.connect(self._doubleclick)
# Create the control buttons & button styles
btn_style = '''QPushButton{background-color: skyblue;}
QPushButton:hover{background-color: lightskyblue; color: dodgerblue; \
font-weight: bold;}'''
# Create buttons for getting audio files and clearing playlist
file_btn = QPushButton('Get Audio')
file_btn.released.connect(self._files)
file_btn.setCursor(Qt.PointingHandCursor)
file_btn.setStyleSheet(btn_style)
file_btn.setMaximumWidth(100)
clear_btn = QPushButton('Clear List')
clear_btn.released.connect(self._clear)
clear_btn.setCursor(Qt.PointingHandCursor)
clear_btn.setStyleSheet(btn_style)
clear_btn.setMaximumWidth(100)
# Create & style the control buttons
self.play_btn = QPushButton('Play')
self.play_btn.released.connect(self._state)
self.play_btn.setCursor(Qt.PointingHandCursor)
self.play_btn.setStyleSheet(btn_style)
self.prev_btn = QPushButton('Prev')
self.prev_btn.released.connect(self._prev)
self.prev_btn.setCursor(Qt.PointingHandCursor)
self.prev_btn.setStyleSheet(btn_style)
self.next_btn = QPushButton('Next')
self.next_btn.released.connect(self._next)
self.next_btn.setCursor(Qt.PointingHandCursor)
self.next_btn.setStyleSheet(btn_style)
self.stop_btn = QPushButton('Stop')
self.stop_btn.released.connect(self._stop)
self.stop_btn.setCursor(Qt.PointingHandCursor)
self.stop_btn.setStyleSheet(btn_style)
self.exit_btn = QPushButton('Exit')
self.exit_btn.released.connect(sys.exit)
self.exit_btn.setCursor(Qt.PointingHandCursor)
self.exit_btn.setStyleSheet('QPushButton{background-color: firebrick;} \
QPushButton:hover{background-color: red; color: white; \
font-weight: bold;}')
# Add the buttons to layout
btn_box.addWidget(file_btn)
btn_box.addWidget(clear_btn)
btn_box2.addWidget(self.play_btn)
btn_box2.addWidget(self.prev_btn)
btn_box2.addWidget(self.next_btn)
btn_box2.addWidget(self.stop_btn)
btn_box2.addWidget(self.exit_btn)
# Add layouts to container layout
container.addWidget(self._header_footer(100, 100, 40, 'PyQt5 Music Player'), 0, 0, 1, 3)
container.addWidget(self.status, 1, 0, 1, 1)
container.addWidget(self.track, 1, 1, 1, 1)
container.addLayout(btn_box, 1, 2, 1, 1)
container.addWidget(frame, 2, 0, 2, 1)
container.addWidget(self.musiclist, 2, 1, 1, 2)
container.addLayout(btn_box2, 3, 1, 1, 2)
container.addWidget(self._header_footer(40, 40, 10, 'my-python.org - 10/16/2021'), 4, 0, 1, 3)
# Create the widget and add the button box layout
widget = QWidget()
widget.setLayout(container)
self.setCentralWidget(widget)
# Get music metadata
def meta_data(self):
if self.player.isMetaDataAvailable():
self.artist.setText(f'Artist: {self.player.metaData(QMediaMetaData.AlbumArtist)}')
self.album_title.setText(f'Album: {self.player.metaData(QMediaMetaData.AlbumTitle)}')
self.track_title.setText(f'Track: {self.player.metaData(QMediaMetaData.Title)}')
self.released.setText(f'Released: {self.player.metaData(QMediaMetaData.Year)}')
self.genre.setText(f'Genre: {self.player.metaData(QMediaMetaData.Genre)}')
self.track.setText(f'Track: {self.player.metaData(QMediaMetaData.Title)}')
pixmap = QPixmap(self.player.metaData(QMediaMetaData.CoverArtImage))
pixmap = pixmap.scaled(int(pixmap.width()/3), int(pixmap.height()/3))
self.art.setPixmap(pixmap)
# Create the header
def _header_footer(self, minheight, maxheight, fontsize, text):
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(3)
shadow.setOffset(3, 3)
scene = QGraphicsScene()
view = QGraphicsView()
view.setMinimumSize(800, minheight)
view.setMaximumHeight(maxheight)
view.setScene(scene)
gradient = QGradient(QGradient.RichMetal)
scene.setBackgroundBrush(gradient)
font = QFont('comic sans ms', fontsize, QFont.Bold)
text = scene.addText(text)
text.setDefaultTextColor(QColor(250,250,250))
text.setFont(font)
text.setGraphicsEffect(shadow)
return view
# Method for double clicking a track and play
def _doubleclick(self):
self.playlist.setCurrentIndex(self.musiclist.currentRow())
self.player.play()
# Method for clearing the playlist and musiclist
def _clear(self):
self.player.stop()
self.musiclist.clear()
self.playlist.clear()
self.play_btn.setText('Play')
self.status.setText('Status: ')
self.track.setText('Track: ')
self.artist.setText('Artist: ')
self.album_title.setText('Album: ')
self.track_title.setText('Track: ')
self.released.setText('Released: ')
self.genre.setText('Genre: ')
pixmap = QPixmap()
self.art.setPixmap(pixmap)
# Method for adding tracks to the playlist and musiclist
def _files(self):
files = QFileDialog.getOpenFileNames(None, 'Get Audio Files',
filter='Audio Files (*.mp3 *.ogg *.wav)')
for file in files[0]:
self.playlist.addMedia(QMediaContent(self.url.fromLocalFile(file)))
file = file.split('/')
self.musiclist.addItem(f'{file[-1][:-4]}')
self.musiclist.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
# Methods for the control buttons
def _prev(self):
if self.playlist.previousIndex() == -1:
self.playlist.setCurrentIndex(self.playlist.mediaCount()-1)
else:
self.playlist.previous()
def _next(self):
self.playlist.next()
if self.playlist.currentIndex() == -1:
self.playlist.setCurrentIndex(0)
self.player.play()
def _stop(self):
self.player.stop()
self.play_btn.setText('Play')
self.playlist.setCurrentIndex(0)
self.musiclist.setCurrentRow(0)
self.status.setText('Status: Now Stopped')
def _state(self):
if self.playlist.mediaCount() > 0:
if self.player.state() != QMediaPlayer.PlayingState:
self.play_btn.setText('Pause')
self.status.setText('Status: Now Playing')
self.player.play()
else:
self.play_btn.setText('Play')
self.player.pause()
self.status.setText('Status: Now Paused')
else:
pass
# Method for updating the listbox when the playlist updates
def update(self):
self.musiclist.setCurrentRow(self.playlist.currentIndex())
if self.playlist.currentIndex() < 0:
self.musiclist.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
Posts: 988
Threads: 15
Joined: Dec 2016
Much better now. A thought occurred to me.
Why the extra exit button?
Maybe a volume slider makes more sense at this point.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from functools import partial
import os
import sys
from PyQt5.QtCore import Qt, QUrl, QDir
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QGridLayout, \
QFrame, QGraphicsDropShadowEffect, QGraphicsView, QGraphicsScene, QLabel, \
QPushButton, QHBoxLayout, QStyle, QListWidget, QFileDialog, QSlider, QVBoxLayout
from PyQt5.QtGui import QGradient, QFont, QColor, QCursor, QIcon, QPixmap
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist, \
QMediaMetaData
class Window(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('PyQt5 Music Player')
# Create a containers
btn_box = QHBoxLayout()
btn_box2 = QHBoxLayout()
container = QGridLayout()
info_container = QGridLayout()
frame = QFrame()
frame.setFrameShape(QFrame.Box)
frame.setFrameShadow(QFrame.Sunken)
frame.setLayout(info_container)
# Create some variables
self.dir = f'{QDir.currentPath()}'
self.url = QUrl()
self.player = QMediaPlayer()
self.content = QMediaContent()
self.playlist = QMediaPlaylist(self.player)
self.player.setPlaylist(self.playlist)
# Used to changed to notify self.update that the playlist index has changed.
# Will update the highlighted line in the listbox
self.playlist.currentIndexChanged.connect(self.update)
# Signal that the metadate has changed
self.player.metaDataChanged.connect(self.meta_data)
# Labels for the track information
self.artist = QLabel('Artist: ')
self.album_title = QLabel('Album: ')
self.track_title = QLabel('Track: ')
self.released = QLabel('Released: ')
self.genre = QLabel('Genre: ')
self.art = QLabel()
# Add track information to the info container
info_container.addWidget(self.artist, 0, 0, 1, 1)
info_container.addWidget(self.album_title, 1, 0, 1, 1)
info_container.addWidget(self.track_title, 2, 0, 1, 1)
info_container.addWidget(self.released, 3, 0, 1, 1)
info_container.addWidget(self.genre, 4, 0, 1, 1)
info_container.addWidget(self.art, 5, 0, 1, 1)
# Create the status and track labels
self.status = QLabel('Status: ')
self.status.setFrameShape(QFrame.Box)
self.status.setFrameShadow(QFrame.Sunken)
self.track = QLabel('Track: ')
self.track.setFrameShape(QFrame.Box)
self.track.setFrameShadow(QFrame.Sunken)
# Define and create the listbox
self.musiclist = QListWidget()
self.musiclist.setFrameShape(QFrame.Box)
self.musiclist.setFrameShadow(QFrame.Sunken)
self.musiclist.setStyleSheet('background-color: snow;')
# Used for track play when double clicked
self.musiclist.itemDoubleClicked.connect(self._doubleclick)
# Create the control buttons & button styles
btn_style = '''QPushButton{background-color: skyblue;}
QPushButton:hover{background-color: lightskyblue; color: dodgerblue; \
font-weight: bold;}'''
# Create buttons for getting audio files and clearing playlist
file_btn = QPushButton('Get Audio')
file_btn.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
file_btn.released.connect(self._files)
file_btn.setCursor(Qt.PointingHandCursor)
file_btn.setStyleSheet(btn_style)
file_btn.setMaximumWidth(100)
clear_btn = QPushButton('Clear List')
clear_btn.setIcon(self.style().standardIcon(QStyle.SP_TrashIcon))
clear_btn.released.connect(self._clear)
clear_btn.setCursor(Qt.PointingHandCursor)
clear_btn.setStyleSheet(btn_style)
clear_btn.setMaximumWidth(100)
# Create & style the control buttons
self.play_btn = QPushButton('Play')
self.play_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.play_btn.released.connect(self._state)
self.play_btn.setCursor(Qt.PointingHandCursor)
self.play_btn.setStyleSheet(btn_style)
self.prev_btn = QPushButton('Prev')
self.prev_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward))
self.prev_btn.released.connect(self._prev)
self.prev_btn.setCursor(Qt.PointingHandCursor)
self.prev_btn.setStyleSheet(btn_style)
self.next_btn = QPushButton('Next')
self.next_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward))
self.next_btn.released.connect(self._next)
self.next_btn.setCursor(Qt.PointingHandCursor)
self.next_btn.setStyleSheet(btn_style)
self.stop_btn = QPushButton('Stop')
self.stop_btn.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
self.stop_btn.released.connect(self._stop)
self.stop_btn.setCursor(Qt.PointingHandCursor)
self.stop_btn.setStyleSheet(btn_style)
self.vol_slider = QSlider(orientation=1)
self.vol_slider.setFixedWidth(80)
self.vol_slider.setRange(0, 100)
self.vol_slider.valueChanged.connect(self.set_volume)
self.vol_slider.setValue(75)
self.vol_slider.setStyleSheet("""QSlider::groove:horizontal {
border: 1px solid #999999;
height: 8px;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #686da0, stop:1 #c4c4c4);
margin: 2px 0;
}
QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #729fcf, stop:1 #3465a4);
border: 1px solid #5c5c5c;
width: 18px;
margin: -2px 0;
border-radius: 3px;}""")
self.exit_btn = QPushButton('Exit')
self.exit_btn.released.connect(sys.exit)
self.exit_btn.setCursor(Qt.PointingHandCursor)
self.exit_btn.setStyleSheet('QPushButton{background-color: firebrick;} \
QPushButton:hover{background-color: red; color: white; \
font-weight: bold;}')
# Add the buttons to layout
btn_box.addWidget(file_btn)
btn_box.addWidget(clear_btn)
btn_box2.addWidget(self.play_btn)
btn_box2.addWidget(self.prev_btn)
btn_box2.addWidget(self.next_btn)
btn_box2.addWidget(self.stop_btn)
btn_box2.addWidget(self.vol_slider)
# Add layouts to container layout
container.addWidget(self._header_footer(100, 100, 40, 'PyQt5 Music Player'), 0, 0, 1, 3)
container.addWidget(self.status, 1, 0, 1, 1)
container.addWidget(self.track, 1, 1, 1, 1)
container.addLayout(btn_box, 1, 2, 1, 1)
container.addWidget(frame, 2, 0, 2, 1)
container.addWidget(self.musiclist, 2, 1, 1, 2)
container.addLayout(btn_box2, 3, 1, 1, 2)
container.addWidget(self._header_footer(40, 40, 10, 'my-python.org - 10/16/2021'), 4, 0, 1, 3)
# Create the widget and add the button box layout
widget = QWidget()
widget.setLayout(container)
self.setCentralWidget(widget)
def set_volume(self):
self.player.setVolume(self.vol_slider.value())
# Get music metadata
def meta_data(self):
if self.player.isMetaDataAvailable():
self.artist.setText(f'Artist: {self.player.metaData(QMediaMetaData.AlbumArtist)}')
self.album_title.setText(f'Album: {self.player.metaData(QMediaMetaData.AlbumTitle)}')
self.track_title.setText(f'Track: {self.player.metaData(QMediaMetaData.Title)}')
self.released.setText(f'Released: {self.player.metaData(QMediaMetaData.Year)}')
self.genre.setText(f'Genre: {self.player.metaData(QMediaMetaData.Genre)}')
self.track.setText(f'Track: {self.player.metaData(QMediaMetaData.Title)}')
pixmap = QPixmap(self.player.metaData(QMediaMetaData.CoverArtImage))
pixmap = pixmap.scaled(int(pixmap.width()/3), int(pixmap.height()/3))
self.art.setPixmap(pixmap)
# Create the header
def _header_footer(self, minheight, maxheight, fontsize, text):
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(3)
shadow.setOffset(3, 3)
scene = QGraphicsScene()
view = QGraphicsView()
view.setMinimumSize(800, minheight)
view.setMaximumHeight(maxheight)
view.setScene(scene)
gradient = QGradient(QGradient.RichMetal)
scene.setBackgroundBrush(gradient)
font = QFont('comic sans ms', fontsize, QFont.Bold)
text = scene.addText(text)
text.setDefaultTextColor(QColor(250,250,250))
text.setFont(font)
text.setGraphicsEffect(shadow)
return view
# Method for double clicking a track and play
def _doubleclick(self):
self.playlist.setCurrentIndex(self.musiclist.currentRow())
self.player.play()
# Method for clearing the playlist and musiclist
def _clear(self):
self.player.stop()
self.musiclist.clear()
self.playlist.clear()
self.play_btn.setText('Play')
self.status.setText('Status: ')
self.track.setText('Track: ')
self.artist.setText('Artist: ')
self.album_title.setText('Album: ')
self.track_title.setText('Track: ')
self.released.setText('Released: ')
self.genre.setText('Genre: ')
pixmap = QPixmap()
self.art.setPixmap(pixmap)
# Method for adding tracks to the playlist and musiclist
def _files(self):
files = QFileDialog.getOpenFileNames(None, 'Get Audio Files',
filter='Audio Files (*.mp3 *.ogg *.wav)')
for file in files[0]:
self.playlist.addMedia(QMediaContent(self.url.fromLocalFile(file)))
file = file.split('/')
self.musiclist.addItem(f'{file[-1][:-4]}')
self.musiclist.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
# Methods for the control buttons
def _prev(self):
if self.playlist.previousIndex() == -1:
self.playlist.setCurrentIndex(self.playlist.mediaCount()-1)
else:
self.playlist.previous()
def _next(self):
self.playlist.next()
if self.playlist.currentIndex() == -1:
self.playlist.setCurrentIndex(0)
self.player.play()
def _stop(self):
self.player.stop()
self.play_btn.setText('Play')
self.playlist.setCurrentIndex(0)
self.musiclist.setCurrentRow(0)
self.status.setText('Status: Now Stopped')
def _state(self):
if self.playlist.mediaCount() > 0:
if self.player.state() != QMediaPlayer.PlayingState:
self.play_btn.setText('Pause')
self.status.setText('Status: Now Playing')
self.player.setVolume(self.vol_slider.value())
self.player.play()
else:
self.play_btn.setText('Play')
self.player.pause()
self.status.setText('Status: Now Paused')
else:
pass
# Method for updating the listbox when the playlist updates
def update(self):
self.musiclist.setCurrentRow(self.playlist.currentIndex())
if self.playlist.currentIndex() < 0:
self.musiclist.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
Posts: 966
Threads: 104
Joined: Sep 2019
I'm still tweaking. Slider for the track length and a volume control too.
Posts: 988
Threads: 15
Joined: Dec 2016
To avoid the error message if no picture is available.
if self.player.metaData(QMediaMetaData.CoverArtImage):
pixmap = QPixmap(self.player.metaData(QMediaMetaData.CoverArtImage))
pixmap = pixmap.scaled(int(pixmap.width()/3), int(pixmap.height()/3))
self.art.setPixmap(pixmap)
Posts: 966
Threads: 104
Joined: Sep 2019
Oct-17-2021, 10:03 PM
(This post was last modified: Oct-17-2021, 10:03 PM by menator01.)
Thanks Axel_Erfurt. I haven't gotten that error yet.
Here is what I have now. Added a truncate function to shorten text if too long. Added mutagen to get some metadata, mainly for the listbox display. Added a volume control and working slide with tack duration.
from functools import partial
import os
import sys
import mutagen
from PyQt5.QtCore import Qt, QUrl, QDir
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QGridLayout, \
QFrame, QGraphicsDropShadowEffect, QGraphicsView, QGraphicsScene, QLabel, \
QPushButton, QHBoxLayout, QStyle, QListWidget, QFileDialog, QSlider, QVBoxLayout, QDial
from PyQt5.QtGui import QGradient, QFont, QColor, QCursor, QIcon, QPixmap
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist, \
QMediaMetaData
class Window(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('PyQt5 Music Player')
# Create some variables
self.url = QUrl()
self.player = QMediaPlayer()
self.playlist = QMediaPlaylist(self.player)
self.player.setPlaylist(self.playlist)
# Create the status and track labels
common_style = '''
font-weight: bold;
font-size: 10pt;
'''
self.status = QLabel('Status: Now Stopped')
self.status.setStyleSheet(common_style)
self.status.setFrameShape(QFrame.Box)
self.status.setFrameShadow(QFrame.Sunken)
self.track = QLabel('Track: ')
self.track.setStyleSheet(common_style)
self.track.setFrameShape(QFrame.Box)
self.track.setFrameShadow(QFrame.Sunken)
# Labels for the track information
artist = QLabel('Artist:')
artist.setStyleSheet(common_style)
album = QLabel('Album:')
album.setStyleSheet(common_style)
track = QLabel('Track:')
track.setStyleSheet(common_style)
released = QLabel('Album Release:')
released.setStyleSheet(common_style)
genre = QLabel('Genre:')
genre.setStyleSheet(common_style)
self.artist = QLabel()
self.artist.setStyleSheet(common_style)
self.album_title = QLabel()
self.album_title.setStyleSheet(common_style)
self.track_title = QLabel()
self.track_title.setStyleSheet(common_style)
self.released = QLabel()
self.released.setStyleSheet(common_style)
self.genre = QLabel()
self.genre.setStyleSheet(common_style)
self.art = QLabel()
self.art.setContentsMargins(5, 170, 5, 5)
# Timer Label
self._timer = QLabel('Duration: 00:00:00 / 00:00:00')
# Define and create the listbox
self.musiclist = QListWidget()
self.musiclist.setFrameShape(QFrame.Box)
self.musiclist.setFrameShadow(QFrame.Sunken)
self.musiclist.setStyleSheet('background-color: snow;')
# Create some containers
btn_box = QHBoxLayout()
btn_box2 = QHBoxLayout()
slider_box = QVBoxLayout()
slider_box.setContentsMargins(5,80,5,5)
dial_box = QVBoxLayout()
container = QGridLayout()
info_container = QGridLayout()
info_container.setSpacing(8)
frame = QFrame()
frame.setMinimumWidth(390)
frame.setFrameShape(QFrame.Box)
frame.setFrameShadow(QFrame.Sunken)
frame.setLayout(info_container)
img_frame = QFrame()
img_frame.setMinimumHeight(100)
# Create slider frame and control
slider_frame = QFrame()
slider_frame.setFrameShape(QFrame.Box)
slider_frame.setFrameShadow(QFrame.Sunken)
slider_frame.setMinimumHeight(30)
slider_frame.setLayout(slider_box)
self.slider = QSlider(Qt.Horizontal)
slider_box.addWidget(self._timer)
slider_box.addWidget(self.slider)
# Create volume frame and control
dial_frame = QFrame()
dial_frame.setFrameShape(QFrame.Box)
dial_frame.setFrameShadow(QFrame.Sunken)
dial_frame.setLayout(dial_box)
self.dial = QDial()
self.dial.setRange(0, 100)
self.dial.setNotchesVisible(True)
self.dial.setSliderPosition(70)
self.dial.setValue(70)
self.dial.setMinimumWidth(200)
self.dial.setMaximumWidth(200)
self.dial.setMinimumHeight(100)
dial_box.addWidget(QLabel('Volume'))
dial_box.addWidget(self.dial)
# Used to update various aspects of gui
self.playlist.currentIndexChanged.connect(self.update)
self.dial.valueChanged.connect(self._volume, self.dial.value())
self.player.metaDataChanged.connect(self.meta_data)
self.musiclist.itemDoubleClicked.connect(self._doubleclick)
self.player.positionChanged.connect(self.track_position)
self.player.durationChanged.connect(self.duration)
self.slider.valueChanged.connect(self.timer)
# Add track information to the info container
info_container.addWidget(artist, 0, 0, 1, 1)
info_container.addWidget(self.artist, 0, 1, 1, 1)
info_container.addWidget(album, 1, 0, 1, 1)
info_container.addWidget(self.album_title, 1, 1, 1, 1)
info_container.addWidget(track, 2, 0, 1, 1)
info_container.addWidget(self.track_title, 2, 1, 1, 1)
info_container.addWidget(released, 3, 0, 1, 1)
info_container.addWidget(self.released, 3, 1, 1, 1)
info_container.addWidget(genre, 4, 0, 1, 1)
info_container.addWidget(self.genre, 4, 1, 1, 1)
info_container.addWidget(self.art, 5, 0, 1, 2)
# Create the control buttons & button styles
btn_style = '''QPushButton{background-color: skyblue;}
QPushButton:hover{background-color: lightskyblue; color: dodgerblue; \
font-weight: bold;}'''
# Create buttons for getting audio files and clearing playlist
file_btn = QPushButton('Get Audio')
file_btn.released.connect(self._files)
file_btn.setCursor(Qt.PointingHandCursor)
file_btn.setStyleSheet(btn_style)
file_btn.setMaximumWidth(100)
clear_btn = QPushButton('Clear List')
clear_btn.released.connect(self._clear)
clear_btn.setCursor(Qt.PointingHandCursor)
clear_btn.setStyleSheet(btn_style)
clear_btn.setMaximumWidth(100)
# Create & style the control buttons
self.play_btn = QPushButton('Play')
self.play_btn.released.connect(self._state)
self.play_btn.setCursor(Qt.PointingHandCursor)
self.play_btn.setStyleSheet(btn_style)
self.prev_btn = QPushButton('Prev')
self.prev_btn.released.connect(self._prev)
self.prev_btn.setCursor(Qt.PointingHandCursor)
self.prev_btn.setStyleSheet(btn_style)
self.next_btn = QPushButton('Next')
self.next_btn.released.connect(self._next)
self.next_btn.setCursor(Qt.PointingHandCursor)
self.next_btn.setStyleSheet(btn_style)
self.stop_btn = QPushButton('Stop')
self.stop_btn.released.connect(self._stop)
self.stop_btn.setCursor(Qt.PointingHandCursor)
self.stop_btn.setStyleSheet(btn_style)
self.exit_btn = QPushButton('Exit')
self.exit_btn.released.connect(sys.exit)
self.exit_btn.setCursor(Qt.PointingHandCursor)
self.exit_btn.setStyleSheet('QPushButton{background-color: firebrick;} \
QPushButton:hover{background-color: red; color: white; \
font-weight: bold;}')
# Add the buttons to layout
btn_box.addWidget(file_btn)
btn_box.addWidget(clear_btn)
btn_box2.addWidget(self.play_btn)
btn_box2.addWidget(self.prev_btn)
btn_box2.addWidget(self.next_btn)
btn_box2.addWidget(self.stop_btn)
btn_box2.addWidget(self.exit_btn)
# Add layouts to container layout
container.addWidget(self._header_footer(100, 100, 40, 'PyQt5 Music Player'), 0, 0, 1, 3)
container.addWidget(self.status, 1, 0, 1, 1)
container.addWidget(self.track, 1, 1, 1, 1)
container.addLayout(btn_box, 1, 2, 1, 1)
container.addWidget(frame, 2, 0, 2, 1)
container.addWidget(self.musiclist, 2, 1, 1, 2)
container.addLayout(btn_box2, 3, 1, 1, 2)
container.addWidget(slider_frame, 4, 0, 1, 2)
container.addWidget(dial_frame, 4, 2, 1, 1)
container.addWidget(self._header_footer(40, 40, 10, 'my-python.org - 10/16/2021'), 5, 0, 1, 3)
# Create the widget and set layout to container
widget = QWidget()
widget.setLayout(container)
self.setCentralWidget(widget)
# Volume control
def _volume(self, val=70):
self.player.setVolume(val)
# Sets position of slider
def track_position(self, position):
self.slider.setValue(position)
# Duration of the track playing
def duration(self, duration):
self.slider.setRange(0, duration)
# Updates duration of track playing
def timer(self):
total_milliseconds = self.player.duration()
total_seconds, total_milliseconds = divmod(total_milliseconds,1000)
total_minutes, total_seconds = divmod(total_seconds,60)
total_hours, total_minutes = divmod(total_minutes, 60)
elapsed_milliseconds = self.slider.value()
elapsed_seconds, elapsed_milliseconds = divmod(elapsed_milliseconds,1000)
elapsed_minutes, elapsed_seconds = divmod(elapsed_seconds, 60)
elapsed_hours, elapsed_minutes = divmod(elapsed_minutes, 60)
self._timer.setText(f'Duration: {elapsed_hours:02d}:{elapsed_minutes:02d}:{elapsed_seconds:02d} / {total_hours:02d}:{total_minutes:02d}:{total_seconds:02d}')
# Shorten text that may be too long
def _truncate(self, text, length=25):
if len(text) <= length:
return text
else:
return f"{' '.join(text[:length+1].split(' ')[0:-1])} ...."
# Get music metadata
def meta_data(self):
if self.player.isMetaDataAvailable():
self.artist.setText(self.player.metaData(QMediaMetaData.AlbumArtist))
self.album_title.setText(self._truncate(self.player.metaData(QMediaMetaData.AlbumTitle)))
self.track_title.setText(self._truncate(self.player.metaData(QMediaMetaData.Title)))
self.released.setText(f'{self.player.metaData(QMediaMetaData.Year)}')
self.genre.setText(self.player.metaData(QMediaMetaData.Genre))
self.track.setText(f'Track: {self._truncate(self.player.metaData(QMediaMetaData.Title),20)}')
if self.player.metaData(QMediaMetaData.CoverArtImage):
pixmap = QPixmap(self.player.metaData(QMediaMetaData.CoverArtImage))
pixmap = pixmap.scaled(int(pixmap.width()/3), int(pixmap.height()/3))
self.art.setPixmap(pixmap)
self.art.setContentsMargins(0,32 , 0, 5)
# Create the header
def _header_footer(self, minheight, maxheight, fontsize, text):
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(3)
shadow.setOffset(3, 3)
scene = QGraphicsScene()
view = QGraphicsView()
view.setMinimumSize(800, minheight)
view.setMaximumHeight(maxheight)
view.setScene(scene)
gradient = QGradient(QGradient.RichMetal)
scene.setBackgroundBrush(gradient)
font = QFont('comic sans ms', fontsize, QFont.Bold)
text = scene.addText(text)
text.setDefaultTextColor(QColor(250,250,250))
text.setFont(font)
text.setGraphicsEffect(shadow)
return view
# Method for double clicking a track and play
def _doubleclick(self):
self.playlist.setCurrentIndex(self.musiclist.currentRow())
self.player.play()
# Method for clearing the playlist and musiclist
def _clear(self):
self.player.stop()
self.musiclist.clear()
self.playlist.clear()
self.play_btn.setText('Play')
self.status.setText('Status: ')
self.track.setText('Track: ')
self.artist.setText('Artist: ')
self.album_title.setText('Album: ')
self.track_title.setText('Track: ')
self.released.setText('Released: ')
self.genre.setText('Genre: ')
self.art.setContentsMargins(5, 170, 5, 50)
pixmap = QPixmap()
self.art.setPixmap(pixmap)
self.dial.setSliderPosition(70)
self.dial.setValue(70)
# Method for adding tracks to the playlist and musiclist
def _files(self):
files = QFileDialog.getOpenFileNames(None, 'Get Audio Files',
filter='Audio Files (*.mp3 *.ogg *.wav)')
for file in files[0]:
self.playlist.addMedia(QMediaContent(self.url.fromLocalFile(file)))
track = mutagen.File(file)
self.musiclist.addItem(str(track['TIT2']))
self.musiclist.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
# Methods for the control buttons
def _prev(self):
if self.playlist.previousIndex() == -1:
self.playlist.setCurrentIndex(self.playlist.mediaCount()-1)
else:
self.playlist.previous()
def _next(self):
self.playlist.next()
if self.playlist.currentIndex() == -1:
self.playlist.setCurrentIndex(0)
self.player.play()
def _stop(self):
self.player.stop()
self.play_btn.setText('Play')
self.playlist.setCurrentIndex(0)
self.musiclist.setCurrentRow(0)
self.status.setText('Status: Now Stopped')
def _state(self):
if self.playlist.mediaCount() > 0:
if self.player.state() != QMediaPlayer.PlayingState:
self.play_btn.setText('Pause')
self.status.setText('Status: Now Playing')
self.player.play()
else:
self.play_btn.setText('Play')
self.player.pause()
self.status.setText('Status: Now Paused')
else:
pass
# Method for updating the listbox when the playlist updates
def update(self):
self.musiclist.setCurrentRow(self.playlist.currentIndex())
if self.playlist.currentIndex() < 0:
self.musiclist.setCurrentRow(0)
self.playlist.setCurrentIndex(0)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
Posts: 988
Threads: 15
Joined: Dec 2016
You should check whether there is an mp3 tag at all, otherwise the list will remain empty.
Output: mutagen.mp3.HeaderNotFoundError: can't sync to MPEG frame
|