Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
Resource icon

PyQt5 - Python 3.12 Music Player - Part 4

In this tutorial we will be adding functionality to our buttons.
Buttons:
  • Get Audio - Used to get our music file
  • Clear List - Clear the playlist
  • Play/Pause - Will play or pause our music player
  • Prev - Go back to previous track
  • Next - Go to nest track
  • Stop - Stop the music player
  • Exit - Exit the music player
  • Add volume control to dial

In our Controller Class add these lines


Python:
        # Set some variables for our player
        self.url = QUrl
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist(self.player)
        self.player.setPlaylist(self.playlist)

        # Button Commands
        self.window.file_button.released.connect(self.getfiles)
        self.window.clear_button.released.connect(self.clear)
        self.window.play.released.connect(self.state)
        self.window.prev.released.connect(self.prev)
        self.window._next.released.connect(self._next)
        self.window._exit.released.connect(sys.exit)
        self.window.stop.released.connect(self.stop)
       

        # Other commands
        self.playlist.currentIndexChanged.connect(self.update)
        self.window.music_list.itemDoubleClicked.connect(self.doubleclick)
        self.window.dial.valueChanged.connect(self.volume, self.window.dial.value())

Now we need to define some functions:

Python:
def volume(self, val=50):
        self.player.setVolume(val)

    def getfiles(self):
        ''' Method for getting our audio files - Can store multiple select ions '''
        files = QFileDialog.getOpenFileNames(None, 'Get Audio Giles',
                                             filter='Audio Files(*.mp3 *.ogg *.wav)')
        
        # Loop through the files and add them to our playlist
        for file in files[0]:
            self.playlist.addMedia(QMediaContent(self.url.fromLocalFile(file)))
            try:
                track = MP3(file)
                self.window.music_list.addItem(str(track['TIT2']))
            except:
                track = self.truncate(file.rpartition('/')[2].rpartition('.')[0])
                # Adds the track title to our listbox
                self.window.music_list.addItem(track)

        # Set indexes in our playlist and listbox to 0
        self.window.music_list.setCurrentRow(0)
        self.playlist.setCurrentIndex(0)
        
    def truncate(self, text, length=25):
        # method shortens the text track a little
        if text:
            if len(text) <= length:
                return text
            else:
                return f"{' '.join(text[:length+1].split( ' ')[0:-1])} ..."

    def clear(self):
        ''' Method clears everthing. More will be added here later. '''
        self.player.stop()
        self.window.music_list.clear()
        self.playlist.clear()
        self.window.play.setText('Play')
        
    def state(self):
        ''' Method checks the state of the music player and append correct text
            to the play button '''
        if self.playlist.mediaCount() > 0:
            if self.player.state() != QMediaPlayer.PlayingState:
                self.window.play.setText('Paused')
                self.player.play()
            else:
                self.window.play.setText('Play')
                self.player.pause()
            
    def _next(self):
        ''' method for moving to next track '''
        self.playlist.next()
        if self.playlist.currentIndex() == -1:
            self.playlist.setCurrentIndex(0)
            self.player.play()
    
    def prev(self):
        ''' Method for going to previous track '''
        if self.playlist.previousIndex() == -1:
            self.playlist.setCurrentIndex(self.playlist.mediaCount()-1)
        else:
            self.playlist.previous()
            
    def stop(self):
        ''' method stops music player and resets indexes. '''
        self.player.stop()
        self.window.play.setText('Play')
        self.playlist.setCurrentIndex(0)
        self.window.music_list.setCurrentRow(0)

    def update(self):
        ''' Method updates our list box highlight with the playlist '''
        self.window.music_list.setCurrentRow(self.playlist.currentIndex())
        if self.playlist.currentIndex() < 0:
            self.window.music_list.setCurrentRow(0)
            self.playlist.setCurrentIndex(0)

    def doubleclick(self):
        ''' method plays a track that has been double clicked in the listbox .'''
        self.playlist.setCurrentIndex(self.window.music_list.currentRow())
        self.player.play()

And now our music.py should be looking something like this.

Python:
# Do the imports
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout, QLabel,
                             QFrame, QHBoxLayout, QPushButton, QListWidget, QVBoxLayout, \
                                QDial, QFileDialog)
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtMultimedia import (QMediaPlayer, QMediaContent, QMediaPlaylist,
                                QMediaMetaData)
from mutagen.mp3 import MP3

class Data:
    pass

