From 6a74b090b13a9e1ff37338332627eb5f16ed7d40 Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Sun, 1 Nov 2020 19:47:29 +0100 Subject: Initial commit --- mediaplayer/mediaplayer.py | 185 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 mediaplayer/mediaplayer.py (limited to 'mediaplayer/mediaplayer.py') diff --git a/mediaplayer/mediaplayer.py b/mediaplayer/mediaplayer.py new file mode 100644 index 0000000..fe4cc50 --- /dev/null +++ b/mediaplayer/mediaplayer.py @@ -0,0 +1,185 @@ +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +from PyQt5.QtCore import * +from PyQt5.QtMultimedia import * +from PyQt5.QtMultimediaWidgets import * + +from MainWindow import Ui_MainWindow + +def hhmmss(ms): + # s = 1000 + # m = 60000 + # h = 360000 + h, r = divmod(ms, 36000) + m, r = divmod(r, 60000) + s, _ = divmod(r, 1000) + return ("%d:%02d:%02d" % (h,m,s)) if h else ("%d:%02d" % (m,s)) + +class ViewerWindow(QMainWindow): + state = pyqtSignal(bool) + + def closeEvent(self, e): + # Emit the window state, to update the viewer toggle button. + self.state.emit(False) + + +class PlaylistModel(QAbstractListModel): + def __init__(self, playlist, *args, **kwargs): + super(PlaylistModel, self).__init__(*args, **kwargs) + self.playlist = playlist + + def data(self, index, role): + if role == Qt.DisplayRole: + media = self.playlist.media(index.row()) + return media.canonicalUrl().fileName() + + def rowCount(self, index): + return self.playlist.mediaCount() + + +class MainWindow(QMainWindow, Ui_MainWindow): + def __init__(self, *args, **kwargs): + super(MainWindow, self).__init__(*args, **kwargs) + self.setupUi(self) + + self.player = QMediaPlayer() + + self.player.error.connect(self.erroralert) + self.player.play() + + # Setup the playlist. + self.playlist = QMediaPlaylist() + self.player.setPlaylist(self.playlist) + + # Add viewer for video playback, separate floating window. + self.viewer = ViewerWindow(self) + self.viewer.setWindowFlags(self.viewer.windowFlags() | Qt.WindowStaysOnTopHint) + self.viewer.setMinimumSize(QSize(480,360)) + + videoWidget = QVideoWidget() + self.viewer.setCentralWidget(videoWidget) + self.player.setVideoOutput(videoWidget) + + # Connect control buttons/slides for media player. + self.playButton.pressed.connect(self.player.play) + self.pauseButton.pressed.connect(self.player.pause) + self.stopButton.pressed.connect(self.player.stop) + self.volumeSlider.valueChanged.connect(self.player.setVolume) + + self.viewButton.toggled.connect(self.toggle_viewer) + self.viewer.state.connect(self.viewButton.setChecked) + + self.previousButton.pressed.connect(self.playlist.previous) + self.nextButton.pressed.connect(self.playlist.next) + + self.model = PlaylistModel(self.playlist) + self.playlistView.setModel(self.model) + self.playlist.currentIndexChanged.connect(self.playlist_position_changed) + selection_model = self.playlistView.selectionModel() + selection_model.selectionChanged.connect(self.playlist_selection_changed) + + self.player.durationChanged.connect(self.update_duration) + self.player.positionChanged.connect(self.update_position) + self.timeSlider.valueChanged.connect(self.player.setPosition) + + self.open_file_action.triggered.connect(self.open_file) + + self.setAcceptDrops(True) + + self.show() + + def dragEnterEvent(self, e): + if e.mimeData().hasUrls(): + e.acceptProposedAction() + + def dropEvent(self, e): + for url in e.mimeData().urls(): + self.playlist.addMedia( + QMediaContent(url) + ) + + self.model.layoutChanged.emit() + + # If not playing, seeking to first of newly added + play. + if self.player.state() != QMediaPlayer.PlayingState: + i = self.playlist.mediaCount() - len(e.mimeData().urls()) + self.playlist.setCurrentIndex(i) + self.player.play() + + def open_file(self): + path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "mp3 Audio (*.mp3);mp4 Video (*.mp4);Movie files (*.mov);All files (*.*)") + + if path: + self.playlist.addMedia( + QMediaContent( + QUrl.fromLocalFile(path) + ) + ) + + self.model.layoutChanged.emit() + + def update_duration(self, duration): + print("!", duration) + print("?", self.player.duration()) + + self.timeSlider.setMaximum(duration) + + if duration >= 0: + self.totalTimeLabel.setText(hhmmss(duration)) + + def update_position(self, position): + if position >= 0: + self.currentTimeLabel.setText(hhmmss(position)) + + # Disable the events to prevent updating triggering a setPosition event (can cause stuttering). + self.timeSlider.blockSignals(True) + self.timeSlider.setValue(position) + self.timeSlider.blockSignals(False) + + def playlist_selection_changed(self, ix): + # We receive a QItemSelection from selectionChanged. + i = ix.indexes()[0].row() + self.playlist.setCurrentIndex(i) + + def playlist_position_changed(self, i): + if i > -1: + ix = self.model.index(i) + self.playlistView.setCurrentIndex(ix) + + def toggle_viewer(self, state): + if state: + self.viewer.show() + else: + self.viewer.hide() + + def erroralert(self, *args): + print(args) + + + + +if __name__ == '__main__': + app = QApplication([]) + app.setApplicationName("Failamp") + app.setStyle("Fusion") + + # Fusion dark palette from https://gist.github.com/QuantumCD/6245215. + palette = QPalette() + palette.setColor(QPalette.Window, QColor(53, 53, 53)) + palette.setColor(QPalette.WindowText, Qt.white) + palette.setColor(QPalette.Base, QColor(25, 25, 25)) + palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) + palette.setColor(QPalette.ToolTipBase, Qt.white) + palette.setColor(QPalette.ToolTipText, Qt.white) + palette.setColor(QPalette.Text, Qt.white) + palette.setColor(QPalette.Button, QColor(53, 53, 53)) + palette.setColor(QPalette.ButtonText, Qt.white) + palette.setColor(QPalette.BrightText, Qt.red) + palette.setColor(QPalette.Link, QColor(42, 130, 218)) + palette.setColor(QPalette.Highlight, QColor(42, 130, 218)) + palette.setColor(QPalette.HighlightedText, Qt.black) + app.setPalette(palette) + app.setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }") + + window = MainWindow() + app.exec_() -- cgit v1.2.3