def adjust_player_volume_by_decibel(self, player: QMediaPlayer, decibel: Number) -> Number: original_volume = player.volume() target_volume = round( add_decibel_to_linear_volume(original_volume, decibel)) player.setVolume(target_volume) # Return clamped volume difference, so increasing linear volume 100 by n > 1 db # returns 0 return player.volume() - original_volume
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.player = QMediaPlayer() self.playlist = QMediaPlaylist() toolBar = QToolBar() self.addToolBar(toolBar) playIcon = self.style().standardIcon(QStyle.SP_MediaPlay) previousIcon = self.style().standardIcon(QStyle.SP_MediaSkipBackward) nextIcon = self.style().standardIcon(QStyle.SP_MediaSkipForward) pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause) stopIcon = self.style().standardIcon(QStyle.SP_MediaStop) self.playAction = toolBar.addAction(playIcon, "Play") self.previousAction = toolBar.addAction(previousIcon, "Previous") self.nextAction = toolBar.addAction(nextIcon, "Next") self.pauseAction = toolBar.addAction(pauseIcon, "Pause") self.stopAction = toolBar.addAction(stopIcon, "Stop") self.playAction.triggered.connect(self.player.play) self.previousAction.triggered.connect(self.previousClicked) self.nextAction.triggered.connect(self.playlist.next) self.pauseAction.triggered.connect(self.player.pause) self.stopAction.triggered.connect(self.player.stop) self.volSlider = QSlider() self.volSlider.setOrientation(Qt.Horizontal) self.volSlider.setMinimum(0) self.volSlider.setMaximum(100) self.volSlider.setFixedWidth(120) self.volSlider.setValue(self.player.volume()) self.volSlider.setTickInterval(10) self.volSlider.setTickPosition(QSlider.TicksBelow) self.volSlider.setToolTip("Volume") self.volSlider.valueChanged.connect(self.player.setVolume) toolBar.addWidget(self.volSlider) openAction = QAction(QIcon.fromTheme("document-open"), "&Open...", self, shortcut=QKeySequence.Open, triggered=self.open) exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit", self, shortcut="Ctrl+Q", triggered=self.close) aboutQtAct = QAction("About &Qt", self, triggered=qApp.aboutQt) fileMenu = self.menuBar().addMenu("&File") fileMenu.addAction(openAction) fileMenu.addAction(exitAction) playMenu = self.menuBar().addMenu("&Play") playMenu.addAction(self.playAction) playMenu.addAction(self.previousAction) playMenu.addAction(self.nextAction) playMenu.addAction(self.pauseAction) playMenu.addAction(self.stopAction) aboutMenu = self.menuBar().addMenu("&About") aboutMenu.addAction(aboutQtAct) self.videoWidget = QVideoWidget() self.setCentralWidget(self.videoWidget) self.player.setPlaylist(self.playlist) self.player.stateChanged.connect(self.updateButtons) self.player.setVideoOutput(self.videoWidget) self.updateButtons(self.player.state()) def open(self): fileDialog = QFileDialog(self) supportedMimeTypes = ["video/mp4", "*.*"] fileDialog.setMimeTypeFilters(supportedMimeTypes) moviesLocation = QStandardPaths.writableLocation( QStandardPaths.MoviesLocation) fileDialog.setDirectory(moviesLocation) if fileDialog.exec_() == QDialog.Accepted: self.playlist.addMedia(fileDialog.selectedUrls()[0]) self.player.play() def previousClicked(self): if self.player.position() <= 5000: self.playlist.previous() else: player.setPosition(0) def updateButtons(self, state): mediaCount = self.playlist.mediaCount() self.playAction.setEnabled(mediaCount > 0 and state != QMediaPlayer.PlayingState) self.pauseAction.setEnabled(state == QMediaPlayer.PlayingState) self.stopAction.setEnabled(state != QMediaPlayer.StoppedState) self.previousAction.setEnabled(self.player.position() > 0) self.nextAction.setEnabled(mediaCount > 1)
class MainWindow(QMainWindow): # Main window def __init__(self): super().__init__() self.setWindowTitle = 'DD烤肉机' self.resize(1870, 820) self.mainWidget = QWidget() self.mainLayout = QGridLayout() # Grid layout self.mainLayout.setSpacing(10) self.mainWidget.setLayout(self.mainLayout) self.duration = 60000 self.bitrate = 2000 self.fps = 60 self.initProcess = InitProcess() self.previewSubtitle = PreviewSubtitle() self.dnldWindow = YoutubeDnld() self.exportWindow = exportSubtitle() self.videoDecoder = VideoDecoder() self.exportWindow.exportArgs.connect(self.exportSubtitle) self.stack = QStackedWidget() self.stack.setFixedWidth(1300) self.mainLayout.addWidget(self.stack, 0, 0, 10, 8) buttonWidget = QWidget() buttonLayout = QHBoxLayout() buttonWidget.setLayout(buttonLayout) self.playButton = QPushButton('从本地打开') self.playButton.clicked.connect(self.open) self.playButton.setFixedWidth(400) self.playButton.setFixedHeight(75) self.dnldButton = QPushButton('Youtube下载器') self.dnldButton.clicked.connect(self.popDnld) self.dnldButton.setFixedWidth(400) self.dnldButton.setFixedHeight(75) buttonLayout.addWidget(self.playButton) buttonLayout.addWidget(self.dnldButton) self.stack.addWidget(buttonWidget) self.videoPath = '' self.videoWidth = 1920 self.videoHeight = 1080 self.globalInterval = 200 self.setPlayer() self.setSubtitle() self.setToolBar() self.setCentralWidget(self.mainWidget) self.playStatus = False self.volumeStatus = True self.volumeValue = 100 self.subSelectedTxt = '' self.subReplayTime = 1 self.clipBoard = [] self.grabKeyboard() self.show() def setPlayer(self): self.playerWidget = QGraphicsVideoItem() self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.resize(1280, 730) self.scene.addItem(self.playerWidget) self.stack.addWidget(self.view) self.player = QMediaPlayer(self, QMediaPlayer.VideoSurface) self.player.setVideoOutput(self.playerWidget) self.view.installEventFilter(self) self.view.show() self.srtTextItemDict = {0: QGraphicsTextItem(), 1: QGraphicsTextItem(), 2: QGraphicsTextItem(), 3: QGraphicsTextItem(), 4: QGraphicsTextItem()} for _, srtTextItem in self.srtTextItemDict.items(): self.scene.addItem(srtTextItem) def setSubtitle(self): self.subtitleDict = {x: {-1: [100, '']} for x in range(5)} self.subTimer = QTimer() self.subTimer.setInterval(100) self.subtitle = QTableWidget() self.subtitle.setAutoScroll(False) self.subtitle.setEditTriggers(QAbstractItemView.NoEditTriggers) self.mainLayout.addWidget(self.subtitle, 0, 8, 10, 12) self.subtitle.setColumnCount(5) self.subtitle.selectRow(0) self.subtitle.setHorizontalHeaderLabels(['%s' % (i + 1) for i in range(5)]) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) for index in range(5): self.subtitle.setColumnWidth(index, 130) self.subtitle.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.subtitle.setEditTriggers(QAbstractItemView.DoubleClicked) self.subtitle.horizontalHeader().sectionClicked.connect(self.addSubtitle) self.subtitle.doubleClicked.connect(self.releaseKeyboard) self.subtitle.cellChanged.connect(self.subEdit) self.subtitle.verticalHeader().sectionClicked.connect(self.subHeaderClick) self.subtitle.setContextMenuPolicy(Qt.CustomContextMenu) self.subtitle.customContextMenuRequested.connect(self.popTableMenu) self.initSubtitle() def initSubtitle(self): self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) for x in range(self.subtitle.columnCount()): for y in range(self.subtitle.rowCount()): self.subtitle.setSpan(y, x, 1, 1) self.subtitle.setRowCount(self.duration // self.globalInterval + 1) for x in range(self.subtitle.columnCount()): for y in range(self.subtitle.rowCount()): self.subtitle.setItem(y, x, QTableWidgetItem('')) self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629'))) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def addSubtitle(self, index): subtitlePath = QFileDialog.getOpenFileName(self, "请选择字幕", None, "字幕文件 (*.srt *.vtt *.ass *.ssa)")[0] if subtitlePath: self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) if subtitlePath.endswith('.ass') or subtitlePath.endswith('.ssa'): p = subprocess.Popen(['utils/ffmpeg.exe', '-y', '-i', subtitlePath, 'temp_sub.srt']) p.wait() subtitlePath = 'temp_sub.srt' subData = {} with open(subtitlePath, 'r', encoding='utf-8') as f: f = f.readlines() subText = '' YoutubeAutoSub = False for l in f: if '<c>' in l: YoutubeAutoSub = True break for cnt, l in enumerate(f): if '<c>' in l: lineData = l.split('c>') if len(lineData) > 3: subText, start, _ = lineData[0].split('<') start = calSubTime(start[:-1]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: end = calSubTime(lineData[-3][1:-2]) // self.globalInterval * self.globalInterval for i in range(len(lineData) // 2): subText += lineData[i * 2 + 1][:-2] subData[start] = [end - start, subText] else: subText, start, _ = lineData[0].split('<') start = calSubTime(start[:-1]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: subText += lineData[1][:-2] subData[start] = [self.globalInterval, subText] elif '-->' in l and f[cnt + 2].strip() and '<c>' not in f[cnt + 2]: subText = f[cnt + 2][:-1] start = calSubTime(l[:12]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: end = calSubTime(l[17:29]) // self.globalInterval * self.globalInterval subData[start] = [end - start, subText] if '-->' in l and f[cnt + 1].strip() and not YoutubeAutoSub: start = calSubTime(l[:12]) // self.globalInterval * self.globalInterval if start not in self.subtitleDict[index]: end = calSubTime(l[17:29]) // self.globalInterval * self.globalInterval delta = end - start if delta > 10: if '<b>' in f[cnt + 1]: subData[start] = [delta, f[cnt + 1].split('<b>')[1].split('<')[0]] else: subData[start] = [delta, f[cnt + 1][:-1]] self.subtitleDict[index].update(subData) maxRow = 0 for _, v in self.subtitleDict.items(): startMax = max(v.keys()) rowCount = (startMax + v[startMax][0]) // self.globalInterval if rowCount > maxRow: maxRow = rowCount if maxRow < self.duration // self.globalInterval + 1: maxRow = self.duration // self.globalInterval else: self.duration = maxRow * self.globalInterval self.subtitle.setRowCount(maxRow) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) for start, rowData in subData.items(): startRow = start // self.globalInterval endRow = startRow + rowData[0] // self.globalInterval for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.refreshComboBox() self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def subTimeOut(self): fontColor = self.previewSubtitle.fontColor fontSize = (self.previewSubtitle.fontSize + 5) / 2.5 fontBold = self.previewSubtitle.bold fontItalic = self.previewSubtitle.italic fontShadowOffset = self.previewSubtitle.shadowOffset for _, srtTextItem in self.srtTextItemDict.items(): srtTextItem.setDefaultTextColor(fontColor) font = QFont() font.setFamily("微软雅黑") font.setPointSize(fontSize) font.setBold(fontBold) font.setItalic(fontItalic) srtTextItem.setFont(font) srtTextShadow = QGraphicsDropShadowEffect() srtTextShadow.setOffset(fontShadowOffset) srtTextItem.setGraphicsEffect(srtTextShadow) try: selected = self.subtitle.selectionModel().selection().indexes() for x, i in enumerate(selected): if self.subtitle.item(i.row(), x): txt = self.subtitle.item(i.row(), x).text() if txt: self.srtTextItemDict[x].setPlainText('#%s:' % (x + 1) + txt) txtSize = self.srtTextItemDict[x].boundingRect().size() posY = self.playerWidget.size().height() - txtSize.height() * (x + 1) posX = (self.playerWidget.size().width() - txtSize.width()) / 2 self.srtTextItemDict[x].setPos(posX, posY) else: self.srtTextItemDict[x].setPlainText('') else: self.srtTextItemDict[x].setPlainText('') except: pass def subHeaderClick(self, index): if self.player.duration(): position = index * self.globalInterval self.player.setPosition(position) self.videoSlider.setValue(position * 1000 // self.player.duration()) self.setTimeLabel() def subEdit(self, row, index): repeat = self.subtitle.rowSpan(row, index) self.setSubtitleDict(row, index, repeat, self.subtitle.item(row, index).text()) self.subtitle.cellChanged.disconnect(self.subEdit) for cnt in range(repeat): if self.subtitle.item(row + cnt, index).text(): self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) else: self.subtitle.item(row, index).setBackground(QBrush(QColor('#232629'))) self.subtitle.cellChanged.connect(self.subEdit) def setSubtitleDict(self, row, index, num, text): self.subtitleDict[index][row * self.globalInterval] = [num * self.globalInterval, text] def popTableMenu(self, pos): self.subtitle.cellChanged.disconnect(self.subEdit) pos = QPoint(pos.x() + 55, pos.y() + 30) menu = QMenu() copy = menu.addAction('复制') paste = menu.addAction('粘贴') setSpan = menu.addAction('合并') clrSpan = menu.addAction('拆分') addSub = menu.addAction('导入字幕') cutSub = menu.addAction('裁剪字幕') action = menu.exec_(self.subtitle.mapToGlobal(pos)) selected = self.subtitle.selectionModel().selection().indexes() yList = [selected[0].row(), selected[-1].row()] xSet = set() for i in range(len(selected)): xSet.add(selected[i].column()) if action == copy: for x in xSet: self.clipBoard = [] for y in range(yList[0], yList[1] + 1): if self.subtitle.item(y, x): self.clipBoard.append(self.subtitle.item(y, x).text()) else: self.clipBoard.append('') break elif action == paste: self.subtitle.cellChanged.connect(self.subEdit) for x in xSet: for cnt, text in enumerate(self.clipBoard): self.subtitle.setItem(yList[0] + cnt, x, QTableWidgetItem(text)) self.subtitleDict[x][(yList[0] + cnt) * self.globalInterval] = [self.globalInterval, text] self.subtitle.cellChanged.disconnect(self.subEdit) elif action == setSpan: for x in xSet: if not self.subtitle.item(yList[0], x): firstItem = '' else: firstItem = self.subtitle.item(yList[0], x).text() for y in range(yList[0], yList[1] + 1): self.subtitle.setSpan(y, x, 1, 1) self.subtitle.setItem(y, x, QTableWidgetItem(firstItem)) self.subtitle.item(y, x).setBackground(QBrush(QColor('#35545d'))) if y * self.globalInterval in self.subtitleDict[x]: del self.subtitleDict[x][y * self.globalInterval] for x in xSet: self.subtitle.setSpan(yList[0], x, yList[1] - yList[0] + 1, 1) self.setSubtitleDict(yList[0], x, yList[1] - yList[0] + 1, firstItem) elif action == clrSpan: for x in xSet: if not self.subtitle.item(yList[0], x): firstItem = '' else: firstItem = self.subtitle.item(yList[0], x).text() for cnt, y in enumerate(range(yList[0], yList[1] + 1)): self.subtitle.setSpan(y, x, 1, 1) if not cnt: self.subtitle.setItem(yList[0], x, QTableWidgetItem(firstItem)) if firstItem: self.subtitle.item(y, x).setBackground(QBrush(QColor('#35545d'))) else: self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629'))) else: self.subtitle.setItem(y, x, QTableWidgetItem('')) self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629'))) self.setSubtitleDict(yList[0], x, yList[1] - yList[0] + 1, firstItem) break elif action == addSub: self.subtitle.cellChanged.connect(self.subEdit) for x in xSet: self.addSubtitle(x) self.subtitle.cellChanged.disconnect(self.subEdit) elif action == cutSub: for x in xSet: start = yList[0] * self.globalInterval end = yList[1] * self.globalInterval self.exportSubWindow(start, end, x + 1) self.subtitle.cellChanged.connect(self.subEdit) def setToolBar(self): ''' menu bar, file menu, play menu, tool bar. ''' toolBar = QToolBar() self.setContextMenuPolicy(Qt.NoContextMenu) self.addToolBar(toolBar) fileMenu = self.menuBar().addMenu('&文件') openAction = QAction(QIcon.fromTheme('document-open'), '&打开...', self, shortcut=QKeySequence.Open, triggered=self.open) fileMenu.addAction(openAction) downloadAction = QAction(QIcon.fromTheme('document-open'), '&Youtube下载器', self, triggered=self.popDnld) fileMenu.addAction(downloadAction) exitAction = QAction(QIcon.fromTheme('application-exit'), '&退出', self, shortcut='Ctrl+Q', triggered=self.close) fileMenu.addAction(exitAction) playMenu = self.menuBar().addMenu('&功能') self.playIcon = self.style().standardIcon(QStyle.SP_MediaPlay) self.pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause) self.playAction = toolBar.addAction(self.playIcon, '播放') self.playAction.triggered.connect(self.mediaPlay) self.volumeIcon = self.style().standardIcon(QStyle.SP_MediaVolume) self.volumeMuteIcon = self.style().standardIcon(QStyle.SP_MediaVolumeMuted) self.volumeAction = toolBar.addAction(self.volumeIcon, '静音') self.volumeAction.triggered.connect(self.volumeMute) previewAction = QAction(QIcon.fromTheme('document-open'), '&设置预览字幕', self, triggered=self.popPreview) playMenu.addAction(previewAction) decodeMenu = self.menuBar().addMenu('&输出') decodeAction = QAction(QIcon.fromTheme('document-open'), '&输出字幕及视频', self, triggered=self.decode) decodeMenu.addAction(decodeAction) self.volSlider = Slider() self.volSlider.setOrientation(Qt.Horizontal) self.volSlider.setMinimum(0) self.volSlider.setMaximum(100) self.volSlider.setFixedWidth(120) self.volSlider.setValue(self.player.volume()) self.volSlider.setToolTip(str(self.volSlider.value())) self.volSlider.pointClicked.connect(self.setVolume) toolBar.addWidget(self.volSlider) self.videoPositionEdit = LineEdit('00:00') self.videoPositionEdit.setAlignment(Qt.AlignRight) self.videoPositionEdit.setFixedWidth(75) self.videoPositionEdit.setFont(QFont('Timers', 14)) self.videoPositionEdit.clicked.connect(self.mediaPauseOnly) self.videoPositionEdit.editingFinished.connect(self.mediaPlayOnly) self.videoPositionLabel = QLabel(' / 00:00 ') self.videoPositionLabel.setFont(QFont('Timers', 14)) toolBar.addWidget(QLabel(' ')) toolBar.addWidget(self.videoPositionEdit) toolBar.addWidget(self.videoPositionLabel) self.timer = QTimer() self.timer.setInterval(100) self.videoSlider = Slider() self.videoSlider.setEnabled(False) self.videoSlider.setOrientation(Qt.Horizontal) self.videoSlider.setMinimum(0) self.videoSlider.setMaximum(1000) self.videoSlider.setFixedWidth(1000) self.videoSlider.sliderMoved.connect(self.timeStop) self.videoSlider.sliderReleased.connect(self.timeStart) self.videoSlider.pointClicked.connect(self.videoSliderClick) toolBar.addWidget(self.videoSlider) toolBar.addWidget(QLabel(' ')) self.globalIntervalComBox = QComboBox() self.globalIntervalComBox.addItems(['间隔 100ms', '间隔 200ms', '间隔 500ms', '间隔 1s']) self.globalIntervalComBox.setCurrentIndex(1) self.globalIntervalComBox.currentIndexChanged.connect(self.setGlobalInterval) toolBar.addWidget(self.globalIntervalComBox) toolBar.addWidget(QLabel(' ')) self.subEditComBox = QComboBox() self.refreshComboBox() toolBar.addWidget(self.subEditComBox) toolBar.addWidget(QLabel(' ')) moveForward = QPushButton('- 1') moveForward.setFixedWidth(50) toolBar.addWidget(moveForward) toolBar.addWidget(QLabel(' ')) moveAfterward = QPushButton('+ 1') moveAfterward.setFixedWidth(50) toolBar.addWidget(moveAfterward) toolBar.addWidget(QLabel(' ')) clearSub = QPushButton('清空') clearSub.setFixedWidth(50) toolBar.addWidget(clearSub) toolBar.addWidget(QLabel(' ')) outputSub = QPushButton('裁剪') outputSub.setFixedWidth(50) toolBar.addWidget(outputSub) moveForward.clicked.connect(self.moveForward) moveAfterward.clicked.connect(self.moveAfterward) clearSub.clicked.connect(self.clearSub) outputSub.clicked.connect(self.exportSubWindow) def setGlobalInterval(self, index): if not self.playStatus: self.mediaPlay() self.globalInterval = {0: 100, 1: 200, 2: 500, 3: 1000}[index] self.initSubtitle() self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) for index, subData in self.subtitleDict.items(): for start, rowData in subData.items(): startRow = start // self.globalInterval deltaRow = rowData[0] // self.globalInterval if deltaRow: endRow = startRow + deltaRow for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) if row >= 0: self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def moveForward(self): self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) index = self.subEditComBox.currentIndex() for y in range(self.subtitle.rowCount()): self.subtitle.setSpan(y, index, 1, 1) self.subtitle.setItem(y, index, QTableWidgetItem('')) self.subtitle.item(y, index).setBackground(QBrush(QColor('#232629'))) tmpDict = self.subtitleDict[index] self.subtitleDict[index] = {} for start, rowData in tmpDict.items(): self.subtitleDict[index][start - self.globalInterval] = rowData for start, rowData in self.subtitleDict[index].items(): startRow = start // self.globalInterval endRow = startRow + rowData[0] // self.globalInterval for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def moveAfterward(self): self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) index = self.subEditComBox.currentIndex() for y in range(self.subtitle.rowCount()): self.subtitle.setSpan(y, index, 1, 1) self.subtitle.setItem(y, index, QTableWidgetItem('')) self.subtitle.item(y, index).setBackground(QBrush(QColor('#232629'))) tmpDict = self.subtitleDict[index] self.subtitleDict[index] = {} for start, rowData in tmpDict.items(): self.subtitleDict[index][start + self.globalInterval] = rowData for start, rowData in self.subtitleDict[index].items(): startRow = start // self.globalInterval endRow = startRow + rowData[0] // self.globalInterval for row in range(startRow, endRow): self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1])) self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d'))) self.subtitle.setSpan(startRow, index, endRow - startRow, 1) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def clearSub(self): index = self.subEditComBox.currentIndex() reply = QMessageBox.information(self, '清空字幕', '清空第 %s 列字幕条?' % (index + 1), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) self.subtitleDict[index] = {0: [self.globalInterval, '']} for i in range(self.subtitle.rowCount()): self.subtitle.setSpan(i, index, 1, 1) self.subtitle.setItem(i, index, QTableWidgetItem('')) self.subtitle.item(i, index).setBackground(QBrush(QColor('#232629'))) self.subtitle.setHorizontalHeaderItem(index, QTableWidgetItem('%s' % (index + 1))) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() def exportSubWindow(self, start=0, end=0, index=None): self.releaseKeyboard() self.exportWindow.hide() self.exportWindow.show() start = '00:00.0' if not start else self.splitTime(start) end = self.splitTime(self.duration) if not end else self.splitTime(end) if not index: index = self.subEditComBox.currentIndex() + 1 self.exportWindow.setDefault(start, end, index) def exportSubtitle(self, exportArgs): start = calSubTime2(exportArgs[0]) end = calSubTime2(exportArgs[1]) subStart = calSubTime2(exportArgs[2]) index = exportArgs[3] - 1 subData = self.subtitleDict[index] rowList = sorted(subData.keys()) exportRange = [] for t in rowList: if t >= start and t <= end: exportRange.append(t) subNumber = 1 with open(exportArgs[-1], 'w', encoding='utf-8') as exportFile: for t in exportRange: text = subData[t][1] if text: start = ms2Time(t + subStart) end = ms2Time(t + subStart + subData[t][0]) exportFile.write('%s\n%s --> %s\n%s\n\n' % (subNumber, start, end, text)) subNumber += 1 QMessageBox.information(self, '导出字幕', '导出完成', QMessageBox.Yes) self.exportWindow.hide() def refreshComboBox(self): self.subEditComBox.clear() for i in range(self.subtitle.columnCount()): self.subEditComBox.addItem('字幕 ' + str(i + 1)) def open(self): self.videoPath = QFileDialog.getOpenFileName(self, "请选择视频文件", None, "MP4格式 (*.mp4);;所有文件(*.*)")[0] if self.videoPath: cmd = ['utils/ffmpeg.exe', '-i', self.videoPath] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.wait() for l in p.stdout.readlines(): l = l.decode('utf8') if 'Duration' in l: self.duration = calSubTime(l.split(' ')[3][:-1]) if 'Stream' in l and 'DAR' in l: self.videoWidth, self.videoHeight = map(int, l.split(' [')[0].split(' ')[-1].split('x')) args = l.split(',') for cnt, arg in enumerate(args): if 'kb' in arg: self.bitrate = int(arg.split('kb')[0]) self.fps = int(args[cnt + 1].split('fps')[0]) break break self.initProcess.show() self.subtitle.cellChanged.disconnect(self.subEdit) self.subtitle.setRowCount(self.duration // self.globalInterval + 1) self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())]) self.subtitle.cellChanged.connect(self.subEdit) self.initProcess.hide() url = QUrl.fromLocalFile(self.videoPath) self.stack.setCurrentIndex(1) self.playerWidget.setSize(QSizeF(1280, 720)) self.player.setMedia(url) self.playStatus = True self.videoSlider.setEnabled(True) self.mediaPlay() self.timer.start() self.timer.timeout.connect(self.timeOut) self.subTimer.start() self.subTimer.timeout.connect(self.subTimeOut) def popDnld(self): self.releaseKeyboard() self.dnldWindow.hide() self.dnldWindow.show() def popPreview(self): self.releaseKeyboard() self.previewSubtitle.hide() self.previewSubtitle.show() def decode(self): self.releaseKeyboard() self.videoDecoder.setDefault(self.videoPath, self.videoWidth, self.videoHeight, self.duration, self.bitrate, self.fps, self.subtitleDict) self.videoDecoder.hide() self.videoDecoder.show() def mediaPlay(self): if self.playStatus: self.player.play() self.grabKeyboard() self.timeStart() self.playStatus = False self.playAction.setIcon(self.pauseIcon) self.playAction.setText('暂停') else: self.player.pause() self.timeStop() self.playStatus = True self.playAction.setIcon(self.playIcon) self.playAction.setText('播放') def mediaPlayOnly(self): self.grabKeyboard() try: timeText = self.videoPositionEdit.text().split(':') m, s = timeText[:2] if not m: m = '00' if not s: s = '00' if len(m) > 3: m = m[:3] if len(s) > 2: s = s[:2] if m.isdigit(): m = int(m) if s.isdigit(): s = int(s) if s > 60: s = 60 total_m = self.player.duration() // 60000 if m > total_m: m = total_m self.player.setPosition(m * 60000 + s * 1000) self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) except: pass self.videoPositionEdit.setReadOnly(True) self.timeStart() def mediaPauseOnly(self): self.releaseKeyboard() self.videoPositionEdit.setReadOnly(False) self.player.pause() self.timeStop() self.playStatus = True self.playAction.setIcon(self.playIcon) self.playAction.setText('播放') def splitTime(self, playTime): playTime = playTime // 1000 m = str(playTime // 60) s = playTime % 60 s = ('0%s' % s)[-2:] if len(m) > 2: t = '%3s:%2s' % (m, s) else: t = '%2s:%2s' % (m, s) return t def timeOut(self): row = self.player.position() // self.globalInterval self.subtitle.selectRow(row) self.subtitle.verticalScrollBar().setValue(row - 10) if self.dnldWindow.isHidden() or self.exportWindow.isHidden() or self.videoDecoder.isHidden(): self.grabKeyboard() try: self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) self.setTimeLabel() except: pass def timeStop(self): self.timer.stop() def timeStart(self): self.timer.start() def videoSliderClick(self, p): self.videoSlider.setValue(p.x()) self.player.setPosition(p.x() * self.player.duration() // 1000) self.setTimeLabel() def setVolume(self, p): self.volumeValue = p.x() if self.volumeValue > 100: self.volumeValue = 100 if self.volumeValue < 0: self.volumeValue = 0 self.volSlider.setValue(self.volumeValue) self.player.setVolume(self.volumeValue) self.volSlider.setToolTip(str(self.volSlider.value())) if self.volumeValue: self.volumeStatus = True self.volumeAction.setIcon(self.volumeIcon) else: self.volumeStatus = False self.volumeAction.setIcon(self.volumeMuteIcon) def volumeMute(self): if self.volumeStatus: self.volumeStatus = False self.old_volumeValue = self.player.volume() self.player.setVolume(0) self.volSlider.setValue(0) self.volumeAction.setIcon(self.volumeMuteIcon) else: self.volumeStatus = True self.player.setVolume(self.old_volumeValue) self.volSlider.setValue(self.old_volumeValue) self.volumeAction.setIcon(self.volumeIcon) def setTimeLabel(self): now = self.player.position() total = self.player.duration() now = self.splitTime(now) total = self.splitTime(total) self.videoPositionEdit.setText(now) self.videoPositionLabel.setText(' / %s ' % total) def eventFilter(self, obj, event): if obj == self.view: if event.type() == QEvent.MouseButtonPress: self.mediaPlay() return QMainWindow.eventFilter(self, obj, event) def keyPressEvent(self, QKeyEvent): key = QKeyEvent.key() if key == Qt.Key_Left: if self.videoSlider.isEnabled(): self.player.setPosition(self.player.position() - 5000) self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) self.setTimeLabel() elif key == Qt.Key_Right: if self.videoSlider.isEnabled(): self.player.setPosition(self.player.position() + 5000) self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration()) self.setTimeLabel() elif key == Qt.Key_Up: self.volumeValue += 10 if self.volumeValue > 100: self.volumeValue = 100 self.volSlider.setValue(self.volumeValue) self.player.setVolume(self.volumeValue) elif key == Qt.Key_Down: self.volumeValue -= 10 if self.volumeValue < 0: self.volumeValue = 0 self.volSlider.setValue(self.volumeValue) self.player.setVolume(self.volumeValue) elif key == Qt.Key_Space: self.mediaPlay()
class MainWindow(QObject): #class constructor def __init__(self, ui_file, parent=None): #reference to our music player self.music_player = QMediaPlayer() self.music_player.setVolume(100) #call parent QObject constructor super(MainWindow, self).__init__(parent) #load the UI file into Python ui_file = QFile(ui_file) ui_file.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(ui_file) #always remember to close files ui_file.close() #add event listeners open_action = self.window.findChild(QAction, 'action_open') open_action.triggered.connect(self.open_action_triggered) quit_action = self.window.findChild(QAction, 'action_quit') quit_action.triggered.connect(self.quit_action_triggered) play_button = self.window.findChild(QPushButton, 'play_button') play_button.clicked.connect(self.play_button_clicked) pause_button = self.window.findChild(QPushButton, 'pause_button') pause_button.clicked.connect(self.pause_button_clicked) stop_button = self.window.findChild(QPushButton, 'stop_button') stop_button.clicked.connect(self.stop_button_clicked) raise_volume_button = self.window.findChild(QPushButton, 'raise_volume_button') raise_volume_button.clicked.connect(self.raise_volume_button_clicked) lower_volume_button = self.window.findChild(QPushButton, 'lower_volume_button') lower_volume_button.clicked.connect(self.lower_volume_button_clicked) #show window to user self.window.show() def open_action_triggered(self): file_name = QFileDialog.getOpenFileName(self.window) self.music_player.setMedia(QUrl.fromLocalFile(file_name[0])) def quit_action_triggered(self): self.window.close() def play_button_clicked(self): self.music_player.play() def pause_button_clicked(self): self.music_player.pause() def stop_button_clicked(self): self.music_player.stop() def raise_volume_button_clicked(self): volume = self.music_player.volume() if volume != 100: volume = volume + 10 self.music_player.setVolume(volume) def lower_volume_button_clicked(self): volume = self.music_player.volume() if volume != 0: volume = volume - 10 self.music_player.setVolume(volume)
class EditorWidget(QWidget): """Widget which contain the editor.""" def __init__(self, plugin_manager): super(EditorWidget, self).__init__() os.environ[ 'QT_MULTIMEDIA_PREFERRED_PLUGINS'] = 'windowsmediafoundation' self.plugin_manager = plugin_manager #parent layout self.v_box = QVBoxLayout() self.h_box = QHBoxLayout() # parent splitter for the text and numbers self.text_h_box = QSplitter(Qt.Horizontal) self.text_h_box.splitterMoved.connect(self.on_text_changed) self.settings = QSettings(c.SETTINGS_PATH, QSettings.IniFormat) self.keyboard_settings = QSettings(c.KEYBOARD_SETTINGS_PATH, QSettings.IniFormat) self.theme = self.settings.value(c.THEME, defaultValue=c.THEME_D) # font settings self.font = QFont( self.settings.value(c.FONT, defaultValue="Arial", type=str)) self.font.setPointSize( self.settings.value(c.FONT_SIZE, defaultValue=16, type=int)) # the text widget itself self.text = QPlainTextEdit() self.text.setFont(self.font) self.text.textChanged.connect(self.on_text_changed) self.text.setFocusPolicy(Qt.StrongFocus) # the number text widget to show the row numbers self.numbers = QPlainTextEdit() self.numbers.setFont(self.font) self.numbers.setReadOnly(True) self.numbers.setMinimumWidth(20) self.numbers.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.numbers.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.numbers.setLineWrapMode(QPlainTextEdit.NoWrap) self.numbers.setFocusPolicy(Qt.NoFocus) self.numbers.setFrameStyle(QFrame.NoFrame) self.numbers.setStyleSheet("background-color: rgba(0,0,0,0%)") # sync the text widget and number widget self.text_bar = self.text.verticalScrollBar() self.number_bar = self.numbers.verticalScrollBar() #self.number_bar.valueChanged.connect(self.text_bar.setValue) self.text_bar.valueChanged.connect(self.number_bar.setValue) # add them into their layout self.text_h_box.addWidget(self.numbers) self.text_h_box.addWidget(self.text) self.text_h_box.setSizes([10, 700]) # layout which holds the media controls in the bottom self.media_controls = QHBoxLayout() self.media_controls_settings = QVBoxLayout() self.media_controls_slider_h_box = QHBoxLayout() # direct player controls self.btn_size = 75 self.play_icon = QIcon( os.path.join(c.ICON_PATH, self.theme, "play.png")) self.pause_icon = QIcon( os.path.join(c.ICON_PATH, self.theme, "pause.png")) self.play_btn = QPushButton(icon=self.play_icon) self.play_btn.clicked.connect(self.on_play) self.play_btn.setFixedSize(self.btn_size, self.btn_size) self.play_btn.setIconSize(QSize(self.btn_size, self.btn_size)) self.play_btn.setFlat(True) self.play_btn.setShortcut(QKeySequence().fromString( self.keyboard_settings.value(c.PLAY_PAUSE_KEY, defaultValue=""))) self.forward_btn = QPushButton( icon=QIcon(os.path.join(c.ICON_PATH, self.theme, "forward.png"))) self.forward_btn.clicked.connect(self.on_forward) self.forward_btn.setFixedSize(self.btn_size, self.btn_size) self.forward_btn.setIconSize(QSize(self.btn_size, self.btn_size)) self.forward_btn.setFlat(True) self.forward_btn.setShortcut(QKeySequence().fromString( self.keyboard_settings.value(c.FORWARD_KEY, defaultValue=""))) self.backward_btn = QPushButton( icon=QIcon(os.path.join(c.ICON_PATH, self.theme, "backward.png"))) self.backward_btn.clicked.connect(self.on_backward) self.backward_btn.setFixedSize(self.btn_size, self.btn_size) self.backward_btn.setIconSize(QSize(self.btn_size, self.btn_size)) self.backward_btn.setFlat(True) self.backward_btn.setShortcut(QKeySequence().fromString( self.keyboard_settings.value(c.BACKWARDS_KEY, defaultValue=""))) # add them to the layout self.media_controls.addStretch() self.media_controls.addWidget(self.backward_btn) self.media_controls.addWidget(self.play_btn) self.media_controls.addWidget(self.forward_btn) self.media_controls.addStretch(4) # slider which shows the current time self.time_slider = QSlider(Qt.Horizontal) self.time_slider.sliderMoved.connect(self.on_time_slider_moved) # label on the right of the slider, which shows the current time self.time_label = QLabel("00:00/00:00") self.media_controls_slider_h_box.addWidget(self.time_slider) self.media_controls_slider_h_box.addWidget(self.time_label) # icons for the other sliders self.vol_icon = QIcon( os.path.join(c.ICON_PATH, self.theme, "volume.png")).pixmap(QSize(32, 32)) self.rate_icon = QIcon( os.path.join(c.ICON_PATH, self.theme, "playbackrate.png")).pixmap(QSize(32, 32)) self.rewind_icon = QIcon( os.path.join(c.ICON_PATH, self.theme, "time.png")).pixmap(QSize(32, 32)) # display the icons through labels self.vol_icon_label = QLabel() self.vol_icon_label.setPixmap(self.vol_icon) self.rate_icon_label = QLabel() self.rate_icon_label.setPixmap(self.rate_icon) self.rewind_rewind_label = QLabel() self.rewind_rewind_label.setPixmap(self.rewind_icon) # init of the other sliders self.vol_slider = QSlider(Qt.Horizontal) self.vol_slider.sliderMoved.connect(self.on_vol_slider_moved) self.vol_slider.setFixedWidth(250) self.vol_slider.setRange(1, 100) self.rate_slider = QSlider(Qt.Horizontal) self.rate_slider.sliderMoved.connect(self.on_rate_slider_moved) self.rate_slider.setFixedWidth(250) self.rate_slider.setRange(1, 20) self.rewind_time = 10 self.rewind_slider = QSlider(Qt.Horizontal) self.rewind_slider.sliderMoved.connect(self.on_rewind_slider_moved) self.rewind_slider.setFixedWidth(250) self.rewind_slider.setRange(1, 60) self.rewind_slider.setValue(self.rewind_time) # labels for the values self.vol_label = QLabel() self.rate_label = QLabel() self.rewind_label = QLabel() # create hbox for each of the three sliders self.vol_h_box = QHBoxLayout() self.vol_h_box.addWidget(self.vol_label) self.vol_h_box.addWidget(self.vol_slider) self.vol_h_box.addWidget(self.vol_icon_label) self.rate_h_box = QHBoxLayout() self.rate_h_box.addWidget(self.rate_label) self.rate_h_box.addWidget(self.rate_slider) self.rate_h_box.addWidget(self.rate_icon_label) self.rewind_h_box = QHBoxLayout() self.rewind_h_box.addWidget(self.rewind_label) self.rewind_h_box.addWidget(self.rewind_slider) self.rewind_h_box.addWidget(self.rewind_rewind_label) # group them together in a vlayout self.media_controls_settings.addLayout(self.vol_h_box) self.media_controls_settings.addLayout(self.rewind_h_box) self.media_controls_settings.addLayout(self.rate_h_box) # add this layout to the layout which already contains the buttons self.media_controls.addLayout(self.media_controls_settings) self.word_by_word_actions = QListWidget() self.word_by_word_actions.setMaximumWidth(150) self.h_box.addWidget(self.text_h_box) self.h_box.addWidget(self.word_by_word_actions) # group all ungrouped layouts and widgets to the parent layout self.v_box.addLayout(self.h_box, 10) self.v_box.addLayout(self.media_controls_slider_h_box, 1) self.v_box.addLayout(self.media_controls, 1) # set parent layout self.setLayout(self.v_box) # init media_player self.media_player = QMediaPlayer() self.video_widget = QVideoWidget() self.video_widget.setGeometry(200, 200, 500, 300) self.video_widget.setWindowTitle("Output") self.media_player.setVideoOutput(self.video_widget) self.media_player.positionChanged.connect(self.on_position_change) self.media_player.durationChanged.connect(self.on_duration_change) self.vol_slider.setValue(self.media_player.volume()) self.rate_slider.setValue(int(self.media_player.playbackRate() * 10)) self.on_vol_slider_moved(self.media_player.volume()) self.on_rate_slider_moved(self.media_player.playbackRate() * 10) self.on_rewind_slider_moved(self.rewind_time) self.activate_text_modules = False self.get_text_modules() self.text_option_on = QTextOption() self.text_option_on.setFlags( QTextOption.ShowTabsAndSpaces | QTextOption.ShowLineAndParagraphSeparators) self.text_option_off = QTextOption() self.transcription_meta_data = None self.word_pos = -1 self.word_start_time = None self.word_end_time = None self.tcf_highlight = QTextCharFormat() self.tcf_highlight.setBackground(Qt.red) self.tcf_normal = QTextCharFormat() self.tcf_normal.setBackground(Qt.transparent) self.show_empty_buttons = self.settings.value(c.SHOW_EMPTY_BUTTONS, defaultValue=True, type=bool) def on_position_change(self, position): """Is executed when media is played (position is changed) Args: position: Current position (ms) of the media player. """ self.time_slider.setValue(position) self.time_label.setText( create_time_string(position, self.media_player.duration())) if self.word_end_time is None: return if position > self.word_end_time: self.on_play() self.word_start_time = None self.word_end_time = None def on_duration_change(self, duration): """Is executed when duration of the media changes. Args: duration: duration of the media. """ self.time_slider.setRange(0, duration) self.time_label.setText( create_time_string(0, self.media_player.duration())) def on_time_slider_moved(self, value): """Is executed when the time slider was moved. Args: value: current value of the slider. """ self.media_player.setPosition(value) def on_vol_slider_moved(self, value): """Is executed when the volume slider is moved. Args: value: current value of the slider. """ self.media_player.setVolume(value) self.vol_label.setText(str(value) + "%") def on_rate_slider_moved(self, value): """Is executed when the rate slider is moved. Args: value: current value of the slider. """ self.media_player.setPlaybackRate(value / 10) self.rate_label.setText(str(value / 10) + "x") def on_rewind_slider_moved(self, value): """Is executed when the rewind slider is moved. Args: value: current value of the slider. """ self.rewind_time = value self.rewind_label.setText(str(value) + "s") def on_play(self): """Is executed when the play or pause button is pressed.""" if self.media_player.state() == QMediaPlayer.PlayingState: self.media_player.pause() self.play_btn.setIcon(self.play_icon) else: self.media_player.play() self.play_btn.setIcon(self.pause_icon) def on_forward(self): """Is executed when the forward button is pressed.""" self.media_player.setPosition(self.media_player.position() + self.rewind_time * 1000) def on_backward(self): """Is executed when the backward button is pressed.""" self.media_player.setPosition(self.media_player.position() - self.rewind_time * 1000) def on_text_changed(self): """Is executed when the text changed Calculates the line numbers and sets the text modules if activated. """ lines = int( self.text.document().documentLayout().documentSize().height()) self.numbers.setPlainText("") text = "" for i in range(1, lines + 1): text = text + str(i) + "\n" self.numbers.setPlainText(text) self.number_bar.setSliderPosition(self.text_bar.sliderPosition()) new_text = self.text.toPlainText() if self.activate_text_modules == True: for key in self.text_modules.keys(): to_replace = " " + key + " " to_replace_with = " " + self.text_modules[key] + " " new_text = new_text.replace(to_replace, to_replace_with) if self.text.toPlainText() != new_text: old_pos = self.text.textCursor().position() self.text.setPlainText(new_text) cursor = self.text.textCursor() cursor.setPosition(old_pos, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.EndOfWord) cursor.movePosition(QTextCursor.NextCharacter) self.text.setTextCursor(cursor) def show_video(self): """Shows or hides the video feed.""" if self.video_widget.isVisible(): self.video_widget.hide() else: self.video_widget.show() def open_project(self, project_folder_path): """Opens a project. Args: project_folder_path: folder of the project which should be opened. """ self.project_folder_path = project_folder_path self.media_file = file_util.get_file(self.project_folder_path, c.CON_COPY_POSTFIX) if self.media_file is None: self.hide() return self.media_player.setMedia( QMediaContent(QUrl.fromLocalFile(self.media_file))) self.transcription_path = file_util.get_file(self.project_folder_path, c.TRANSCRIPTION) if self.transcription_path is None: self.hide() return with open(self.transcription_path, 'r') as f: text = f.read() self.text.setPlainText(text) self.transcription_meta_data = file_util.get_value_from_shelve( self.project_folder_path, c.TRANSCRIPTION_META_DATA) print(self.transcription_meta_data) def change_font(self, new_font, new_size): """Changes the font. Args: new_font: Name of the new font. new_size: New font size. """ self.font = QFont(new_font) self.font.setPointSize(int(new_size)) self.text.setFont(self.font) self.numbers.setFont(self.font) self.settings.setValue(c.FONT_SIZE, int(new_size)) self.settings.setValue(c.FONT, new_font) def get_text_modules(self): """Gets the saved text_modules from the settings.""" self.text_modules = self.settings.value(c.TEXT_MODULES, defaultValue={}) def show_special_characters(self, bol): """Displays the special characters. Args: bol: true or false. """ if bol: self.text.document().setDefaultTextOption(self.text_option_on) else: self.text.document().setDefaultTextOption(self.text_option_off) def on_word_by_word(self): """Selects the next or first word in the on word by word editing mode. For that purpose th word_postion is increased and the next word is marked via the textcursor. If everything works correctly the population of the list will be started. """ self.word_pos += 1 #if self.media_player.state() == QMediaPlayer.PlayingState: # return if self.word_pos > len(self.text.toPlainText().split()) - 1: self.reset_word_by_word() return cursor = self.text.textCursor() if self.word_pos == 0: self.show_empty_buttons = self.settings.value(c.SHOW_EMPTY_BUTTONS, defaultValue=True, type=bool) cursor.setPosition(QTextCursor.Start, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.StartOfWord, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) self.text.setEnabled(False) else: cursor.movePosition(QTextCursor.NextWord, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) self.text.setTextCursor(cursor) selected_word = cursor.selectedText() if not selected_word: self.word_pos -= 1 self.on_word_by_word() return # change to find all meta data meta_data_with_word = self.find_meta_data(selected_word) self.populate_word_actions(selected_word, meta_data_with_word) def on_word_by_word_prev(self): """Same as word for word but selects to the previous word.""" if self.word_pos < 1: return self.word_pos -= 2 cursor = self.text.textCursor() count = 0 cursor.setPosition(QTextCursor.Start, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.StartOfWord, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) while count < self.word_pos: cursor.movePosition(QTextCursor.NextWord, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.KeepAnchor) count += 1 self.text.setTextCursor(cursor) self.on_word_by_word() def reset_word_by_word(self): """Resets the word by word editing mode and goes back to the normal editing.""" self.word_pos = -1 self.play_to = -1 self.text.setEnabled(True) self.word_by_word_actions.clear() cleaned = self.text.textCursor() cleaned.clearSelection() self.text.setTextCursor(cleaned) def populate_word_actions(self, selected, word_meta_data): """Calls the plugin_manager to get alle the word for word buttons and initalize the hear again buttons. Args: selected: The selected word. word_meta_data: The meta_data fr the word. """ self.word_by_word_actions.clear() if self.word_pos == len(self.text.toPlainText().split()): return self.plugin_manager.get_word_by_word_actions(selected, word_meta_data, self.word_pos) btns = [] for meta_data in word_meta_data: media_btn = HearButton(self, meta_data) btns.append(media_btn) self.add_new_word_by_word_action(btns, "Hear again", selected, self.word_pos) def add_new_word_by_word_action(self, btns, name, word, word_pos): """Adds a new word by word action. Args: btns: The buttons to add. name: The (plugin-)name of the buttons. word: The word for which these buttons are. word_pos: The word position. """ if not self.show_empty_buttons and len(btns) == 0: return if self.word_pos != word_pos: print("old item", word, word_pos, self.word_pos) return group_item = QListWidgetItem() group_item.setFlags(Qt.ItemIsSelectable) label = QLabel(name) label.setFixedSize(self.word_by_word_actions.width() - 15, 30) label.setContentsMargins(5, 0, 0, 0) label.setWordWrap(True) group_item.setSizeHint(label.size()) self.word_by_word_actions.addItem(group_item) self.word_by_word_actions.setItemWidget(group_item, label) for btn in btns: btn.setFixedSize(self.word_by_word_actions.width() - 15, 30) item = QListWidgetItem() item.setSizeHint(btn.size()) item.setFlags(Qt.ItemIsSelectable) self.word_by_word_actions.addItem(item) self.word_by_word_actions.setItemWidget(item, btn) def find_meta_data(self, word): """Gets all the meta_data for the given word. Args: word: The word for which the meta_data should be found. Returns: The meta_data """ meta_data_with_word = [] for m_d in self.transcription_meta_data: if m_d.get(c.WORD) == word.lower(): meta_data_with_word.append(m_d) return meta_data_with_word def replace_selection(self, new_word): """Replace the selection with the given word Args: new_word: The replacement. """ cursor = self.text.textCursor() old_cursor_pos = cursor.position() cursor.insertText(new_word) cursor.setPosition(old_cursor_pos, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.EndOfWord, QTextCursor.MoveAnchor) self.text.setTextCursor(cursor) self.word_by_word_actions.clear() def get_selection(self): """Returns the current selection Returns: The current selection. """ return self.text.textCursor().selectedText() def get_text(self): """Returns the current text Returns: The current text. """ return self.text.toPlainText() def set_text(self, new_text, restore_line_breaks=False): """Replace the text with the new text. Args: new_text: The new text. restore_line_breaks: If true, tries to restore the line breaks. (Default value = False) """ cursor = self.text.textCursor() old_cursor_pos = cursor.position() if restore_line_breaks: self.set_text_with_line_breaks(new_text) else: self.text.setPlainText(new_text) cursor.setPosition(old_cursor_pos, QTextCursor.MoveAnchor) self.text.setTextCursor(cursor) def get_word_at(self, pos): """Returns the word at the given position. Args: pos: The position of the word. Returns: The word at the given position. """ text = self.text.toPlainText().strip().split() if pos < 0 or pos > len(text): return None return text[pos % len(text)] def set_word_at(self, word, pos, replace_old): """Sets the word at the given position. Args: word: The replacement. pos: The position. replace_old: If true, the old word at the position will be replaced, otherwise the word will be set before the old word. """ old_word = self.get_word_at(pos) cursor = self.text.textCursor() cursor_pos = cursor.position() if pos < 0: self.text.setPlainText(word + " " + self.text.toPlainText()) cursor.setPosition(cursor_pos, QTextCursor.MoveAnchor) self.text.setTextCursor(cursor) return text = self.text.toPlainText().strip().split() if replace_old and pos < len(text): if word: text[pos] = word else: text.pop(pos) else: text.insert(pos, word) text = " ".join(text) self.set_text_with_line_breaks(text) cursor_pos += len(word) if replace_old: cursor_pos -= len(old_word) if not word: cursor_pos -= 1 else: cursor_pos += 1 words_to_cursor_pos = self.text.toPlainText()[:cursor_pos].split() self.word_pos = len(words_to_cursor_pos) - 1 cursor.setPosition(cursor_pos, QTextCursor.MoveAnchor) cursor.movePosition(QTextCursor.StartOfWord, QTextCursor.MoveAnchor) self.text.setTextCursor(cursor) def find_line_breaks(self): """Returns the lien breaks in the text. Returns: The positions of the linebreaks """ found = [] start = 0 text = self.text.toPlainText() while True: start = text.find("\n", start) if start == -1: return found found.append(start) start += len("\n") def set_text_with_line_breaks(self, text): """Sets the text with linebreaks. Args: text: the new text. """ line_breaks = self.find_line_breaks() for n in line_breaks: text = text[:n + 1] + "\n" + text[n + 1:] text = text.replace(" \n", "\n") text = text.replace("\n ", "\n") self.text.setPlainText(text) def insert_time_stamp(self): """Inserts the current timestamp at the current cursor position.""" cursor = self.text.textCursor() time = "[" + convert_ms(self.media_player.position()) + "]" cursor.insertText(time) def start_hear_again(self, start_time, end_time): """Starts the audio for the specific word from the hear again button. Args: start_time: When to start the audio. end_time: When to end the audio. """ if self.media_player.state() == QMediaPlayer.PlayingState: return self.media_player.pause() self.word_start_time = start_time self.word_end_time = end_time self.media_player.setPosition(self.word_start_time) self.on_play()
class VideoPlayer(QWidget): def __init__(self, aPath, parent=None): super(VideoPlayer, self).__init__(parent) self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAcceptDrops(True) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback) self.mediaPlayer.mediaStatusChanged.connect(self.printMediaData) self.mediaPlayer.setVolume(80) self.videoWidget = QVideoWidget(self) self.lbl = QLineEdit('00:00:00') self.lbl.setReadOnly(True) self.lbl.setFixedWidth(70) self.lbl.setUpdatesEnabled(True) self.lbl.setStyleSheet(stylesheet(self)) self.lbl.selectionChanged.connect(lambda: self.lbl.setSelection(0, 0)) self.elbl = QLineEdit('00:00:00') self.elbl.setReadOnly(True) self.elbl.setFixedWidth(70) self.elbl.setUpdatesEnabled(True) self.elbl.setStyleSheet(stylesheet(self)) self.elbl.selectionChanged.connect( lambda: self.elbl.setSelection(0, 0)) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedWidth(32) self.playButton.setStyleSheet("background-color: black") self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal, self) self.positionSlider.setStyleSheet(stylesheet(self)) self.positionSlider.setRange(0, 100) self.positionSlider.sliderMoved.connect(self.setPosition) self.positionSlider.setSingleStep(2) self.positionSlider.setPageStep(20) self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) self.clip = QApplication.clipboard() self.process = QProcess(self) self.process.readyRead.connect(self.dataReady) self.process.finished.connect(self.playFromURL) self.myurl = "" controlLayout = QHBoxLayout() controlLayout.setContentsMargins(5, 0, 5, 0) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.lbl) controlLayout.addWidget(self.positionSlider) controlLayout.addWidget(self.elbl) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.videoWidget) layout.addLayout(controlLayout) self.setLayout(layout) self.myinfo = "©2016\nAxel Schneider\n\nMouse Wheel = Zoom\nUP = Volume Up\nDOWN = Volume Down\n" + \ "LEFT = < 1 Minute\nRIGHT = > 1 Minute\n" + \ "SHIFT+LEFT = < 10 Minutes\nSHIFT+RIGHT = > 10 Minutes" self.widescreen = True #### shortcuts #### self.shortcut = QShortcut(QKeySequence("q"), self) self.shortcut.activated.connect(self.handleQuit) self.shortcut = QShortcut(QKeySequence("u"), self) self.shortcut.activated.connect(self.playFromURL) self.shortcut = QShortcut(QKeySequence("y"), self) self.shortcut.activated.connect(self.getYTUrl) self.shortcut = QShortcut(QKeySequence("o"), self) self.shortcut.activated.connect(self.openFile) self.shortcut = QShortcut(QKeySequence(" "), self) self.shortcut.activated.connect(self.play) self.shortcut = QShortcut(QKeySequence("f"), self) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence("i"), self) self.shortcut.activated.connect(self.handleInfo) self.shortcut = QShortcut(QKeySequence("s"), self) self.shortcut.activated.connect(self.toggleSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Up), self) self.shortcut.activated.connect(self.volumeUp) self.shortcut = QShortcut(QKeySequence(Qt.Key_Down), self) self.shortcut.activated.connect(self.volumeDown) self.shortcut = QShortcut( QKeySequence(Qt.ShiftModifier + Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider10) self.shortcut = QShortcut(QKeySequence(Qt.ShiftModifier + Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider10) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) print("QT5 Player started") print("press 'o' to open file (see context menu for more)") self.suspend_screensaver() def mouseDoubleClickEvent(self, event): self.handleFullscreen() def playFromURL(self): self.mediaPlayer.pause() self.myurl = self.clip.text() self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() print(self.myurl) def getYTUrl(self): cmd = "youtube-dl -g -f best " + self.clip.text() print("grabbing YouTube URL") self.process.start(cmd) def dataReady(self): self.myurl = str(self.process.readAll(), encoding='utf8').rstrip() ### self.myurl = self.myurl.partition("\n")[0] print(self.myurl) self.clip.setText(self.myurl) self.playFromURL() def suspend_screensaver(self): 'suspend linux screensaver' proc = subprocess.Popen( 'gsettings set org.gnome.desktop.screensaver idle-activation-enabled false', shell=True) proc.wait() def resume_screensaver(self): 'resume linux screensaver' proc = subprocess.Popen( 'gsettings set org.gnome.desktop.screensaver idle-activation-enabled true', shell=True) proc.wait() def openFile(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open Movie", QDir.homePath() + "/Videos", "Media (*.webm *.mp4 *.ts *.avi *.mpeg *.mpg *.mkv *.VOB *.m4v *.3gp *.mp3 *.m4a *.wav *.ogg *.flac *.m3u *.m3u8)" ) if fileName != '': self.loadFilm(fileName) print("File loaded") def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) mtime = QTime(0, 0, 0, 0) mtime = mtime.addMSecs(self.mediaPlayer.position()) self.lbl.setText(mtime.toString()) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) mtime = QTime(0, 0, 0, 0) mtime = mtime.addMSecs(self.mediaPlayer.duration()) self.elbl.setText(mtime.toString()) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) print("Error: ", self.mediaPlayer.errorString()) def handleQuit(self): self.mediaPlayer.stop() self.resume_screensaver() print("Goodbye ...") app.quit() def contextMenuRequested(self, point): menu = QMenu() actionFile = menu.addAction(QIcon.fromTheme("video-x-generic"), "open File (o)") actionclipboard = menu.addSeparator() actionURL = menu.addAction(QIcon.fromTheme("browser"), "URL from Clipboard (u)") actionclipboard = menu.addSeparator() actionYTurl = menu.addAction(QIcon.fromTheme("youtube"), "URL from YouTube (y)") actionclipboard = menu.addSeparator() actionToggle = menu.addAction(QIcon.fromTheme("next"), "show / hide Slider (s)") actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"), "Fullscreen (f)") action169 = menu.addAction(QIcon.fromTheme("tv-symbolic"), "16 : 9") action43 = menu.addAction(QIcon.fromTheme("tv-symbolic"), "4 : 3") actionSep = menu.addSeparator() actionInfo = menu.addAction(QIcon.fromTheme("help-about"), "Info (i)") action5 = menu.addSeparator() actionQuit = menu.addAction(QIcon.fromTheme("application-exit"), "Exit (q)") actionFile.triggered.connect(self.openFile) actionQuit.triggered.connect(self.handleQuit) actionFull.triggered.connect(self.handleFullscreen) actionInfo.triggered.connect(self.handleInfo) actionToggle.triggered.connect(self.toggleSlider) actionURL.triggered.connect(self.playFromURL) actionYTurl.triggered.connect(self.getYTUrl) action169.triggered.connect(self.screen169) action43.triggered.connect(self.screen43) menu.exec_(self.mapToGlobal(point)) def wheelEvent(self, event): mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() mscale = event.angleDelta().y() / 5 if self.widescreen == True: self.setGeometry(mleft, mtop, mwidth + mscale, round((mwidth + mscale) / 1.778)) else: self.setGeometry(mleft, mtop, mwidth + mscale, round((mwidth + mscale) / 1.33)) #elif self.positionSlider.hasFocus(): # self.positionSlider.value = self.positionSlider.value + 5 def screen169(self): self.widescreen = True mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() mratio = 1.778 self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio)) def screen43(self): self.widescreen = False mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() mratio = 1.33 self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio)) def handleFullscreen(self): if self.windowState() & Qt.WindowFullScreen: QApplication.setOverrideCursor(Qt.ArrowCursor) self.showNormal() print("no Fullscreen") else: self.showFullScreen() QApplication.setOverrideCursor(Qt.BlankCursor) print("Fullscreen entered") def handleInfo(self): msg = QMessageBox.about(self, "QT5 Player", self.myinfo) def toggleSlider(self): if self.positionSlider.isVisible(): self.hideSlider() else: self.showSlider() def hideSlider(self): self.playButton.hide() self.lbl.hide() self.positionSlider.hide() self.elbl.hide() mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() if self.widescreen == True: self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.778)) else: self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33)) def showSlider(self): self.playButton.show() self.lbl.show() self.positionSlider.show() self.elbl.show() mwidth = self.frameGeometry().width() mheight = self.frameGeometry().height() mleft = self.frameGeometry().left() mtop = self.frameGeometry().top() if self.widescreen == True: self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.55)) else: self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33)) def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000 * 60) def forwardSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000 * 60) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000 * 60) def backSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000 * 60) def volumeUp(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def mousePressEvent(self, evt): self.oldPos = evt.globalPos() def mouseMoveEvent(self, evt): delta = QPoint(evt.globalPos() - self.oldPos) self.move(self.x() + delta.x(), self.y() + delta.y()) self.oldPos = evt.globalPos() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() elif event.mimeData().hasText(): event.accept() else: event.ignore() def dropEvent(self, event): print("drop") if event.mimeData().hasUrls(): url = event.mimeData().urls()[0].toString() print("url = ", url) self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) self.playButton.setEnabled(True) self.mediaPlayer.play() elif event.mimeData().hasText(): mydrop = event.mimeData().text() ### YouTube url if "youtube" in mydrop: print("is YouTube", mydrop) self.clip.setText(mydrop) self.getYTUrl() else: ### normal url print("generic url = ", mydrop) self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() def loadFilm(self, f): self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) self.playButton.setEnabled(True) self.mediaPlayer.play() def printMediaData(self): if self.mediaPlayer.mediaStatus() == 6: if self.mediaPlayer.isMetaDataAvailable(): res = str(self.mediaPlayer.metaData("Resolution")).partition( "PyQt5.QtCore.QSize(")[2].replace(", ", "x").replace(")", "") print("%s%s" % ("Video Resolution = ", res)) if int(res.partition("x")[0]) / int( res.partition("x")[2]) < 1.5: self.screen43() else: self.screen169() else: print("no metaData available") def openFileAtStart(self, filelist): matching = [s for s in filelist if ".myformat" in s] if len(matching) > 0: self.loadFilm(matching)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.playlist = QMediaPlaylist() self.player = QMediaPlayer() toolBar = QToolBar() self.addToolBar(toolBar) fileMenu = self.menuBar().addMenu("&File") openAction = QAction(QIcon.fromTheme("document-open"), "&Open...", self, shortcut=QKeySequence.Open, triggered=self.open) fileMenu.addAction(openAction) exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit", self, shortcut="Ctrl+Q", triggered=self.close) fileMenu.addAction(exitAction) playMenu = self.menuBar().addMenu("&Play") playIcon = self.style().standardIcon(QStyle.SP_MediaPlay) self.playAction = toolBar.addAction(playIcon, "Play") self.playAction.triggered.connect(self.player.play) playMenu.addAction(self.playAction) previousIcon = self.style().standardIcon(QStyle.SP_MediaSkipBackward) self.previousAction = toolBar.addAction(previousIcon, "Previous") self.previousAction.triggered.connect(self.previousClicked) playMenu.addAction(self.previousAction) pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause) self.pauseAction = toolBar.addAction(pauseIcon, "Pause") self.pauseAction.triggered.connect(self.player.pause) playMenu.addAction(self.pauseAction) nextIcon = self.style().standardIcon(QStyle.SP_MediaSkipForward) self.nextAction = toolBar.addAction(nextIcon, "Next") self.nextAction.triggered.connect(self.playlist.next) playMenu.addAction(self.nextAction) stopIcon = self.style().standardIcon(QStyle.SP_MediaStop) self.stopAction = toolBar.addAction(stopIcon, "Stop") self.stopAction.triggered.connect(self.player.stop) playMenu.addAction(self.stopAction) self.volumeSlider = QSlider() self.volumeSlider.setOrientation(Qt.Horizontal) self.volumeSlider.setMinimum(0) self.volumeSlider.setMaximum(100) self.volumeSlider.setFixedWidth(app.desktop().availableGeometry(self).width() / 10) self.volumeSlider.setValue(self.player.volume()) self.volumeSlider.setTickInterval(10) self.volumeSlider.setTickPosition(QSlider.TicksBelow) self.volumeSlider.setToolTip("Volume") self.volumeSlider.valueChanged.connect(self.player.setVolume) toolBar.addWidget(self.volumeSlider) aboutMenu = self.menuBar().addMenu("&About") aboutQtAct = QAction("About &Qt", self, triggered=qApp.aboutQt) aboutMenu.addAction(aboutQtAct) self.videoWidget = QVideoWidget() self.setCentralWidget(self.videoWidget) self.player.setPlaylist(self.playlist) self.player.stateChanged.connect(self.updateButtons) self.player.setVideoOutput(self.videoWidget) self.updateButtons(self.player.state()) def open(self): fileDialog = QFileDialog(self) supportedMimeTypes = QMediaPlayer.supportedMimeTypes() if not supportedMimeTypes: supportedMimeTypes.append("video/x-msvideo") # AVI fileDialog.setMimeTypeFilters(supportedMimeTypes) moviesLocation = QStandardPaths.writableLocation(QStandardPaths.MoviesLocation) fileDialog.setDirectory(moviesLocation) if fileDialog.exec_() == QDialog.Accepted: self.playlist.addMedia(fileDialog.selectedUrls()[0]) self.player.play() def previousClicked(self): # Go to previous track if we are within the first 5 seconds of playback # Otherwise, seek to the beginning. if self.player.position() <= 5000: self.playlist.previous() else: player.setPosition(0) def updateButtons(self, state): mediaCount = self.playlist.mediaCount() self.playAction.setEnabled(mediaCount > 0 and state != QMediaPlayer.PlayingState) self.pauseAction.setEnabled(state == QMediaPlayer.PlayingState) self.stopAction.setEnabled(state != QMediaPlayer.StoppedState) self.previousAction.setEnabled(self.player.position() > 0) self.nextAction.setEnabled(mediaCount > 1)
class MainWindow(QObject): #class constructor def __init__(self, ui_file, parent=None): #reference to our music player self.music_player = QMediaPlayer() self.music_playlist = QMediaPlaylist() self.music_player.setVolume(80) #call parent QObject constructor super(MainWindow, self).__init__(parent) #load the UI file into Python ui_file = QFile(ui_file) ui_file.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(ui_file) self.window.setWindowFlags(Qt.MSWindowsFixedSizeDialogHint) self.window.setWindowTitle("SynthWAV") #always remember to close files ui_file.close() #add event listeners open_action = self.window.findChild(QAction, 'action_open') open_action.triggered.connect(self.open_action_triggered) quit_action = self.window.findChild(QAction, 'action_quit') quit_action.triggered.connect(self.quit_action_triggered) open_button = self.window.findChild(QPushButton, 'open_button') open_button.clicked.connect(self.open_action_triggered) quit_button = self.window.findChild(QPushButton, 'quit_button') quit_button.clicked.connect(self.quit_action_triggered) play_button = self.window.findChild(QPushButton, 'play_button') play_button.clicked.connect(self.play_button_clicked) pause_button = self.window.findChild(QPushButton, 'pause_button') pause_button.clicked.connect(self.pause_button_clicked) stop_button = self.window.findChild(QPushButton, 'stop_button') stop_button.clicked.connect(self.stop_button_clicked) progress_slider = self.window.findChild(QSlider, 'progress_slider') self.music_player.positionChanged.connect(self.update_progress) progress_slider.sliderMoved.connect(self.scrub_progress) volume_slider = self.window.findChild(QSlider, 'volume_slider') volume_slider.setValue(self.music_player.volume()) volume_slider.sliderMoved.connect(self.adjust_volume) next_button = self.window.findChild(QPushButton, 'next_button') next_button.clicked.connect(self.next_button_clicked) previous_button = self.window.findChild(QPushButton, 'previous_button') previous_button.clicked.connect(self.previous_button_clicked) fforward_button = self.window.findChild(QPushButton, 'fforward_button') fforward_button.clicked.connect(self.fforward_button_clicked) fbackward_button = self.window.findChild(QPushButton, 'fbackward_button') fbackward_button.clicked.connect(self.fbackward_button_clicked) self.music_playlist.currentMediaChanged.connect(self.change_title) #show window to user self.window.show() def open_action_triggered(self): files = QFileDialog.getOpenFileNames(self.window, "Add songs to playlist") for i in range(len(files[0])): self.music_playlist.addMedia(QUrl.fromLocalFile(str(files[0][i]))) self.music_playlist.setCurrentIndex(0) self.music_player.setPlaylist(self.music_playlist) def change_title(self): title_label = self.window.findChild(QLabel, 'media_title') show_title_path = self.music_playlist.currentMedia().canonicalUrl( ).fileName() show_title = os.path.splitext(show_title_path) title_label.setText(show_title[0]) def quit_action_triggered(self): self.window.close() def play_button_clicked(self): self.music_player.play() def pause_button_clicked(self): self.music_player.pause() def stop_button_clicked(self): self.music_player.stop() def next_button_clicked(self): self.music_playlist.next() def previous_button_clicked(self): self.music_playlist.previous() def fforward_button_clicked(self): self.music_player.setPosition(self.music_player.position() + 10000) def fbackward_button_clicked(self): self.music_player.setPosition(self.music_player.position() - 10000) def update_progress(self): progress_slider = self.window.findChild(QSlider, 'progress_slider') if self.music_player.duration != 0: progress_slider.setMaximum(self.music_player.duration()) total_sec = (self.music_player.duration() / 1000) % 60 total_min = (self.music_player.duration() / (1000 * 60)) % 60 if (total_sec < 10): total_time = ("%d:0%d" % (int(total_min), int(total_sec))) else: total_time = ("%d:%d" % (int(total_min), int(total_sec))) track_duration_label = self.window.findChild( QLabel, 'track_duration_label') track_duration_label.setText(total_time) progress = self.music_player.position() progress_slider.setValue(progress) cur_sec = (self.music_player.position() / 1000) % 60 cur_min = (self.music_player.position() / (1000 * 60)) % 60 if (cur_sec < 10): cur_time = ("%d:0%d" % (int(cur_min), int(cur_sec))) else: cur_time = ("%d:%d" % (int(cur_min), int(cur_sec))) track_current_label = self.window.findChild(QLabel, 'track_current_label') track_current_label.setText(cur_time) def scrub_progress(self): progress_slider = self.window.findChild(QSlider, 'progress_slider') self.music_player.setPosition(progress_slider.sliderPosition()) cur_min = (self.music_player.position() / 1000) % 60 cur_sec = (self.music_player.position() / (1000 * 60)) % 60 if (cur_sec < 10): cur_time = ("%d:0%d" % (int(cur_min), int(cur_sec))) else: cur_time = ("%d:%d" % (int(cur_min), int(cur_sec))) track_current_label = self.window.findChild(QLabel, 'track_current_label') track_current_label.setText(cur_time) def adjust_volume(self): volume_slider = self.window.findChild(QSlider, 'volume_slider') self.music_player.setVolume(volume_slider.sliderPosition())
class MainWindow(QObject): #class constructor def __init__(self, ui_file, parent=None): #reference to our music player self.music_player = QMediaPlayer() volume = self.music_player.setVolume(100) #call parent QObject constructor super(MainWindow, self).__init__(parent) #load the UI file into Python ui_file = QFile(ui_file) ui_file.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(ui_file) #always remember to close files ui_file.close() #add event listeners open_action = self.window.findChild(QAction, 'action_open') open_action.triggered.connect(self.open_action_triggered) quit_action = self.window.findChild(QAction, 'action_quit') quit_action.triggered.connect(self.quit_action_triggered) play_button = self.window.findChild(QPushButton, 'play_button') play_button.clicked.connect(self.play_button_clicked) pause_button = self.window.findChild(QPushButton, 'pause_button') pause_button.clicked.connect(self.pause_button_clicked) v_up = self.window.findChild(QPushButton, 'v_up') v_up.clicked.connect(self.v_up_clicked) v_down = self.window.findChild(QPushButton, 'v_down') v_down.clicked.connect(self.v_down_clicked) #skip_prev = self.window.findChild(QPushButton, 'skip_prev') #skip_prev.clicked.connect(self.skip_prev_clicked) #skip_next = self.window.findChild(QPushButton, 'skip_next') #skip_next.clicked.connect(self.skip_next_clicked) #show window to user self.window.show() def open_action_triggered(self): file_name = QFileDialog.getOpenFileName(self.window) self.music_player.setMedia(QUrl.fromLocalFile(file_name[0])) def quit_action_triggered(self): self.window.close() def play_button_clicked(self): self.music_player.play() def pause_button_clicked(self): self.music_player.pause() def v_up_clicked(self): vol = self.music_player.volume() self.music_player.setVolume(vol + 10) def v_down_clicked(self): vol = self.music_player.volume() self.music_player.setVolume(vol - 10)