Python Forum
PyQt5 Music Player - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: General (https://python-forum.io/forum-1.html)
+--- Forum: Code sharing (https://python-forum.io/forum-5.html)
+--- Thread: PyQt5 Music Player (/thread-35265.html)

Pages: 1 2 3


PyQt5 Music Player - menator01 - Oct-14-2021

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()



RE: PyQt5 Music Player - Larz60+ - Oct-14-2021

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.


RE: PyQt5 Music Player - Axel_Erfurt - Oct-14-2021

https://doc.qt.io/qt-5/audiooverview.html examples are in C++

you can find python examples at https://github.com/baoboa/pyqt5/tree/master/examples


RE: PyQt5 Music Player - menator01 - Oct-15-2021

Thanks for the links guys. Actually I referenced a lot of the code from the qt docs. They are very helpful.


RE: PyQt5 Music Player - menator01 - Oct-16-2021

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()



RE: PyQt5 Music Player - Axel_Erfurt - Oct-16-2021

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()



RE: PyQt5 Music Player - menator01 - Oct-16-2021

I'm still tweaking. Slider for the track length and a volume control too.


RE: PyQt5 Music Player - Axel_Erfurt - Oct-17-2021

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)



RE: PyQt5 Music Player - menator01 - Oct-17-2021

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()



RE: PyQt5 Music Player - Axel_Erfurt - Oct-18-2021

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