class Window(QMainWindow):
    ''' Class will handle the display '''
    def __init__(self):
        QMainWindow.__init__(self)

        self.setWindowTitle('My Music Player')

        # Sets a fixed size for the window
        self.setFixedSize(1280,720)

        # Create a main container - will hold all other widgets and layouts
        container = QGridLayout()

        # Create a header label
        header = QLabel('My Music Player')
        header.setFrameShape(QFrame.Shape.Box)
        header.setFrameShadow(QFrame.Shadow.Raised)
        header.setLineWidth(3)

        # Just like in css - set color and background color and the like. Is a bit limited.
        header.setStyleSheet('font-size: 48px; color: gold; \
                             font-weight: bold; font-family: comic sans ms; \
                             background-color: seagreen; padding: 10px;')
        
        # Aligning the text to the center
        header.setAlignment(Qt.AlignmentFlag.AlignCenter)

        # Set some common font styles
        common_style = ''' font-weight: bold; font-size: 10pt; padding: 3px; '''

        # Status Bars
        self.status = QLabel('Status: Now Stopped')
        self.status.setStyleSheet(common_style)
        self.status.setFrameShape(QFrame.Shape.Box)
        self.status.setFrameShadow(QFrame.Shadow.Sunken)

        self.track = QLabel('Track: ')
        self.track.setStyleSheet(common_style)
        self.track.setFrameShape(QFrame.Shape.Box)
        self.track.setFrameShadow(QFrame.Shadow.Sunken)

        # To Buttons
        btn_style = ''' QPushButton{background-color: skyblue;}
                        QPushButton:hover{background-color: lightskyblue; \
                            color: dodgetblue; font-weight: bold;}'''
        
        self.file_button = QPushButton('Get Audio')
        self.file_button.setStyleSheet(btn_style)
        self.file_button.setCursor(Qt.CursorShape.PointingHandCursor)

        self.clear_button = QPushButton('Clear List')
        self.clear_button.setStyleSheet(btn_style)
        self.clear_button.setCursor(Qt.CursorShape.PointingHandCursor)

        # Continaer to hold top button
        box1 = QHBoxLayout()

        box1.addWidget(self.file_button)
        box1.addWidget(self.clear_button)

        # Info Containers
        info_container = QGridLayout()

        # Using a frame to get a border around the info_container
        frame = QFrame()
        frame.setFrameShape(QFrame.Shape.Box)
        frame.setFrameShadow(QFrame.Shadow.Sunken)
        frame.setLayout(info_container)

        
        # Artist Labels Static
        artist = QLabel('Artist:')
        album = QLabel('Album:')
        _track = QLabel('Track:')
        release = QLabel('Album Release:')
        genre = QLabel('Genre:')

        # Empty labels used as place holders. Text will show when a track is playing
        self.artist = QLabel()
        self.album = QLabel()
        self._track = QLabel()
        self.release = QLabel()
        self.genre = QLabel()
        self.art = QLabel()

        img_frame = QFrame()
        img_frame.setFrameShape(QFrame.Shape.Box)
        img_frame.setFrameShadow(QFrame.Shadow.Sunken)
        img_frame.setFixedSize(400,300)

        

        # Numers relate to a grid - row, column, occupy how many rows, how many columns
        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, 1, 1, 1, 1)

        info_container.addWidget(_track, 2, 0, 1, 1)
        info_container.addWidget(self._track, 2, 1, 1, 1)

        info_container.addWidget(release, 3, 0, 1, 1)
        info_container.addWidget(self.release, 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)

        info_container.addWidget(img_frame, 6, 0, 1, 2)

        # Create a listbox to hold tracks
        self.music_list = QListWidget()

        # Container for buttons stop, play, next, back, and exit
        btn_container = QHBoxLayout()

        self.play = QPushButton('Play')
        self.play.setStyleSheet(btn_style)
        self.play.setCursor(Qt.CursorShape.PointingHandCursor)

        self.prev = QPushButton('Prev')
        self.prev.setStyleSheet(btn_style)
        self.prev.setCursor(Qt.CursorShape.PointingHandCursor)

        self._next = QPushButton('Next')
        self._next.setStyleSheet(btn_style)
        self._next.setCursor(Qt.CursorShape.PointingHandCursor)

        self.stop = QPushButton('Stop')
        self.stop.setCursor(Qt.CursorShape.PointingHandCursor)
        self.stop.setStyleSheet(btn_style)

        self._exit = QPushButton('Exit')
        self._exit.setCursor(Qt.CursorShape.PointingHandCursor)
        self._exit.setStyleSheet('QPushButton{background-color: firebrick;} \
                                 QPushButton:hover{background-color: red; color: white; \
                                 font-weight: bold;}')

        # Add buttons to button container
        btn_container.addWidget(self.play)
        btn_container.addWidget(self.prev)
        btn_container.addWidget(self._next)
        btn_container.addWidget(self.stop)
        btn_container.addWidget(self._exit)

        # Placeholder
        holder = QFrame()
        holder.setFrameShape(QFrame.Shape.Box)
        holder.setFrameShadow(QFrame.Shadow.Sunken)

        # Volume Controller - Creating the box give the light gray square
        dialbox = QVBoxLayout()
        dialframe = QFrame()
        dialframe.setFrameShape(QFrame.Shape.Box)
        dialframe.setFrameShadow(QFrame.Shadow.Sunken)
        dialframe.setLayout(dialbox)

        # QDial creates the object, setRange - the range for volume
        # setNotchesVisible - the ticks around the dial
        # setSliderPosition sets the default volume
        # setValues is used for passing variables
        self.dial = QDial()
        self.dial.setRange(0, 100)
        self.dial.setNotchesVisible(True)
        self.dial.setSliderPosition(50)
        self.dial.setValue(50)

        # The volume label in with the dial control
        dialbox.addWidget(QLabel('Volume'))
        dialbox.addWidget(self.dial)
                
        # section for adding widgets to main container
        container.addWidget(header, 0, 0, 1, 3, Qt.AlignmentFlag.AlignTop)
        container.addWidget(self.status, 1, 0, 1, 1)
        container.addWidget(self.track, 1, 1, 1, 1)
        container.addLayout(box1, 1, 2, 1, 1)
        container.addWidget(frame, 2, 0, 2, 1)
        container.addWidget(self.music_list, 2, 1, 1, 2)
        container.addLayout(btn_container, 3, 1, 1, 2)
        container.addWidget(holder, 4, 0, 1, 2)
        container.addWidget(dialframe, 4, 2, 1, 1)

        # Sets main layout
        widget = QWidget()
        widget.setLayout(container)
        self.setCentralWidget(widget)


