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