I left off the header and footer and revamped the code a little.
Track info updates better and gets some data from the internet radio stations.
I can't seem to find a way to get the station names without the player playing. (Want to use the station names to the musiclist instead of the urls)
Track info updates better and gets some data from the internet radio stations.
I can't seem to find a way to get the station names without the player playing. (Want to use the station names to the musiclist instead of the urls)
#! /usr/bin/env python3.9 import sys from mutagen.mp3 import MP3 from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist, QMediaMetaData from PyQt5.QtCore import QUrl, Qt from PyQt5.QtWidgets import QApplication, QMainWindow, QListWidget, QWidget, QHBoxLayout, \ QVBoxLayout, QGridLayout, QLabel, QPushButton, QFrame, QSlider, \ QStyle, QRadioButton, QFileDialog from PyQt5.QtGui import QIcon, QPixmap class Window(QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Set the window title self.setWindowTitle('PyQt5 Audio Player') # Set some variables self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.musiclist = QListWidget() self.player.setPlaylist(self.playlist) # Changes cursor to hand when over button or link self.hand = Qt.PointingHandCursor # Set the spacing on the musiclist self.musiclist.setSpacing(2) # Create the needed containers container = QGridLayout() container.setSpacing(0) info_container = QGridLayout() info_frame = QFrame() info_frame.setContentsMargins(0, 3, 2, 3) info_frame.setMinimumHeight(300) info_frame.setMaximumWidth(361) info_frame.setFrameShape(QFrame.Box) info_frame.setFrameShadow(QFrame.Sunken) info_frame.setLayout(info_container) radio_frame = QFrame() radio_frame.setContentsMargins(0,0,0,0) radio_frame.setFrameShape(QFrame.Box) radio_frame.setFrameShadow(QFrame.Sunken) radio_frame.setMinimumHeight(60) radio_frame.setMaximumHeight(60) radio_container = QGridLayout() radio_frame.setLayout(radio_container) # Frame for the slider slider_box = QGridLayout() slider_frame = QFrame() slider_frame.setContentsMargins(0, 3, 2, 3) slider_frame.setFrameShape(QFrame.Box) slider_frame.setFrameShadow(QFrame.Sunken) slider_frame.setLayout(slider_box) # Control Box to hold volume, play, next, prev, stop control_box = QGridLayout() control_frame = QFrame() control_frame.setFrameShape(QFrame.Box) control_frame.setFrameShadow(QFrame.Sunken) control_frame.setContentsMargins(4,4,1,4) control_frame.setLayout(control_box) # Create some common styles self.musiclist.setFrameShadow(QFrame.Sunken) self.musiclist.setStyleSheet(''' margin-top: 3px; margin-bottom: 3px; margin-left: 2px; background-color: snow; padding: 12px; ''') style = ''' background-color: snow; padding-left: 8px; padding-right: 20px; border: 1px solid lightgray; font-weight: bold; font-size: 10pt; ''' style2 = ''' background-color: snow; padding-left: 8px; padding-right: 20px; border: 1px solid lightgray; font-weight: 400; font-size: 10pt; color: navy; ''' # Common button style self.btn_style = ''' QPushButton{background-color: skyblue; color: navy; font-size: 10pt; font-weight: 500; padding: 6px; margin-left: 6px;} QPushButton:hover{background-color: lightskyblue; color: blue; font-weight: 600; padding: 6px;} QPushButton:pressed{background-color: dodgerblue; color: lightblue; font-weight: 400; padding: 4px;} ''' # Create the needed labels. Labels without self will not change data. #Labels with self will change data status_label = QLabel('Status:') status_label.setMinimumHeight(30) status_label.setMaximumHeight(30) status_label.setMinimumWidth(80) status_label.setMaximumWidth(80) status_label.setStyleSheet(style) self.status_label = QLabel('Now Stopped') self.status_label.setMinimumHeight(30) self.status_label.setMaximumHeight(30) self.status_label.setMinimumWidth(200) self.status_label.setMaximumWidth(200) self.status_label.setStyleSheet(style2) track_label = QLabel('Track:') track_label.setMinimumHeight(30) track_label.setMaximumHeight(30) track_label.setMinimumWidth(80) track_label.setMaximumWidth(80) track_label.setStyleSheet(style) self.track_label = QLabel() self.track_label.setMinimumHeight(30) self.track_label.setMaximumHeight(30) self.track_label.setMinimumWidth(420) self.track_label.setStyleSheet(style2) artist = QLabel('Artist:') artist.setStyleSheet(style) artist.setMaximumHeight(30) artist.setMinimumHeight(30) title = QLabel('Title:') title.setStyleSheet(style) title.setMaximumHeight(30) title.setMinimumHeight(30) album = QLabel('Album') album.setStyleSheet(style) album.setMaximumHeight(30) album.setMinimumHeight(30) released = QLabel('Released:') released.setStyleSheet(style) released.setMaximumHeight(30) released.setMinimumHeight(30) genre = QLabel('Genre:') genre.setStyleSheet(style) genre.setMaximumHeight(30) genre.setMinimumHeight(30) self.artist = QLabel() self.artist.setStyleSheet(style2) self.artist.setMinimumWidth(235) self.artist.setMaximumHeight(30) self.artist.setMinimumHeight(30) self.title = QLabel() self.title.setStyleSheet(style2) self.title.setMinimumWidth(235) self.title.setMaximumHeight(30) self.title.setMinimumHeight(30) self.album = QLabel() self.album.setStyleSheet(style2) self.album.setMinimumWidth(235) self.album.setMaximumHeight(30) self.album.setMinimumHeight(30) self.released = QLabel() self.released.setStyleSheet(style2) self.released.setMinimumWidth(235) self.released.setMaximumHeight(30) self.released.setMinimumHeight(30) self.genre = QLabel() self.genre.setStyleSheet(style2) self.genre.setMinimumWidth(235) self.genre.setMaximumHeight(30) self.genre.setMinimumHeight(30) self.cover_art = QLabel() self.cover_art.setMinimumSize(300, 300) self.cover_art.setFrameShape(QFrame.Box) self.cover_art.setFrameShadow(QFrame.Sunken) # Just a couple of spacers to keep everything push up when expanding self.spacer = QLabel() self.spacer2 = QLabel() self.duration_labelheader = QLabel('Duration:') self.duration_labelheader.setMinimumHeight(40) self.duration_labelheader.setMaximumHeight(40) self.duration_labelheader.setStyleSheet('font-size: 11pt; font-weight:500;') self.duration_timer = QLabel('00:00:00/00:00:00') self.duration_timer.setStyleSheet('font-size: 10pt; font-weight: 400; color: gray;') # Create the buttons self.get_btn = QPushButton('Get Audio') self.get_btn.setStyleSheet(self.btn_style) self.get_btn.setCursor(self.hand) self.get_btn.released.connect(self._files) clear_btn = QPushButton('Clear Playlist') clear_btn.setStyleSheet(self.btn_style) clear_btn.setCursor(self.hand) clear_btn.released.connect(self._clear) self.volume_slider = QSlider(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setTickInterval(10) self.volume_slider.setValue(70) self.volume_slider.setTickPosition(QSlider.TicksAbove) self.volume_label = QLabel(f'Volume: {self.volume_slider.value()}') self.volume_label.setMinimumWidth(200) self.volume_label.setStyleSheet('font-size: 11pt; padding-left: 25px;') self.play_btn = QPushButton() self.play_btn.setIcon(self.play_btn.style().standardIcon(QStyle.SP_MediaPlay)) self.play_btn.setCursor(self.hand) self.play_btn.released.connect(self.player.play) stop_btn = QPushButton() stop_btn.setIcon(stop_btn.style().standardIcon(QStyle.SP_MediaStop)) stop_btn.setCursor(self.hand) stop_btn.released.connect(self.player.stop) prev_btn = QPushButton() prev_btn.setIcon(prev_btn.style().standardIcon(QStyle.SP_MediaSkipBackward)) prev_btn.setCursor(self.hand) prev_btn.released.connect(self._prev) next_btn = QPushButton() next_btn.setIcon(next_btn.style().standardIcon(QStyle.SP_MediaSkipForward)) next_btn.setCursor(self.hand) next_btn.released.connect(self._next) # Radio buttons to choose internet radio or local files self.radio_btn = QRadioButton('Internet Radio') self._local_file_btn = QRadioButton('Local Files') self._local_file_btn.setChecked(True) # Create the slider for track length self.track_slider = QSlider(Qt.Horizontal) self.track_slider.setRange(0, 100) self.track_slider.setTickInterval(10) self.track_slider.setTickPosition(QSlider.TicksAbove) # Add the control buttons to the control box control_box.addWidget(self.volume_slider, 0,0, 1, 1) control_box.addWidget(self.volume_label, 0, 1, 1, 1) control_box.addWidget(self.play_btn, 0, 2, 1, 1) control_box.addWidget(stop_btn,0, 3, 1, 1) control_box.addWidget(prev_btn,0, 4, 1, 1) control_box.addWidget(next_btn, 0, 5, 1, 1) # Add the radio buttons to the radio container radio_container.addWidget(self.radio_btn, 0, 0, 1, 1) radio_container.addWidget(self._local_file_btn, 0, 1, 1, 1) # Add the slider to the slider box slider_box.addWidget(self.duration_labelheader, 0, 0, 1, 1) slider_box.addWidget(self.duration_timer, 0, 1, 1, 1) slider_box.addWidget(self.track_slider,1, 0,1, 3) # Add widgets to info_frame/container info_container.addWidget(artist, 0, 0, 1, 1) info_container.addWidget(title, 1, 0, 1, 1) info_container.addWidget(album, 2, 0, 1, 1) info_container.addWidget(released, 3, 0, 1, 1) info_container.addWidget(genre, 4, 0, 1, 1) info_container.addWidget(self.artist, 0, 1, 1, 1) info_container.addWidget(self.title, 1, 1, 1, 1) info_container.addWidget(self.album, 2, 1, 1, 1) info_container.addWidget(self.released, 3, 1, 1, 1) info_container.addWidget(self.genre, 4, 1, 1, 1) info_container.addWidget(self.cover_art, 5, 0, 1, 3) info_container.addWidget(self.spacer, 6, 0, 1, 3) info_container.addWidget(self.spacer2, 7, 0, 1, 3) info_container.addWidget(radio_frame, 8, 0, 1, 3) # Add widgets and layout to container layout container.addWidget(status_label, 1, 0, 1, 1) container.addWidget(self.status_label, 1, 1, 1, 1) container.addWidget(track_label, 1, 2, 1, 1) container.addWidget(self.track_label, 1, 3, 1, 1) container.addWidget(self.get_btn, 1, 4, 1, 1) container.addWidget(clear_btn, 1, 5, 1, 1) container.addWidget(info_frame, 2, 0, 1, 4) container.addWidget(self.musiclist,2, 3, 1, 3) container.addWidget(slider_frame, 3, 0, 1, 3) container.addWidget(control_frame, 3, 3, 1, 3) widget = QWidget() widget.setLayout(container) self.setCentralWidget(widget) # Set channels for updates and changes happening in the gui self.volume_slider.valueChanged.connect(self._volume, self.volume_slider.value()) self.radio_btn.toggled.connect(self._music) self.player.metaDataChanged.connect(self._update) self.player.stateChanged.connect(self._state) self.player.positionChanged.connect(self._slider_pos) self.player.durationChanged.connect(self._duration) self.track_slider.valueChanged.connect(self._timer) self.musiclist.itemDoubleClicked.connect(self._doubleclick) # Method for playing a track if double clicked in the music list def _doubleclick(self): self.playlist.setCurrentIndex(self.musiclist.currentRow()) self.player.play() # Method for updating slider position def _slider_pos(self, position): self.track_slider.setValue(position) # Method for setting the range of the duration def _duration(self, duration): self.track_slider.setRange(0, duration) # Updates the duration timer 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.track_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.duration_timer.setText(f'{elapsed_hours:02d}:{elapsed_minutes:02d}:{elapsed_seconds:02d} / {total_hours:02d}:{total_minutes:02d}:{total_seconds:02d}') # Checks player state and updates accorrdingly def _state(self): if self.player.state() == self.player.PlayingState: self.play_btn.setIcon(self.play_btn.style().standardIcon(QStyle.SP_MediaPause)) self.play_btn.released.connect(self.player.pause) self.status_label.setText('Now Playing') elif self.player.state() == self.player.PausedState: self.play_btn.setIcon(self.play_btn.style().standardIcon(QStyle.SP_MediaPlay)) self.play_btn.released.connect(self.player.play) self.status_label.setText('Now Paused') else: self.play_btn.setIcon(self.play_btn.style().standardIcon(QStyle.SP_MediaPlay)) self.play_btn.released.connect(self.player.play) self.status_label.setText('Now Stopped') # Methods for the next/prev actions def _prev(self): if self.playlist.previousIndex() == -1: self.playlist.setCurrentIndex(self.playlist.mediaCount()-1) else: self.playlist.previous() if self.playlist.currentIndexChanged: self.musiclist.setCurrentRow(self.playlist.currentIndex()) self.player.play() def _next(self): self.playlist.next() if self.playlist.currentIndex() == -1: self.playlist.setCurrentIndex(0) self.musiclist.setCurrentRow(self.playlist.currentIndex()) self.player.play() # Method for getting the music files 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(QUrl.fromLocalFile(file))) try: self.track = MP3(file) self.musiclist.addItem(str(self.track['TIT2'])) except: self.track = self._truncate(file.rpartition('/')[2].rpartition('.')[0]) self.musiclist.addItem(self.track) self.musiclist.setCurrentRow(0) self.playlist.setCurrentIndex(0) # Method for updating much of the text information def _update(self): self.musiclist.setCurrentRow(self.playlist.currentIndex()) try: if self.player.isMetaDataAvailable(): if self.player.metaData(QMediaMetaData.AlbumArtist): self.artist.setText(self.player.metaData(QMediaMetaData.AlbumArtist)) if self.player.metaData(QMediaMetaData.Title): if self.radio_btn.isChecked(): info = self.player.metaData(QMediaMetaData.Title).split('-') self.artist.setText(info[0]) self.title.setText(info[1]) self.track_label.setText(info[1]) else: self.title.setText(self._truncate(self.player.metaData(QMediaMetaData.Title))) self.track_label.setText(self._truncate(self.player.metaData(QMediaMetaData.Title))) if self.player.metaData(QMediaMetaData.AlbumTitle): self.album.setText(self._truncate(self.player.metaData(QMediaMetaData.AlbumTitle))) 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.CoverArtImage): pixmap = QPixmap(self.player.metaData(QMediaMetaData.CoverArtImage)) pixmap = pixmap.scaled(328, 295) self.cover_art.setPixmap(pixmap) self.cover_art.setStyleSheet('padding: 5px;') else: self.artist.setText('') self.title.setText('') self.album.setText('') self.released.setText('') self.genre.setText('') self.cover_art.setPixmap(QPixmap()) self.track_label.setText('') except TypeError: pass # Method for shortening text def _truncate(self, text, length=25): if text: if len(text) <= length: return text else: return f"{' '.join(text[:length+1].split(' ')[0:-1])} ...." # Method for playing either radio or local audio files def _music(self): if self.radio_btn.isChecked(): self.musiclist.clear() self.playlist.clear() self.get_btn.setEnabled(False) self.get_btn.setStyleSheet('''QPushButton{background-color: lightgray; color: black; font-size: 10pt; font-weight: 50; padding: 6px; margin-left: 6px;}''') stations = [ 'http://us4.internet-radio.com:8258/stream', 'http://us5.internet-radio.com:8267/stream', 'https://us9.maindigitalstream.com/ssl/bigrock991', 'https://playerservices.streamtheworld.com/api/livestream-redirect/KGFKAM.mp3', 'https://cob-ais.leanstream.co/CFJBFM-MP3', 'http://37.59.195.28:8045', 'https://playerservices.streamtheworld.com/api/livestream-redirect/WIRLAM.mp3', 'https://ais-sa2.cdnstream1.com/2383_128' ] for station in stations: self.playlist.addMedia(QMediaContent(QUrl(station))) self.musiclist.addItem(station) self.player.play() else: self._clear() self.get_btn.setEnabled(True) self.get_btn.setStyleSheet(self.btn_style) # Method for updating the volume def _volume(self, value): self.volume_label.setText(f'Volume: {value}') self.player.setVolume(value) # Method for clearing playlist, musiclist, and other data def _clear(self): self.playlist.clear() self.musiclist.clear() self.status_label.setText('Now Stopped') self.track_label.setText('') self._local_file_btn.setChecked(True) self._update() def main(): app = QApplication(sys.argv) window = Window() window.show() sys.exit(app.exec()) if __name__ == '__main__': main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags