• Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

PyQt5 Music Player

menator01

Silver Coder
Thought I would post a project from a while back.
Requires:
  • PyQt5
  • mutagen
  • requests
Python:
#! /usr/bin/env python3.9
# PtQt5 Music Player
# Copyright (C) 2021 menator01
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
import os
import sys
from mutagen.mp3 import MP3
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QGridLayout, \
QFrame, QGraphicsDropShadowEffect, QGraphicsView, QGraphicsScene, QLabel, \
QPushButton, QHBoxLayout, QListWidget, QFileDialog, QSlider, QVBoxLayout, QDial
from PyQt5.QtGui import QGradient, QFont, QColor, QIcon, QPixmap, QImage
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist, \
QMediaMetaData
# from urllib.request import urlopen
import requests
class Window(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle('PyQt5 Music Player')
        self.setFixedSize(1024,720)
        # Set taskbar icon
        img_url = 'https://my-python.org/images/png/ratt.png'
        image = QImage()
        image.loadFromData(requests.get(img_url).content)
        self.setWindowIcon(QIcon(QPixmap(image)))
        # 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)
        # 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 and set the 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 text:
            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():
            if self.player.metaData(QMediaMetaData.AlbumArtist):
                self.artist.setText(self.player.metaData(QMediaMetaData.AlbumArtist))
            if self.player.metaData(QMediaMetaData.AlbumTitle):
                self.album_title.setText(self._truncate(self.player.metaData(QMediaMetaData.AlbumTitle)))
            if self.player.metaData(QMediaMetaData.Title):
                self.track_title.setText(self._truncate(self.player.metaData(QMediaMetaData.Title)))
            if self.player.metaData(QMediaMetaData.Year):
                self.released.setText(f'{self.player.metaData(QMediaMetaData.Year)}')
            if self.player.metaData(QMediaMetaData.Genre):
                self.genre.setText(self.player.metaData(QMediaMetaData.Genre))
            if self.player.metaData(QMediaMetaData.Title):
                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)))
            try:
                track = MP3(file)
                self.musiclist.addItem(str(track['TIT2']))
            except:
                track = self._truncate(file.rpartition('/')[2].rpartition('.')[0])
                self.musiclist.addItem(track)
        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()
To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.
 
Last edited:

New Threads

Latest posts

Buy us a coffee!

300x250
Top Bottom