class Controller:
    def __init__(self, window):
        self.window = window

        # Set some variables for our player
        self.url = QUrl
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist(self.player)
        self.player.setPlaylist(self.playlist)

        # Button Commands
        self.window.file_button.released.connect(self.getfiles)
        self.window.clear_button.released.connect(self.clear)
        self.window.play.released.connect(self.state)
        self.window.prev.released.connect(self.prev)
        self.window._next.released.connect(self._next)
        self.window._exit.released.connect(sys.exit)
        self.window.stop.released.connect(self.stop)
        

        # Other commands
        self.playlist.currentIndexChanged.connect(self.update)
        self.window.music_list.itemDoubleClicked.connect(self.doubleclick)
        self.window.dial.valueChanged.connect(self.volume, self.window.dial.value())

    def volume(self, val=50):
        self.player.setVolume(val)

    def getfiles(self):
        ''' Method for getting our audio files - Can store multiple select ions '''
        files = QFileDialog.getOpenFileNames(None, 'Get Audio Giles',
                                             filter='Audio Files(*.mp3 *.ogg *.wav)')
        
        # Loop through the files and add them to our playlist
        for file in files[0]:
            self.playlist.addMedia(QMediaContent(self.url.fromLocalFile(file)))
            try:
                track = MP3(file)
                self.window.music_list.addItem(str(track['TIT2']))
            except:
                track = self.truncate(file.rpartition('/')[2].rpartition('.')[0])
                # Adds the track title to our listbox
                self.window.music_list.addItem(track)

        # Set indexes in our playlist and listbox to 0
        self.window.music_list.setCurrentRow(0)
        self.playlist.setCurrentIndex(0)
        
    def truncate(self, text, length=25):
        # method shortens the text track a little
        if text:
            if len(text) <= length:
                return text
            else:
                return f"{' '.join(text[:length+1].split( ' ')[0:-1])} ..."

    def clear(self):
        ''' Method clears everthing. More will be added here later. '''
        self.player.stop()
        self.window.music_list.clear()
        self.playlist.clear()
        self.window.play.setText('Play')
        
    def state(self):
        ''' Method checks the state of the music player and append correct text
            to the play button '''
        if self.playlist.mediaCount() > 0:
            if self.player.state() != QMediaPlayer.PlayingState:
                self.window.play.setText('Paused')
                self.player.play()
            else:
                self.window.play.setText('Play')
                self.player.pause()
            
    def _next(self):
        ''' method for moving to next track '''
        self.playlist.next()
        if self.playlist.currentIndex() == -1:
            self.playlist.setCurrentIndex(0)
            self.player.play()
    
    def prev(self):
        ''' Method for going to previous track '''
        if self.playlist.previousIndex() == -1:
            self.playlist.setCurrentIndex(self.playlist.mediaCount()-1)
        else:
            self.playlist.previous()
            
    def stop(self):
        ''' method stops music player and resets indexes. '''
        self.player.stop()
        self.window.play.setText('Play')
        self.playlist.setCurrentIndex(0)
        self.window.music_list.setCurrentRow(0)

    def update(self):
        ''' Method updates our list box highlight with the playlist '''
        self.window.music_list.setCurrentRow(self.playlist.currentIndex())
        if self.playlist.currentIndex() < 0:
            self.window.music_list.setCurrentRow(0)
            self.playlist.setCurrentIndex(0)

    def doubleclick(self):
        ''' method plays a track that has been double clicked in the listbox .'''
        self.playlist.setCurrentIndex(self.window.music_list.currentRow())
        self.player.play()

if __name__ == '__main__':
    app = QApplication([])
    controller = Controller(Window())
    controller.window.show()
    sys.exit(app.exec())

We now should have a working music player. In the next tutorial we will be adding some display data to our music player.
Back
Top Bottom