├── .gitignore ├── README.md └── music_player.py /.gitignore: -------------------------------------------------------------------------------- 1 | /.kdev4/* 2 | music_player.kdev4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Music Player 2 | Music Player in PyQt5 3 | 4 | What is working: 5 | 1) Choose a song from the open Song dialog 6 | 2) play a Song 7 | 3) pause the song playing 8 | 4) stop the song playing 9 | 5) Increase/ Decrease the volume 10 | 6) Progressbar of the song 11 | 7) Seek control over the progressbar 12 | 8) current song's elapsed time and total time 13 | 9) Show current song's information 14 | 10)Added Playlist support 15 | -------------------------------------------------------------------------------- /music_player.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Documentation, License etc. 3 | 4 | @package music_player 5 | ''' 6 | import sys 7 | from os.path import expanduser 8 | from PyQt5.QtWidgets import * 9 | from PyQt5.QtMultimedia import * 10 | from PyQt5.QtCore import * 11 | 12 | class MainWindow(QMainWindow): 13 | def __init__(self): 14 | super().__init__() 15 | 16 | #self.currentFile = '/' 17 | self.currentPlaylist = QMediaPlaylist() 18 | self.player = QMediaPlayer() 19 | self.userAction = -1 #0- stopped, 1- playing 2-paused 20 | self.player.mediaStatusChanged.connect(self.qmp_mediaStatusChanged) 21 | self.player.stateChanged.connect(self.qmp_stateChanged) 22 | self.player.positionChanged.connect(self.qmp_positionChanged) 23 | self.player.volumeChanged.connect(self.qmp_volumeChanged) 24 | self.player.setVolume(60) 25 | #Add Status bar 26 | self.statusBar().showMessage('No Media :: %d'%self.player.volume()) 27 | self.homeScreen() 28 | 29 | def homeScreen(self): 30 | #Set title of the MainWindow 31 | self.setWindowTitle('Music Player by deathholes') 32 | 33 | #Create Menubar 34 | self.createMenubar() 35 | 36 | #Create Toolbar 37 | self.createToolbar() 38 | 39 | #Add info screen 40 | #infoscreen = self.createInfoScreen() 41 | 42 | #Add Control Bar 43 | controlBar = self.addControls() 44 | 45 | #need to add both infoscreen and control bar to the central widget. 46 | centralWidget = QWidget() 47 | centralWidget.setLayout(controlBar) 48 | self.setCentralWidget(centralWidget) 49 | 50 | #Set Dimensions of the MainWindow 51 | self.resize(200,100) 52 | 53 | #show everything. 54 | self.show() 55 | 56 | def createMenubar(self): 57 | menubar = self.menuBar() 58 | filemenu = menubar.addMenu('File') 59 | filemenu.addAction(self.fileOpen()) 60 | filemenu.addAction(self.songInfo()) 61 | filemenu.addAction(self.folderOpen()) 62 | filemenu.addAction(self.exitAction()) 63 | 64 | def createToolbar(self): 65 | pass 66 | 67 | def addControls(self): 68 | controlArea = QVBoxLayout() #centralWidget 69 | seekSliderLayout = QHBoxLayout() 70 | controls = QHBoxLayout() 71 | playlistCtrlLayout = QHBoxLayout() 72 | 73 | #creating buttons 74 | playBtn = QPushButton('Play') #play button 75 | pauseBtn = QPushButton('Pause') #pause button 76 | stopBtn = QPushButton('Stop') #stop button 77 | volumeDescBtn = QPushButton('V (-)')#Decrease Volume 78 | volumeIncBtn = QPushButton('V (+)') #Increase Volume 79 | 80 | #creating playlist controls 81 | prevBtn = QPushButton('Prev Song') 82 | nextBtn = QPushButton('Next Song') 83 | 84 | #creating seek slider 85 | seekSlider = QSlider() 86 | seekSlider.setMinimum(0) 87 | seekSlider.setMaximum(100) 88 | seekSlider.setOrientation(Qt.Horizontal) 89 | seekSlider.setTracking(False) 90 | seekSlider.sliderMoved.connect(self.seekPosition) 91 | #seekSlider.valueChanged.connect(self.seekPosition) 92 | 93 | seekSliderLabel1 = QLabel('0.00') 94 | seekSliderLabel2 = QLabel('0.00') 95 | seekSliderLayout.addWidget(seekSliderLabel1) 96 | seekSliderLayout.addWidget(seekSlider) 97 | seekSliderLayout.addWidget(seekSliderLabel2) 98 | 99 | #Add handler for each button. Not using the default slots. 100 | playBtn.clicked.connect(self.playHandler) 101 | pauseBtn.clicked.connect(self.pauseHandler) 102 | stopBtn.clicked.connect(self.stopHandler) 103 | volumeDescBtn.clicked.connect(self.decreaseVolume) 104 | volumeIncBtn.clicked.connect(self.increaseVolume) 105 | 106 | #Adding to the horizontal layout 107 | controls.addWidget(volumeDescBtn) 108 | controls.addWidget(playBtn) 109 | controls.addWidget(pauseBtn) 110 | controls.addWidget(stopBtn) 111 | controls.addWidget(volumeIncBtn) 112 | 113 | #playlist control button handlers 114 | prevBtn.clicked.connect(self.prevItemPlaylist) 115 | nextBtn.clicked.connect(self.nextItemPlaylist) 116 | playlistCtrlLayout.addWidget(prevBtn) 117 | playlistCtrlLayout.addWidget(nextBtn) 118 | 119 | #Adding to the vertical layout 120 | controlArea.addLayout(seekSliderLayout) 121 | controlArea.addLayout(controls) 122 | controlArea.addLayout(playlistCtrlLayout) 123 | return controlArea 124 | 125 | def playHandler(self): 126 | self.userAction = 1 127 | self.statusBar().showMessage('Playing at Volume %d'%self.player.volume()) 128 | if self.player.state() == QMediaPlayer.StoppedState : 129 | if self.player.mediaStatus() == QMediaPlayer.NoMedia: 130 | #self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.currentFile))) 131 | print(self.currentPlaylist.mediaCount()) 132 | if self.currentPlaylist.mediaCount() == 0: 133 | self.openFile() 134 | if self.currentPlaylist.mediaCount() != 0: 135 | self.player.setPlaylist(self.currentPlaylist) 136 | elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia: 137 | self.player.play() 138 | elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia: 139 | self.player.play() 140 | elif self.player.state() == QMediaPlayer.PlayingState: 141 | pass 142 | elif self.player.state() == QMediaPlayer.PausedState: 143 | self.player.play() 144 | 145 | def pauseHandler(self): 146 | self.userAction = 2 147 | self.statusBar().showMessage('Paused %s at position %s at Volume %d'%\ 148 | (self.player.metaData(QMediaMetaData.Title),\ 149 | self.centralWidget().layout().itemAt(0).layout().itemAt(0).widget().text(),\ 150 | self.player.volume())) 151 | self.player.pause() 152 | 153 | def stopHandler(self): 154 | self.userAction = 0 155 | self.statusBar().showMessage('Stopped at Volume %d'%(self.player.volume())) 156 | if self.player.state() == QMediaPlayer.PlayingState: 157 | self.stopState = True 158 | self.player.stop() 159 | elif self.player.state() == QMediaPlayer.PausedState: 160 | self.player.stop() 161 | elif self.player.state() == QMediaPlayer.StoppedState: 162 | pass 163 | 164 | def qmp_mediaStatusChanged(self): 165 | if self.player.mediaStatus() == QMediaPlayer.LoadedMedia and self.userAction == 1: 166 | durationT = self.player.duration() 167 | self.centralWidget().layout().itemAt(0).layout().itemAt(1).widget().setRange(0,durationT) 168 | self.centralWidget().layout().itemAt(0).layout().itemAt(2).widget().setText('%d:%02d'%(int(durationT/60000),int((durationT/1000)%60))) 169 | self.player.play() 170 | 171 | def qmp_stateChanged(self): 172 | if self.player.state() == QMediaPlayer.StoppedState: 173 | self.player.stop() 174 | 175 | def qmp_positionChanged(self, position,senderType=False): 176 | sliderLayout = self.centralWidget().layout().itemAt(0).layout() 177 | if senderType == False: 178 | sliderLayout.itemAt(1).widget().setValue(position) 179 | #update the text label 180 | sliderLayout.itemAt(0).widget().setText('%d:%02d'%(int(position/60000),int((position/1000)%60))) 181 | 182 | def seekPosition(self, position): 183 | sender = self.sender() 184 | if isinstance(sender,QSlider): 185 | if self.player.isSeekable(): 186 | self.player.setPosition(position) 187 | 188 | def qmp_volumeChanged(self): 189 | msg = self.statusBar().currentMessage() 190 | msg = msg[:-2] + str(self.player.volume()) 191 | self.statusBar().showMessage(msg) 192 | 193 | def increaseVolume(self): 194 | vol = self.player.volume() 195 | vol = min(vol+5,100) 196 | self.player.setVolume(vol) 197 | 198 | def decreaseVolume(self): 199 | vol = self.player.volume() 200 | vol = max(vol-5,0) 201 | self.player.setVolume(vol) 202 | 203 | def fileOpen(self): 204 | fileAc = QAction('Open File',self) 205 | fileAc.setShortcut('Ctrl+O') 206 | fileAc.setStatusTip('Open File') 207 | fileAc.triggered.connect(self.openFile) 208 | return fileAc 209 | 210 | def openFile(self): 211 | fileChoosen = QFileDialog.getOpenFileUrl(self,'Open Music File', expanduser('~'),'Audio (*.mp3 *.ogg *.wav)','*.mp3 *.ogg *.wav') 212 | if fileChoosen != None: 213 | self.currentPlaylist.addMedia(QMediaContent(fileChoosen[0])) 214 | 215 | def folderOpen(self): 216 | folderAc = QAction('Open Folder',self) 217 | folderAc.setShortcut('Ctrl+D') 218 | folderAc.setStatusTip('Open Folder (Will add all the files in the folder) ') 219 | folderAc.triggered.connect(self.addFiles) 220 | return folderAc 221 | 222 | def addFiles(self): 223 | folderChoosen = QFileDialog.getExistingDirectory(self,'Open Music Folder', expanduser('~')) 224 | if folderChoosen != None: 225 | it = QDirIterator(folderChoosen) 226 | it.next() 227 | while it.hasNext(): 228 | if it.fileInfo().isDir() == False and it.filePath() != '.': 229 | fInfo = it.fileInfo() 230 | print(it.filePath(),fInfo.suffix()) 231 | if fInfo.suffix() in ('mp3','ogg','wav'): 232 | print('added file ',fInfo.fileName()) 233 | self.currentPlaylist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) 234 | it.next() 235 | 236 | def songInfo(self): 237 | infoAc = QAction('Info',self) 238 | infoAc.setShortcut('Ctrl+I') 239 | infoAc.setStatusTip('Displays Current Song Information') 240 | infoAc.triggered.connect(self.displaySongInfo) 241 | return infoAc 242 | 243 | def displaySongInfo(self): 244 | metaDataKeyList = self.player.availableMetaData() 245 | fullText = '
| ' + key + ' | ' + str(value) + ' |