class Player(QGraphicsVideoItem): def __init__(self, parent=None): super().__init__() self.parent = parent self.player = QMediaPlayer() self.player.setVideoOutput(self) def playerPlayOrOpen(self, arg=None): if type(arg) == list and len(arg) > 1: content = QMediaContent(QUrl.fromLocalFile(arg[1])) self.player.setMedia(content) self.play() def addVideo(self, video): content = QMediaContent(QUrl.fromLocalFile(video)) self.player.setMedia(content) self.play() def sliderChanged(self, pos): self.player.setPosition(pos) def mouseDoubleClickEvent(self, event): if not self.parent.isFullScreen(): self.parent.showFullScreen() else: self.parent.showNormal() def play(self): self.player.play() def stop(self): self.player.stop() def pause(self): self.player.pause() def setMuted(self, mute): self.player.setMuted(mute) def mutedState(self): if self.player.isMuted(): self.setMuted(False) else: self.setMuted(True) def isMuted(self): return self.player.isMuted() def setVolume(self, value): self.player.setVolume(value) def volume(self): return self.player.volume()
def __alarm(self): if not self.go: return; self.timer.stop() player = QMediaPlayer(self); player.setMedia(QMediaContent(QUrl.fromLocalFile(self.music))); player.setVolume(100); player.play(); self.setEnabled(False) QMessageBox.critical(self, "ALERTA", "TIME TO DIE<br>" + self.ui.groupBox.title(), QMessageBox.Yes) self.setEnabled(True) player.stop() player.deleteLater()
class AudioPlayBack(): def __init__(self): self.__audioPlayback = QMediaPlayer() self.__audioPlayback.setVolume(50) self.__audioPlayback.positionChanged.connect(self.onTick) pass def onTick(self, e=None): print(self.__audioPlayback.position(), self.__audioPlayback.state()) Event.dis(AudioPlaybackEvent.TICK, self.__audioPlayback.position()) pass def load(self, path): content = QMediaContent(QUrl(path)) self.__audioPlayback.setMedia(content) self.__audioPlayback.play() pass def seek(self, position): self.__audioPlayback.setPosition(position) pass def play(self): if self.__audioPlayback.state() == QMediaPlayer.PausedState: self.__audioPlayback.play() pass pass def pause(self): if self.__audioPlayback.state() == QMediaPlayer.PlayingState: self.__audioPlayback.pause() pass pass # 0~100 def setVolume(self, vol): self.__audioPlayback.setVolume(vol) pass
class IntroWindow(QMainWindow, Form): def __init__(self): Form.__init__(self) QMainWindow.__init__(self) self.setWindowIcon(QIcon("logo.png")) p = self.palette() p.setColor(QPalette.Window, Qt.gray) self.setPalette(p) self.setupUi(self) self.a = 1 self.videowidget = QVideoWidget() self.vertical.addWidget(self.videowidget) self.videoplayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoplayer.setVideoOutput(self.videowidget) self.sliderfilm.setRange(0, 0) self.volume.setRange(0, 100) self.videoplayer.setVolume(100) self.volume.setValue(100) self.play.setEnabled(False) self.increaseRate.setEnabled(False) self.decreaseRate.setEnabled(False) self.sliderfilm.installEventFilter(self) self.volume.installEventFilter(self) self.frames.installEventFilter(self) self.frame_2.installEventFilter(self) self.frames.installEventFilter(self) # putting Icons on buttons self.increaseRate.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekForward)) self.decreaseRate.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekBackward)) self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.open.setIcon(self.style().standardIcon(QStyle.SP_DirHomeIcon)) self.skipforward.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) self.skipback.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipBackward)) self.stop.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.sliderfilm.sliderMoved.connect(self.setpos) self.videoplayer.positionChanged.connect(self.position) self.videoplayer.durationChanged.connect(self.changed) self.videoplayer.volumeChanged.connect(self.setvolpos) self.volume.sliderMoved.connect(self.setvolpos) self.actionOpen.triggered.connect(self.Loadvideo) self.actionSearch_By_Tag.triggered.connect(self.opensecond) self.actionFullscreen.triggered.connect(self.screen) self.skipforward.clicked.connect(self.skipforw) self.skipback.clicked.connect(self.skipbac) self.increaseRate.clicked.connect(self.incRate) self.decreaseRate.clicked.connect(self.decRate) self.play.clicked.connect(self.play_video) self.open.clicked.connect(lambda: self.Loadvideo(self.videoplayer)) self.stop.clicked.connect(self.stopp) self.listView.hide() self.tolfilm = 0 self.listviewstatus = 0 self.listbtn.clicked.connect(lambda: self.list()) self.listView.itemClicked.connect(self.listwidgetclicked) self.theme1.triggered.connect(lambda: self.theme01()) self.theme2.triggered.connect(lambda: self.theme02()) self.theme3.triggered.connect(lambda: self.theme03()) self.theme4.triggered.connect(lambda: self.theme04()) self.actionFarsi.triggered.connect(lambda: self.farsi()) self.actionEnglish.triggered.connect(lambda: self.english()) self.filename = "" self.x = 0 self.videowidget3 = QVideoWidget() self.verticalLayout_8.addWidget(self.videowidget3) self.videoplayer3 = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.videoplayer3.setVideoOutput(self.videowidget3) self.widget.hide() self.stop.setEnabled(False) self.m = 0 self.dataL = [] with open("config.txt") as f: self.config = f.read() if int(self.config) == 11: self.theme01() self.farsi() if int(self.config) == 12: self.theme01() self.english() elif int(self.config) == 21: self.farsi() self.theme02() elif int(self.config) == 22: self.english() self.theme02() elif int(self.config) == 31: self.farsi() self.theme03() elif int(self.config) == 32: self.english() self.theme03() elif int(self.config) == 41: self.farsi() self.theme04() elif int(self.config) == 42: self.english() self.theme04() def farsi(self): self.menuLanguage.setTitle("زبان") self.menuView.setTitle("نمایش") self.theme1.setText("تم ۱") self.theme2.setText("تم ۲") self.theme3.setText("تم ۳") self.theme4.setText("تم ۴") self.menuFile.setTitle("فایل") self.actionOpen.setText("باز کردن ویدیو") self.actionSearch_By_Tag.setText("پنل تگ ها") self.actionFullscreen.setText("تمام صفحه") self.actionEnglish.setText("انگلیسی") self.actionFarsi.setText("فارسی") self.decreaseRate.setStatusTip("کاهش سرعت") self.decreaseRate.setToolTip("کاهش سرعت") self.increaseRate.setStatusTip("افزایش سرعت") self.increaseRate.setToolTip("افزایش سرعت") self.open.setStatusTip("باز کردن ویدیو") self.open.setToolTip("باز کردن ویدیو") self.stop.setStatusTip("توقف") self.stop.setToolTip("توقف") self.skipback.setStatusTip("عقب رفتن") self.skipback.setToolTip("عقب رفتن") self.play.setStatusTip("شروع/ایست") self.play.setToolTip("شروع/ایست") self.skipforward.setStatusTip("جلو رفتن") self.skipforward.setToolTip("جلو رفتن") self.volume.setStatusTip("صدا") self.volume.setToolTip("صدا") self.listbtn.setStatusTip("دسترسی آسان") self.listbtn.setToolTip( "پنلی شامل تگ ها و پنجره ای برای پیش نمایش را نمایان/پنهان میکند که با کلیک کردن بر روی هر کدام ویدیو به آن لحظه میرود" ) with open("config.txt") as f: self.config = f.read() if int(self.config) // 10 == 1: with open("config.txt", "w") as f2: f2.write("11") if int(self.config) // 10 == 2: with open("config.txt", "w") as f2: f2.write("21") if int(self.config) // 10 == 3: with open("config.txt", "w") as f2: f2.write("31") if int(self.config) // 10 == 4: with open("config.txt", "w") as f2: f2.write("41") def english(self): self.menuLanguage.setTitle("Language") self.menuView.setTitle("View") self.theme1.setText("Theme1") self.theme2.setText("Theme2") self.theme3.setText("Theme3") self.theme4.setText("Theme4") self.menuFile.setTitle("File") self.actionOpen.setText("Open Video") self.actionSearch_By_Tag.setText("Tags Panel") self.actionFullscreen.setText("Fullscreen") self.actionEnglish.setText("English") self.actionFarsi.setText("Persian") self.decreaseRate.setStatusTip("Decrease Play Speed") self.decreaseRate.setToolTip("Decrease Play Speed") self.increaseRate.setStatusTip("Increase Play Speed") self.increaseRate.setToolTip("Increase Play Speed") self.open.setStatusTip("Open Video") self.open.setToolTip("Open Video") self.stop.setStatusTip("Stop") self.stop.setToolTip("Stop") self.skipback.setStatusTip("Previous") self.skipback.setToolTip("Previous") self.play.setStatusTip("Play/Pause") self.play.setToolTip("Play/Pause") self.skipforward.setStatusTip("Next") self.skipforward.setToolTip("Next") self.volume.setStatusTip("Volume") self.volume.setToolTip("Volume") self.listbtn.setStatusTip("Easy Access") self.listbtn.setToolTip( "Shows/Hides a panel for the tags that can be clicked on to take the video to its moment and also a preview window" ) with open("config.txt") as f: self.config = f.read() if self.config == "": with open("config.txt", w) as f2: f2.write("11") self.config = "11" if int(self.config) // 10 == 1: with open("config.txt", "w") as f2: f2.write("12") if int(self.config) // 10 == 2: with open("config.txt", "w") as f2: f2.write("22") if int(self.config) // 10 == 3: with open("config.txt", "w") as f2: f2.write("32") if int(self.config) // 10 == 4: with open("config.txt", "w") as f2: f2.write("42") def moviess(self): x = self.filename.split("/") file_name = self.filename[:self.filename.find(x[len(x) - 1])] png = "" png2 = "" folders = os.listdir(file_name + r"/") for file in folders: if file.find(".mp4") > 0: png = png + ";" + file_name + file png2 = ";" + file_name + file + png2 png = png + ";" self.png = png png2 = png2 + ";" self.png2 = png2 def hoverleave(self): self.widget.hide() def gotovolume(self): x, _ = win32api.GetCursorPos() self.videoplayer.setVolume( int((x - self.mapToGlobal(self.volume.pos()).x()) / self.volume.width() * 100)) self.volume.setValue( int((x - self.mapToGlobal(self.volume.pos()).x()) / self.volume.width() * 100)) if self.m % 2 == 1: self.m += 1 self.videoplayer.setMuted(False) def goto(self): x, _ = win32api.GetCursorPos() if self.filename != "": self.videoplayer.setPosition( (x - self.mapToGlobal(self.sliderfilm.pos()).x()) / self.sliderfilm.width() * self.dur * 1000) def onHovered(self): x, _ = win32api.GetCursorPos() if self.filename != "": if self.listviewstatus % 2 == 1: self.videoplayer3.setPosition( (x - self.mapToGlobal(self.sliderfilm.pos()).x()) / self.sliderfilm.width() * self.dur * 1000) self.widget.show() def eventFilter(self, obj, event): if obj == self.sliderfilm and event.type() == QtCore.QEvent.HoverMove: self.onHovered() elif (obj == self.frames or obj == self.frame_2) and event.type() == QtCore.QEvent.Enter: self.hoverleave() elif obj == self.sliderfilm and event.type( ) == QtCore.QEvent.MouseButtonPress: self.goto() elif obj == self.volume and event.type( ) == QtCore.QEvent.MouseButtonPress: self.gotovolume() elif obj == self.frames and event.type( ) == QtCore.QEvent.MouseButtonDblClick: if not self.isFullScreen(): self.fulls() else: self.unfull() return super(QMainWindow, self).eventFilter(obj, event) def stopp(self): self.stop.setEnabled(False) self.videoplayer.stop() self.videoplayer.setPosition(0) self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) def listwidgetclicked(self, item): t = item.text() t = t[t.find(">") + 1:] pt = datetime.strptime(t, "%H:%M:%S") total_seconds = pt.second + pt.minute * 60 + pt.hour * 3600 if self.a == 0: self.videoplayer.setPosition(total_seconds * 1000) def list(self): if self.listviewstatus % 2 == 1: self.listView.hide() self.widget.hide() self.listbtn.setText("^") self.listviewstatus += 1 else: self.listbtn.setText("v") self.listviewstatus += 1 self.listView.show() def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: if self.isFullScreen(): self.unfull() elif e.key() == Qt.Key_6: if self.filename != "": self.videoplayer.setPosition(self.videoplayer.position() + 5000) elif e.key() == Qt.Key_4: if self.filename != "": self.videoplayer.setPosition(self.videoplayer.position() - 5000) elif e.key() == Qt.Key_Space: if self.filename != "": self.play_video() elif e.key() == Qt.Key_M: if self.m % 2 == 0: self.m += 1 self.videoplayer.setMuted(True) self.volume.setEnabled(False) self.vvv = self.volume.value() self.volume.setValue(0) else: self.m += 1 self.volume.setValue(self.vvv) self.volume.setEnabled(True) self.videoplayer.setMuted(False) def screen(self): if not self.isFullScreen(): self.fulls() else: self.unfull() # forward media 5s def skipforw(self): a = self.png.find(self.filename) aa = self.png.find(";", a + 1) filename = self.png[aa + 1:self.png.find(";", aa + 1)] if filename != "": self.filename = filename self.videoplayer.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.videoplayer3.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) title = filename.split("/") title = title[len(title) - 1] self.setWindowTitle(f"Taz Player openning{title}") self.videoplayer3.play() self.videoplayer3.pause() self.widget.hide() self.videoplayer.setPosition(0) self.videoplayer.play() self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) clip = VideoFileClip(filename) self.dur = clip.duration def skipbac(self): a = self.png2.find(self.filename) aa = self.png2.find(";", a + 1) filename = self.png2[aa + 1:self.png2.find(";", aa + 1)] if filename != "": self.filename = filename self.videoplayer.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.videoplayer3.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) title = filename.split("/") title = title[len(title) - 1] self.setWindowTitle(f"Taz Player openning{title}") self.videoplayer3.play() self.videoplayer3.pause() self.widget.hide() self.videoplayer.setPosition(0) self.videoplayer.play() self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) clip = VideoFileClip(filename) self.dur = clip.duration # set increase rate def incRate(self): if self.videoplayer.playbackRate() == 0: x = self.videoplayer.playbackRate() + 1 else: x = self.videoplayer.playbackRate() self.videoplayer.setPlaybackRate(x + 0.25) # set decrease rate def decRate(self): if self.videoplayer.playbackRate() == 0: x = self.videoplayer.playbackRate() + 1 else: x = self.videoplayer.playbackRate() self.videoplayer.setPlaybackRate(x - 0.25) # Handling Tags def fillListView(self): for i in range(len(self.dataL)): self.listView.addItem(self.dataL[i][0] + "->" + self.dataL[i][1]) def updateTagFile(self): fname = self.fileName.split(".") fname = fname[0] with open(fname + ".csv", mode="w") as f: writer = csv.writer( f, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL, lineterminator="\n", ) for line in self.dataL: writer.writerow(line) def giveTime(self): vidPos = self.videoplayer.position() h = int(vidPos / 1000 // 3600) m = int((vidPos / 1000 - h * 3600) // 60) s = int(((vidPos / 1000 - h * 3600 - m * 60) % 60) % 60) * 100 // 100 if h < 10: h = "0" + str(h) if m < 10: m = "0" + str(m) if s < 10: s = "0" + str(s) return f"{h}:{m}:{s}" def insertTag(self, tableWidget): t = tableWidget tag = "New Tag" tagTime = self.giveTime() l = len(self.dataL) i = 0 flag = False while tagTime > self.dataL[i][1]: i += 1 if i >= l: break if i < l: if tagTime == self.dataL[i][1]: flag = True if not flag: self.dataL.insert(i, [tag, tagTime]) t.insertRow(i) t.setItem( i, 0, QTableWidgetItem(tag), ) t.setItem( i, 1, QTableWidgetItem(tagTime), ) t.editItem(t.item(i, 0)) def removeRow(self, tableWidget): if len(self.dataL) > 0: self.dataL.remove(self.dataL[tableWidget.currentRow()]) tableWidget.removeRow(tableWidget.currentRow()) def updateList(self, tableWidget): for i in range(tableWidget.rowCount()): self.dataL[i] = [ tableWidget.item(i, 0).text(), tableWidget.item(i, 1).text(), ] def undoChanges(self): fname = self.fileName.split(".") fname = fname[0] with open(fname + ".csv", mode="r+") as f: data = csv.reader(f) self.dataL = list(data) def fillTable(self, tableWidget): tableWidget.setRowCount(len(self.dataL)) for i in range(len(self.dataL)): tableWidget.setItem(i, 0, QTableWidgetItem(self.dataL[i][0])) tableWidget.setItem(i, 1, QTableWidgetItem(self.dataL[i][1])) def openTagFile(self): filename, _ = QFileDialog.getOpenFileName( self, "Open Tag File", filter="*.csv", ) if filename != "": self.fileName = filename with open(filename, mode="r+") as f: data = csv.reader(f) self.dataL = list(data) def opensecond(self): login_page = LoginPage() login_page.setWindowFlags(QtCore.Qt.WindowCloseButtonHint) if int(self.config) % 10 == 1: login_page.Save.setText("برو به") login_page.apply.setText("اعمال تغییرات") login_page.buttonBox.button(QDialogButtonBox.Ok).setText("تایید") login_page.buttonBox.button( QDialogButtonBox.Cancel).setText("انصراف") login_page.AddRow.setText("افزودن تگ") login_page.DeleteRow.setText("حذف تگ") login_page.OpenTagButton.setText("باز کردن فایل تگ") login_page.tableWidget.setHorizontalHeaderLabels(["تگ", "زمان"]) else: login_page.tableWidget.setHorizontalHeaderLabels(["Tag", "Time"]) self.fillTable(login_page.tableWidget) login_page.buttonBox.accepted.connect(lambda: [ self.updateList(login_page.tableWidget), self.listbtn.setFocus(), self.listView.clear(), self.fillListView(), self.updateTagFile(), ]) login_page.buttonBox.rejected.connect(lambda: [ self.listbtn.setFocus(), self.undoChanges(), ]) login_page.apply.clicked.connect(lambda: [ self.updateList(login_page.tableWidget), self.listView.clear(), self.fillListView(), ]) login_page.AddRow.clicked.connect(lambda: [ self.insertTag(login_page.tableWidget), ]) login_page.Save.clicked.connect(lambda: [ login_page.shows(self), self.updateList(login_page.tableWidget), self.listbtn.setFocus(), self.listView.clear(), self.fillListView(), ]) login_page.DeleteRow.clicked.connect(lambda: [ self.removeRow(login_page.tableWidget), ]) login_page.OpenTagButton.clicked.connect(lambda: [ self.openTagFile(), self.fillTable(login_page.tableWidget), self.listView.clear(), self.fillListView(), ]) login_page.tableWidget.sortByColumn(1, Qt.AscendingOrder) # if int(self.config) % 10 == 2: # login_page.tableWidget.setHorizontalHeaderLabels(["Tag", "Time"]) # else: # login_page.tableWidget.setHorizontalHeaderLabels(["تگ", "زمان"]) login_page.exec_() # End of Handling Tags def fulls(self): self.decreaseRate.hide() self.increaseRate.hide() self.centralwidget.setContentsMargins(0, 0, 0, 0) self.play.hide() self.open.hide() self.skipforward.hide() self.skipback.hide() self.label.hide() self.label_2.hide() self.volume.hide() self.menubar.hide() self.sliderfilm.hide() self.statusBar.hide() self.showFullScreen() self.listbtn.hide() self.widget.hide() self.listView.hide() self.frame_2.hide() self.stop.hide() self.listviewstatus = 1 def unfull(self): self.frame_2.show() self.stop.show() self.list() self.centralwidget.setContentsMargins(10, 10, 10, 10) self.decreaseRate.show() self.increaseRate.show() self.play.show() self.open.show() self.skipforward.show() self.skipback.show() self.label.show() self.label_2.show() self.volume.show() self.menubar.show() self.sliderfilm.show() self.statusBar.show() self.showNormal() self.listbtn.show() ##setting position of film def setpos(self, position): self.videoplayer.setPosition(position) def position(self, position): position2 = self.tolfilm * 1000 - position + 1000 hour = int((position / 3600000) % 24) hour2 = int((position2 / 3600000) % 24) if hour < 10: hour = "0" + str(hour) if hour2 < 10: hour2 = "0" + str(hour2) minute = int((position / 60000) % 60) minute2 = int((position2 / 60000) % 60) if minute < 10: minute = "0" + str(minute) if minute2 < 10: minute2 = "0" + str(minute2) second = int((position / 1000) % 60) second2 = int((position2 / 1000) % 60) if second < 10: second = "0" + str(second) if second2 < 10: second2 = "0" + str(second2) self.label.setText(f"{hour}:{minute}:{second}") self.label_2.setText(f"{hour2}:{minute2}:{second2}") self.sliderfilm.setValue(position) if position2 < 1000: self.videoplayer.stop() self.sliderfilm.setValue(0) self.stop.setEnabled(False) self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) def changed(self, duration): self.sliderfilm.setRange(0, duration) ##setting position of volume def setvolpos(self, position): self.videoplayer.setVolume(position) ##open button or open from menu bar def Loadvideo(self, videoplayer): self.a = 0 filename, _ = QFileDialog.getOpenFileName( self, "Open Video", filter="*.mp4;*.mov;*.wmv;*.webm;*.wmv;*.m4v;*.m4a;*.flv", ) if filename != "": self.videoplayer.setPosition(0) self.filename = filename if filename != "": self.fileName = filename.split(".")[0] fname = filename.split(".") fnmae = fname[0] if os.path.isfile(fnmae + ".csv"): with open(fnmae + ".csv", mode="r+") as f: data = csv.reader(f) self.dataL = list(data) self.listView.clear(), self.fillListView() clip = VideoFileClip(filename) self.dur = clip.duration self.videoplayer.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.videoplayer3.setMedia( QMediaContent(QUrl.fromLocalFile(filename))) self.moviess() clip = VideoFileClip(filename) self.tolfilm = int(clip.duration) title = filename.split("/") title = title[len(title) - 1] self.setWindowTitle(f"Taz Player openning : {title}") self.videoplayer3.play() self.videoplayer3.pause() self.widget.hide() self.stop.setEnabled(True) self.videoplayer.play() self.play.setEnabled(True) self.play.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) self.increaseRate.setEnabled(True) self.decreaseRate.setEnabled(True) ##play button def play_video(self): if self.videoplayer.state() == QMediaPlayer.PlayingState: self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.videoplayer.pause() else: self.videoplayer.play() self.stop.setEnabled(True) self.play.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) def theme01(self): self.videowidget.setStyleSheet("background-color: #404040") self.setStyleSheet("background-color: #A0A0A0") if self.theme1.text() == "Theme1": with open("config.txt", "w") as f: f.write("12") else: with open("config.txt", "w") as f: f.write("11") def theme02(self): self.videowidget.setStyleSheet("background-color: #330019") self.setStyleSheet("background-color: #990000") if self.theme1.text() == "Theme1": with open("config.txt", "w") as f: f.write("22") else: with open("config.txt", "w") as f: f.write("21") def theme03(self): self.videowidget.setStyleSheet("background-color: #35557F") self.setStyleSheet("background-color: #003366") if self.theme1.text() == "Theme1": with open("config.txt", "w") as f: f.write("32") else: with open("config.txt", "w") as f: f.write("31") def theme04(self): self.videowidget.setStyleSheet("background-color: #00FF00") self.setStyleSheet("background-color: #4C9900") if self.theme1.text() == "Theme1": with open("config.txt", "w") as f: f.write("42") else: with open("config.txt", "w") as f: f.write("41")
class VideoPlayer(QVideoWidget): # doubleClicked = pyqtSignal() clicked = pyqtSignal() # keyPressed = pyqtSignal() # rtime_changed = pyqtSignal(str) # duration_changed = pyqtSignal(int) def __init__(self, parent=None): super(VideoPlayer, self).__init__(parent) self.playing = False self.full_screen = False self.media_player = QMediaPlayer() self.media_player.setVideoOutput(self) self.widescreen = True self.media_player.setVolume(0) def load_video(self, path): self.media_player.setMedia(QMediaContent(QUrl.fromLocalFile(path))) def play(self): if self.playing is False: self.media_player.play() self.playing = True else: self.media_player.pause() self.playing = False def stop(self): self.media_player.stop() self.playing = False def set_volume(self, volume): self.media_player.setVolume(volume) def mousePressEvent(self, event): # self.play() self.clicked.emit() super(VideoPlayer, self).mousePressEvent(event) def update_position(self, position): self.media_player.setPosition(position) def set_postion(self, position): self.media_player.setPosition(position) def mouseDoubleClickEvent(self, event): self.set_fullscreen() def set_fullscreen(self): self.setFullScreen(not self.isFullScreen()) def keyPressEvent(self, event): if event.key() == Qt.Qt.Key_Escape and self.isFullScreen(): self.setFullScreen(False) event.accept() else: super(VideoPlayer, self).keyPressEvent(event)
class VideoPlayer(QWidget): def __init__(self, parent=None): global gantChart global Topics super(VideoPlayer, self).__init__(parent) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.setVolume(0) #Parse json file videoGlobals.classLabels, videoGlobals.highLabels, videoGlobals.annotationColors, videoGlobals.eventColors = self.parseJson() Topics = None self.time_ = 0 self.time_dif = 0 self.duration = 0 self.message_count = 0 self.videobox = [] self.box_buffer = [] self.metric_buffer = [] #Audio variables self.player = QMediaPlayer() self.playlist = QMediaPlaylist(self) self.playFlag = False self.topic_window = topicBox.TopicBox() # >> DEFINE WIDGETS OCJECTS # >> VIDEO - AUDIO - GANTT CHART #---------------------- self.videoWidget = VideoWidget() self.videoWidget.setFixedSize(640, 480) #Video buttons videoLayout = self.createVideoButtons() #Video Gantt Chart self.gantt = gantChart.gantShow() gantChart = self.gantt gantChart.axes.get_xaxis().set_visible(False) gantChart.setFixedSize(1300, 90) #Create Slider self.createSlider() self.controlEnabled = False #Specify video layout align laserAndVideoLayout = QHBoxLayout() laserAndVideoLayout.addLayout(videoLayout) #Audio Player buttons buttonLayoutAudio = self.createAudioButtons() waveLayout = self.createAudio() self.mainLayout = QVBoxLayout() self.mainLayout.addLayout(laserAndVideoLayout) self.mainLayout.addWidget(self.positionSlider) self.mainLayout.addWidget(self.gantt) self.mainLayout.addLayout(waveLayout) self.mainLayout.addLayout(buttonLayoutAudio) self.setLayout(self.mainLayout) self.mediaPlayer.setVideoOutput(self.videoWidget.videoSurface()) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) def createSlider(self): self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setMinimum(0) self.positionSlider.setMaximum(self.duration) self.positionSlider.setTickInterval(1) self.positionSlider.sliderMoved.connect(self.setPosition) def createVideoButtons(self): verticalLine = QFrame() verticalLine.setFrameStyle(QFrame.VLine) verticalLine.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setShortcut(QKeySequence(Qt.Key_Space)) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.previousButton = QPushButton() self.previousButton.setIcon(self.style().standardIcon(QStyle.SP_MediaSeekBackward)) self.previousButton.setShortcut(QKeySequence(Qt.ALT + Qt.Key_A)) self.previousButton.clicked.connect(self.previousFrame) self.nextButton = QPushButton() self.nextButton.setIcon(self.style().standardIcon(QStyle.SP_MediaSeekForward)) self.nextButton.setShortcut(QKeySequence(Qt.ALT + Qt.Key_D)) self.nextButton.clicked.connect(self.nextFrame) #add label to slider about elapsed time self.label_tmp = '<b><FONT SIZE=3>{}</b>' self.timelabel = QLabel(self.label_tmp.format('Time: ' + str(self.duration))) self.label = QHBoxLayout() self.label.addWidget(self.timelabel) self.label.setAlignment(Qt.AlignRight) self.controlLayout = QHBoxLayout() self.controlLayout.addWidget(self.playButton) self.controlLayout.addWidget(self.previousButton) self.controlLayout.addWidget(self.nextButton) self.controlLayout.setAlignment(Qt.AlignLeft) self.newLayout = QHBoxLayout() self.newLayout.addLayout(self.controlLayout) self.newLayout.addLayout(self.label) videoLayout = QVBoxLayout() videoLayout.addWidget(self.videoWidget) videoLayout.addLayout(self.newLayout) return videoLayout def pauseMedia(self): self.mediaPlayer.pause() self.Pause() def previousFrame(self): global frameCounter if frameCounter > 0: frameCounter -= 2 pos = round(((frameCounter ) * (self.duration * 1000)) / self.message_count) self.mediaPlayer.setPosition(pos) def nextFrame(self): global frameCounter if frameCounter < self.message_count: pos = round(((frameCounter ) * (self.duration * 1000)) / self.message_count) self.mediaPlayer.setPosition(pos) # AUDIO PLAYER BUTTON FUNCTIONS def createAudio(self): #Define Audio annotations and gantt chart self.wave = vA.Waveform() audioGlobals.fig = self.wave self.wave.axes.get_xaxis().set_visible(False) self.wave.draw() self.wave.setFixedSize(1300, 175) self.audioChart = gA.Chart() audioGlobals.chartFig = self.audioChart self.audioChart.setFixedSize(1300, 90) #Audio layouts waveLayout = QVBoxLayout() waveLayout.addWidget(self.wave) waveLayout.addWidget(self.audioChart) return waveLayout def createAudioButtons(self): self.playButtonAudio = QPushButton() self.stopButtonAudio = QPushButton() self.playButtonAudio.clicked.connect(self.audioPlay) self.playButtonAudio.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) buttonLayoutAudio = QHBoxLayout() buttonLayoutAudio.addWidget(self.playButtonAudio) buttonLayoutAudio.setAlignment(Qt.AlignLeft) return buttonLayoutAudio #Play audio (whole signal or segment) def audioPlay(self): #GET CLICKS FROM WAVEFORM #Initialize connection-position ONCE if not audioGlobals.playerStarted: #10ms for changePosition -> Not Delaying self.player.positionChanged.connect(self.checkPositionToStop) self.player.setNotifyInterval(10) audioGlobals.playerStarted = True if audioGlobals.durationFlag in [0, 1]: self.end = audioGlobals.duration*1000 - 10 audioGlobals.endTimeToPlay = self.end else: self.end = audioGlobals.endTimeToPlay self.start = audioGlobals.startTimeToPlay self.player.setPosition(self.start) if self.playFlag: self.playFlag = False audioGlobals.playerStarted = True self.player.setPosition(self.time_) self.player.pause() self.playButtonAudio.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) else: self.playFlag = True self.playButtonAudio.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) self.player.play() #Stop audio playing def audioStop(self): self.player.stop() #Begin again segment self.start = audioGlobals.startTimeToPlay self.player.setPosition(self.start) #Check ms in audio to stop play def checkPositionToStop(self): self.time_ = self.player.position() if not video_player: audioGlobals.fig.drawNew(float(self.time_)/1000) audioGlobals.fig.draw() if self.time_ >= self.end: self.audioStop() self.player.setPosition(self.start) def videoPosition(self): self.videoTime = self.mediaPlayer.position() def openFile(self): global framerate global bagFile global rgbFileName global Topics global audio_player global video_player framerate = 0 fileName, _ = QFileDialog.getOpenFileName(self, "Open Bag", QDir.currentPath(),"(*.bag *.avi *.mp4 *.mkv *.mp3 *.wav)") # create a messsage box for get or load data info if fileName: name, extension = os.path.splitext(fileName) self.videobox = [] if extension == '.bag': bagFile = fileName try: bag = rosbag.Bag(fileName) Topics, self.duration = get_bag_metadata(bag) #Show window to select topics self.topic_window.show_topics(Topics) except: self.errorMessages(0) #Audio Handling if self.topic_window.temp_topics[0][1] != 'Choose Topic': try: audio_player = True audioGlobals.annotations = [] rosbagAudio.runMain(bag, str(fileName)) except: self.errorMessages(6) #DEFINE PLAYER-PLAYLIST #---------------------- self.source = QUrl.fromLocalFile(os.path.abspath(audioGlobals.wavFileName)) self.content = QMediaContent(self.source) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) self.wave.drawWave() self.wave.drawAnnotations() self.wave.draw() self.audioChart.drawChart() self.audioChart.draw() #RGB Handling if self.topic_window.temp_topics[2][1] != 'Choose Topic': try: video_player = True rgbFileName = fileName.replace(".bag","_RGB.avi") if not os.path.isfile(rgbFileName): self.message_count, compressed, framerate = rosbagVideo.buffer_bag_metadata(bag, self.topic_window.temp_topics[2][1]) #Get bag video metadata print('Getting rgb data from ROS', 'green') image_buffer = rosbagRGB.buffer_rgb_data(bag, self.topic_window.temp_topics[2][1], compressed) if not image_buffer: raise Exception(8) result = rosbagRGB.write_rgb_video(rgbFileName, image_buffer, framerate) if not result: raise Exception(2) self.duration, framerate, self.message_count = rosbagRGB.get_metadata(rgbFileName) # just fill time buffer in case that video exists start_time = None for topic, msg, t in bag.read_messages(topics=[self.topic_window.temp_topics[2][1]]): if not start_time: start_time = t.to_sec() time = t.to_sec() - start_time self.videobox.append(boundBox(time)) self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(os.path.abspath(rgbFileName)))) self.playButton.setEnabled(True) except Exception as e: print(e) self.errorMessages(e[0]) else: if extension in video_extensions: video_player = True self.duration, framerate, self.message_count = rosbagRGB.get_metadata(fileName) self.videobox = [boundBox(count/framerate) for count in xrange(int(self.message_count))] self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(os.path.abspath(fileName)))) self.playButton.setEnabled(True) rgbFileName = fileName try: audioGlobals.annotations = [] rosbagAudio.runMain(None, str(fileName)) #DEFINE PLAYER-PLAYLIST #---------------------- print audioGlobals.wavFileName self.source = QUrl.fromLocalFile(os.path.abspath(audioGlobals.wavFileName)) self.content = QMediaContent(self.source) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) self.wave.drawWave() self.wave.drawAnnotations() self.wave.draw() self.audioChart.drawChart() self.audioChart.draw() audio_player = True except: print "No audio found" mainWindow.repaint(player.videobox, framerate) mainWindow.setWindowTitle(fileName) self.setWindowTitle(fileName + ' -> Annotation') #Open CSV file def openCsv(self): global framerate global rgbFileName global bagFile global videoCSV global headlines self.box_buffer = [] if rgbFileName is not None: # OPEN VIDEO - AUDIO fileName,_ = QFileDialog.getOpenFileName(self, "Open Csv ", os.path.dirname(os.path.abspath(rgbFileName)),"(*.csv)") if fileName: videoCSV = fileName self.videobox = [boundBox(count) for count in xrange(int(self.message_count))] headlines, box_buff, box_action, features = rosbagRGB.buffer_video_csv(fileName) if not (box_buff): self.errorMessages(1) else: self.box_buffer = [list(elem) for elem in box_buff] #Frame counter initialize timestamp = None counter = 0 self.box_actionBuffer = [key for key in box_action] self.features = [key for key in features] for i, key in enumerate(self.box_buffer): if timestamp is not None: if timestamp != key[0]: counter += 1 self.videobox[counter].addBox(key[0], key[1], key[2:], self.box_actionBuffer[i], features[i]) timestamp = key[0] mainWindow.repaint(player.videobox, framerate) else: self.errorMessages(10) #Writes the boxes to csv def writeCSV(self): global headlines global rgbFileName global video_player if video_player: name, extension = os.path.splitext(rgbFileName) csvFileName = rgbFileName.replace(extension,"_video.csv") with open(csvFileName, 'w') as file: csv_writer = csv.writer(file, delimiter='\t') csv_writer.writerow(headlines) for i in xrange(0, len(self.videobox)): box = self.videobox[i] if len(box.box_id) > 0: for j in xrange(0, len(box.box_id)): master = [] append = master.append if box.box_id[j] != -1: append(box.timestamp) append(box.box_id[j]) for param in box.box_Param[j][::]: append(param) for param in box.features[j][::]: append(param) append(box.annotation[j]) csv_writer.writerow(master) else: csv_writer.writerow([box.timestamp]) else: csv_writer.writerow([box.timestamp]) print ("Video csv written at: ", csvFileName) def errorMessages(self, index): msgBox = QMessageBox() msgBox.setIcon(msgBox.Warning) if index == 0: msgBox.setWindowTitle("Open rosbag") msgBox.setText("Could not open rosbag") elif index == 1: msgBox.setWindowTitle("Open CSV") msgBox.setText("Could not process CSV file") elif index == 2: msgBox.setWindowTitle("Open rosbag") msgBox.setIcon(msgBox.Critical) msgBox.setText("Could not write video") elif index == 3: msgBox.setText("Error: Json file path error") elif index == 4: msgBox.setText("Not integer type") elif index == 5: msgBox.setText("Box id already given") elif index == 6: msgBox.setWindowTitle("Open rosbag") msgBox.setText("Incorrect Audio Topic") elif index == 8: msgBox.setWindowTitle("Open rosbag") msgBox.setText("Incorrect RGB Topic") elif index == 10: msgBox.setWindowTitle("Open CSV") msgBox.setText("You must select a rosbag first") msgBox.resize(100,40) msgBox.exec_() def play(self): global frameCounter global audio_player global video_player if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.videoPosition() self.mediaPlayer.pause() if audio_player: self.audioPlay() self.time_ = self.positionSlider else: self.time_ = self.mediaPlayer.position() if audio_player: self.player.setPosition(self.time_) self.end = audioGlobals.duration*1000 - 10 self.audioPlay() if video_player: self.mediaPlayer.play() # >> Get slider position for bound box posSlider = self.positionSlider.value() #self.tickLabel.setAlignment(posSlider) frameCounter = int(round((self.message_count * posSlider)/(self.duration * 1000))) def mediaStateChanged(self, state): if 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): time = "{0:.2f}".format(float(position)/1000) self.positionSlider.setValue(position) self.positionSlider.setToolTip(str(time) + ' sec') self.timelabel.setText(self.label_tmp.format('Time: ' + str(time) + '/ ' + str("{0:.2f}".format(self.duration)) + ' sec')) if audioGlobals.duration > 0 and self.mediaPlayer.state() != 0: audioGlobals.fig.drawNew(time) audioGlobals.fig.draw() def keyPressEvent(self,event): if event.key() == Qt.Key_Control: self.controlEnabled = True def keyReleaseEvent(self,event): if event.key() == Qt.Key_Control: self.controlEnabled = False def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): global frameCounter global audio_player global video_player frameCounter = int(round(self.message_count * position/(self.duration * 1000))) if frameCounter >= self.message_count: frameCounter = self.message_count - 1 if video_player: self.mediaPlayer.setPosition(position) if audio_player: self.player.setPosition(position) def closeEvent(self, event): self.writeCSV() eA.writeCSV() def parseJson(self): json_basicLabel = [] json_highLabel = [] json_annotationColors = [] json_eventColors = [] with open("labels.json") as json_file: json_data = json.load(json_file) for i in json_data['basiclabels'] : json_basicLabel.append(i) for i in json_data['highlevellabels']: json_highLabel.append(i) for i in json_data['annotationColors'] : json_annotationColors.append(i) for i in json_data['eventColors']: json_eventColors.append(i) return json_basicLabel,json_highLabel, json_annotationColors, json_eventColors
class VoiceWindow(QMainWindow): switch_window1 = QtCore.pyqtSignal() switch_window2 = QtCore.pyqtSignal() switch_openWindow = QtCore.pyqtSignal() # class constructor def __init__(self): # call QWidget constructor super().__init__() self.ui = Ui_VoiceWindow() self.ui.setupUi(self) self.mic = [] p1 = pyaudio.PyAudio() info = p1.get_host_api_info_by_index(0) numdevices = info.get('deviceCount') self.ui.DeviceBox.setDuplicatesEnabled(False) for i in range(0, numdevices): self.mic.append(p1.get_device_info_by_host_api_device_index(0, i).get('name')) self.ui.DeviceBox.addItem(p1.get_device_info_by_host_api_device_index(0, i).get('name')) p1.terminate() self.ID="" self.CHUNK = 512 self.FORMAT = pyaudio.paInt16 self.CHANNELS = 1 self.RATE = 16000 self.RECORD_SECONDS = 3 self.player = QMediaPlayer() self.count = 0 self.volume = 0 self.player.setVolume(100) self.ui.record1_cb.setEnabled(False) self.ui.record2_cb.setEnabled(False) self.ui.record3_cb.setEnabled(False) self.ui.volume_sl.setMaximum(100) self.ui.volume_sl.setPageStep(1) self.ui.volume_sl.setValue(100) self.ui.play_bt.setEnabled(False) self.ui.done_bt.setEnabled(False) # Disable Save in menubar until process done self.ui.save_act.setEnabled(False) self.ui.record_sl.setRange(0,0) self.ui.record_sl.sliderMoved.connect(self.set_position) self.player.positionChanged.connect(self.position_changed) self.player.durationChanged.connect(self.duration_changed) # create a timer self.timer = QTimer() # set timer timeout callback function self.timer.timeout.connect(self.recordHandler) self.timer.start(20) # set control_bt callback clicked function self.ui.record_bt.clicked.connect(lambda: self.setCount(5)) self.ui.volume_sl.valueChanged.connect(self.changeVolume) self.ui.play_bt.clicked.connect(self.playing) self.ui.previous_bt.clicked.connect(self.pushbutton_handler1) self.ui.done_bt.clicked.connect(self.pushbutton_handler2) # Open file menu and click New (Ctrl + N) self.ui.new_act.triggered.connect(self.setNew) # Open file menu and click Open (Ctrl + O) self.ui.open_act.triggered.connect(self.openUser) # Open file menu and click Save (Ctrl + S) self.ui.save_act.triggered.connect(self.saveUser) # Open file menu and click Exit (Ctrl + Esc) self.ui.exit_act.triggered.connect(self.closeApp) def pushbutton_handler1(self): self.switch_window1.emit() def pushbutton_handler2(self): with open('data/ID.txt', 'w') as f: f.write("") self.switch_window2.emit() def position_changed(self, position): self.ui.record_sl.setValue(position) def duration_changed(self, duration): self.ui.record_sl.setRange(0, duration) def set_position(self, position): self.player.setPosition(position) def setCount(self, item): self.count = item self.data_encode = [] self.ui.record1_cb.setChecked(False) self.ui.record2_cb.setChecked(False) self.ui.record3_cb.setChecked(False) def setCountPlay(self, item): self.countPlay = item def changeVolume(self, value): self.player.setVolume(value) def playing(self): sound1 = AudioSegment.from_wav(f"data/{self.ID}/voice/1.wav") sound2 = AudioSegment.from_wav(f"data/{self.ID}/voice/2.wav") sound3 = AudioSegment.from_wav(f"data/{self.ID}/voice/3.wav") combined_sounds = sound1 + sound2 + sound3 combined_sounds.export(f"data/{self.ID}/voice/joinedFile.wav", format="wav") filename = os.path.abspath(f"data/{self.ID}/voice/joinedFile.wav") self.player.setMedia(QMediaContent(QUrl.fromLocalFile(filename))) self.player.play() # handle the record def recordHandler(self): mic1 = [] p1 = pyaudio.PyAudio() info = p1.get_host_api_info_by_index(0) numdevices = info.get('deviceCount') self.ui.DeviceBox.setDuplicatesEnabled(False) for i in range(0, numdevices): mic1.append(p1.get_device_info_by_host_api_device_index(0, i).get('name')) if mic1 != self.mic: print(True) self.ui.DeviceBox.clear() self.ui.DeviceBox.addItems(mic1) self.mic = mic1 p1.terminate() print(self.ui.DeviceBox.currentIndex()) with open(f'data/ID.txt', 'r') as f: self.ID = f.read() # If process done, save in menubar will be enabled if os.path.exists(f'data/{self.ID}/voice/3.wav'): self.ui.save_act.setEnabled(True) else: self.ui.save_act.setEnabled(False) # else it still be disabled # Check 3 wav files exist or not if os.path.exists(f'data/{self.ID}/voice/1.wav'): self.ui.record1_cb.setChecked(True) else: self.ui.record1_cb.setChecked(False) if os.path.exists(f'data/{self.ID}/voice/2.wav'): self.ui.record2_cb.setChecked(True) else: self.ui.record2_cb.setChecked(False) if os.path.exists(f'data/{self.ID}/voice/3.wav'): self.ui.record3_cb.setChecked(True) self.ui.play_bt.setEnabled(True) self.ui.done_bt.setEnabled(True) else: self.ui.record3_cb.setChecked(False) self.ui.play_bt.setEnabled(False) self.ui.done_bt.setEnabled(False) # Record voice if (self.count>0) & (self.count<=4): p = pyaudio.PyAudio() stream = p.open(format=self.FORMAT, channels=self.CHANNELS, rate=self.RATE, input=True, frames_per_buffer=self.CHUNK, input_device_index=self.ui.DeviceBox.currentIndex()) self.ui.status_lb.setText(f"Status: * recording {5-self.count}") # 1 record turn will not be used if (self.count!= 4): wave_output_filename = f"data/{self.ID}/voice/{4-self.count}.wav" frames = [] # Check the record check box if self.count == 1: self.ui.record3_cb.setChecked(True) self.ui.play_bt.setEnabled(True) self.ui.done_bt.setEnabled(True) if self.count == 2: self.ui.record2_cb.setChecked(True) if self.count == 3: self.ui.record1_cb.setChecked(True) for i in range(0, int(self.RATE / self.CHUNK * self.RECORD_SECONDS)): data = stream.read(self.CHUNK) frames.append(data) stream.stop_stream() stream.close() p.terminate() buff = BytesIO() wf = wave.open(wave_output_filename, 'wb') wf.setnchannels(self.CHANNELS) wf.setsampwidth(p.get_sample_size(self.FORMAT)) wf.setframerate(self.RATE) wf.writeframes(b''.join(frames)) wf.close() encoded_data = resemblyzer.preprocess_wav(wave_output_filename) self.data_encode.append(encoded_data) # Save pickle file with open(f'data/{self.ID}/voice/{self.ID}_encoded_wav.pickle', 'wb') as handle: pickle.dump(self.data_encode, handle, protocol=pickle.HIGHEST_PROTOCOL) self.count -= 1 if self.count == 0: # Status of not recording self.ui.status_lb.setText("Status: Click record") if self.count == 5: # Status of begin recording self.ui.status_lb.setText(f"Status: * Ready") self.count -= 1 # Function of menubar def setNew(self): # Pop up message box when exit. 2 option yes or no reply = QMessageBox.question(self,'Message','Press Yes to create New user.',QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes) if reply == QMessageBox.Yes: # When face data and voice data have not done, # click yes will lead to remove current ID folder with open('data/ID.txt', 'r') as f: ID = f.read() if not os.path.exists(f'data/{ID}/voice/3.wav'): shutil.rmtree(f'data/{ID}', ignore_errors=True) # Clear temporary ID with open('data/ID.txt', 'w') as f: f.write("") # Go to first window self.switch_window2.emit() if reply == QMessageBox.No: return def openUser(self): # Go to open window self.switch_openWindow.emit() def saveUser(self): # Pop up message box when exit. 2 option yes or no reply = QMessageBox.question(self,'Message','Press Yes to save user.',QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes) if reply == QMessageBox.Yes: with open('data/ID.txt', 'r') as f: ID = f.read() # Clear temporary ID with open('data/ID.txt', 'w') as f: f.write("") self.switch_window2.emit() if reply == QMessageBox.No: return def closeApp(self): reply = QMessageBox.question(self,'Message','Press Yes to Close.',QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes) if reply == QMessageBox.Yes: # When face data and voice data have not done, # click yes will lead to remove current ID folder with open('data/ID.txt', 'r') as f: ID = f.read() if ID != "": if not os.path.exists(f'data/{ID}/voice/3.wav'): print(ID) shutil.rmtree(f'data/{ID}', ignore_errors=True) sys.exit() if reply == QMessageBox.No: return
class AudioPlayer(QObject): songPositionChanged = pyqtSignal(int) songDurationChanged = pyqtSignal(int) stateChanged = pyqtSignal(int) playlistChanged = pyqtSignal(QMediaPlaylist, int) currentSongChanged = pyqtSignal(str, str, bytes) currentSelectionChanged = pyqtSignal(UUID, int) customPlaylistCreated = pyqtSignal(UUID, str) libraryPlaylistCreated = pyqtSignal(UUID) addedToLibraryPlaylist = pyqtSignal(UUID, list) addedToCustomPlaylist = pyqtSignal(UUID, list) updatedLibraryPlaylist = pyqtSignal(UUID, list) playlistRemoved = pyqtSignal(UUID) def __init__(self, volumeLevel=40, playbackMode=QMediaPlaylist.Sequential, parent=None): super(AudioPlayer, self).__init__(parent) self.__player = QMediaPlayer() self.__player.setVolume(volumeLevel) self.__player.currentMediaChanged.connect(self._onMediaChanged) self.__player.stateChanged.connect( lambda state: self.stateChanged.emit(int(state))) self.__player.positionChanged.connect( lambda x: self.songPositionChanged.emit(x)) self.__player.durationChanged.connect( lambda x: self.songDurationChanged.emit(x)) self.__playlistManager = PlaylistManger() self.__playlistManager.customPlaylistCreated.connect( lambda uuid, name: self.customPlaylistCreated.emit(uuid, name)) self.__playlistManager.libraryPlaylistCreated.connect( lambda p: self.libraryPlaylistCreated.emit(p)) self.__playlistManager.currentPlaylistChanged.connect( self._onChangedPlaylist) self.__playlistManager.currentPlaylistChanged.connect( lambda p, i: self.playlistChanged.emit(p, i)) self.__playlistManager.playlistRemoved.connect( lambda uuid: self.playlistRemoved.emit(uuid)) self.__playlistManager.addedToLibraryPlaylist.connect( lambda uuid, l: self.addedToLibraryPlaylist.emit(uuid, l)) self.__playlistManager.addedToCustomPlaylist.connect( lambda uuid, l: self.addedToCustomPlaylist.emit(uuid, l)) self.__playlistManager.updatedLibraryPlaylist.connect( lambda uuid, l: self.updatedLibraryPlaylist.emit(uuid, l)) def createCustomPlaylist(self, name=None, urls=None): self.__playlistManager.createCustomPlaylist(name, urls) def createLibraryPlaylist(self, urls=None): self.__playlistManager.createLibraryPlaylist(urls) def addToLibraryPlaylist(self, url=None): self.__playlistManager.addToLibraryPlaylist(url) def updateLibraryPlaylist(self, url=None): self.__playlistManager.updateLibraryPlaylist(url) def renamePlaylist(self, uuid, newName): self.__playlistManager.renamePlaylist(uuid, newName) def addSongsToCustomPlaylist(self, uuid, urls=[]): self.__playlistManager.addSongsToCustomPlaylist(uuid, urls) def removeSong(self, uuid, row): self.__playlistManager.removeSong(uuid, row) def setPlaylist(self, uuid, index=0): if (self.__player.playlist() and self.__playlistManager.isCurrentPlaylist(uuid)): if index == self.__player.playlist().currentIndex(): if self.__player.state() == QMediaPlayer.PlayingState: self.__player.pause() else: self.__player.play() else: self.__player.playlist().setCurrentIndex(index) else: self.__playlistManager.setPlaylist(uuid, index) def hasLibraryPlaylist(self): return self.__playlistManager.hasLibraryPlaylist() def removePlaylist(self, uuid): self.__playlistManager.removePlaylist(uuid) def getCurrentPlaylist(self): self.__playlistManager.getCurrentPlaylist() def getCurrentQMediaPlaylist(self): self.__player.playlist() def isPlayerAvailable(self): return self.__player.isAvailable() def getDuration(self): return self.__player.duration() def getPlayer(self): return self.__player def getState(self): return self.__player.state() def play(self): if self.__player.playlist(): self.__player.play() def pause(self): if self.__player.playlist(): self.__player.pause() def stop(self): if self.__player.playlist(): self.__player.stop() def previousEnhanced(self, sameSongMillis): if self.__player.position() <= sameSongMillis: self.previous() else: self.__player.setPosition(0) def previous(self): if self.__player.playlist(): self.__player.playlist().previous() def next(self): if self.__player.playlist(): self.__player.playlist().next() def setVolume(self, value): self.__player.setVolume(value) def setPosition(self, milliseconds): self.__player.setPosition(milliseconds) def playlistCurrentIndex(self): if self.__player.playlist(): return self.__player.playlist().currentIndex() def setCurrentPlaylistIndex(self, index): if self.__player.playlist(): self.__player.playlist().setCurrentIndex(index) def _onChangedPlaylist(self, playlist, index, playIt=False): self.__player.setPlaylist(playlist) if playlist: playlist.setCurrentIndex(index) if playIt: self.play() def _onMediaChanged(self, media): if media.isNull() and self.__player.playlist(): self.__player.playlist().setCurrentIndex(0) media = self.__player.playlist().media(0) if media.isNull(): return title, artist, cover = self.__playlistManager.getBasicSongInfo(media) self.currentSongChanged.emit(title, artist, cover) uuid = self.__playlistManager.getCurrentPlaylistUuid() index = self.__playlistManager.getCurrentSongIndex() self.currentSelectionChanged.emit(uuid, index) # def saveSettings(self): # # settings = QSettings(QSettings.IniFormat, QSettings.UserScope, # # QCoreApplication.organizationName(), # # QCoreApplication.applicationName()) # # settings.beginGroup("music_player") # # # if self.__playlistManager.getLibraryPlaylist(): # # # libraryDirectories = self.__playlistManager.getLibraryPlaylist().getDirectories() # # # settings.beginWriteArray('library_playlist', # # # len(libraryDirectories)) # # # for index, value in enumerate(libraryDirectories): # # # settings.setArrayIndex(index) # # # settings.setValue("url", value) # # # settings.endArray() # # customPlaylists = self.__playlistManager.getCustomPlaylists() # # settings.beginWriteArray('custom_playlists', # # len(customPlaylists)) # # for index, value in enumerate(customPlaylists): # # settings.setArrayIndex(index) # # playlistName = settings.value('name', value.getName()) # # playlistUrls = value.getAddedSongUrls() # # settings.beginWriteArray(playlistName, # # len(playlistUrls)) # # for i, v in enumerate(playlistUrls): # # settings.setArrayIndex(i) # # settings.setValue("url", v) # # settings.endArray() # # settings.endArray() # # settings.endGroup() # # if self.__playlistManager.getLibraryPlaylist(): # # libraryDirectories = self.__playlistManager.getLibraryPlaylist().getDirectories() # # settings.beginWriteArray('library_playlist', # # len(libraryDirectories)) # # for index, value in enumerate(libraryDirectories): # # settings.setArrayIndex(index) # # settings.setValue("url", value) # # settings.endArray() # customPlaylists = self.__playlistManager.getCustomPlaylists() # for playlist in customPlaylists: # playlistName = playlist.getName() # for url in playlist: # pass # def restoreSettings(self): # settings = QSettings(QSettings.IniFormat, QSettings.UserScope, # QCoreApplication.organizationName(), # QCoreApplication.applicationName()) # settings.beginGroup("music_player") # # size = settings.beginReadArray('library_playlist') # # libraryDirectories = [] # # for i in range(size): # # settings.setArrayIndex(i) # # libraryDirectories.append(settings.value("url")) # # settings.endArray() # customPlaylists = {} # size = settings.beginReadArray('custom_playlists') # for i in range(size): # urls = [] # settings.setArrayIndex(i) # playlistName = settings.value('name') # print(playlistName) # size2 = settings.beginReadArray(playlistName) # for j in range(size2): # settings.setArrayIndex(j) # url = settings.value("url") # urls.append(url) # settings.endArray() # customPlaylists[playlistName] = urls # settings.endArray() # settings.endGroup() # print('-------') # print(customPlaylists) # settings = QSettings(QCoreApplication.organizationName(), # QCoreApplication.applicationName()) # settings.beginGroup("music_player") # size = settings.beginReadArray('library_playlist') # if not size == 0: # for i in range(0, size): # settings.setArrayIndex(i) # url = settings.value("url") # settings.endArray() # if url: # from audio.playlist_models import DirectoryPlaylist # playlist = DirectoryPlaylist() # playlist.add_directory(url) # self.addAndSetPlaylist(playlist, 2) # settings.endGroup() pass
class App(QMainWindow): def __init__(self, song): super().__init__() self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.title = 'PyTunes' self.left = 300 self.top = 300 self.width = 300 self.height = 150 self.color = 0 # 0- toggle to dark 1- toggle to light self.userAction = -1 # 0- stopped, 1- playing 2-paused self.initUI() self.song = song def initUI(self): # Add file menu self.addControls() self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.toggleColors() self.show() def addControls(self): wid = QWidget(self) self.setCentralWidget(wid) # Add song controls volumeslider = QSlider(Qt.Horizontal, self) volumeslider.setFocusPolicy(Qt.NoFocus) volumeslider.valueChanged[int].connect(self.changeVolume) volumeslider.setValue(100) playBtn = QPushButton('Play') # play button pauseBtn = QPushButton('Pause') # pause button # Add button layouts controlArea = QVBoxLayout() # centralWidget controls = QHBoxLayout() playlistCtrlLayout = QHBoxLayout() # Add buttons to song controls layout controls.addWidget(playBtn) controls.addWidget(pauseBtn) # Add buttons to playlist controls layout # Add to vertical layout controlArea.addWidget(volumeslider) controlArea.addLayout(controls) controlArea.addLayout(playlistCtrlLayout) wid.setLayout(controlArea) # Connect each signal to their appropriate function playBtn.clicked.connect(self.playhandler) pauseBtn.clicked.connect(self.pausehandler) self.statusBar() self.playlist.currentMediaChanged.connect(self.songChanged) def openFile(self): song = QFileDialog.getOpenFileName(self, "Open Song", "~", "Sound Files (*.mp3 *.ogg *.wav *.m4a)") print(song) if song[0] != '': url = QUrl.fromLocalFile(song[0]) if self.playlist.mediaCount() == 0: self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.player.play() self.userAction = 1 else: self.playlist.addMedia(QMediaContent(url)) def addFiles(self): if self.playlist.mediaCount() != 0: self.folderIterator() else: self.folderIterator() self.player.setPlaylist(self.playlist) self.player.playlist().setCurrentIndex(0) self.player.play() self.userAction = 1 def folderIterator(self): folderChosen = QFileDialog.getExistingDirectory(self, 'Open Music Folder', '~') if folderChosen != None: it = QDirIterator(folderChosen) it.next() while it.hasNext(): if it.fileInfo().isDir() == False and it.filePath() != '.': fInfo = it.fileInfo() if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'): self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) it.next() if it.fileInfo().isDir() == False and it.filePath() != '.': fInfo = it.fileInfo() if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'): self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) def playhandler(self): if self.playlist.mediaCount() == 0: self.openFile() elif self.playlist.mediaCount() != 0: self.player.play() self.userAction = 1 def pausehandler(self): self.userAction = 2 self.player.pause() def changeVolume(self, value): self.player.setVolume(value) def songChanged(self, media): if not media.isNull(): url = media.canonicalUrl() self.statusBar().showMessage(url.fileName()) def toggleColors(self): """ Fusion dark palette from https://gist.github.com/QuantumCD/6245215. Modified by me and J.J. """ app.setStyle("Fusion") palette = QPalette() if self.color == 0: 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(235, 101, 54)) palette.setColor(QPalette.Highlight, QColor(235, 101, 54)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) self.color = 1 elif self.color == 1: palette.setColor(QPalette.Window, Qt.white) palette.setColor(QPalette.WindowText, Qt.black) palette.setColor(QPalette.Base, QColor(240, 240, 240)) palette.setColor(QPalette.AlternateBase, Qt.white) palette.setColor(QPalette.ToolTipBase, Qt.white) palette.setColor(QPalette.ToolTipText, Qt.white) palette.setColor(QPalette.Text, Qt.black) palette.setColor(QPalette.Button, Qt.white) palette.setColor(QPalette.ButtonText, Qt.black) palette.setColor(QPalette.BrightText, Qt.red) palette.setColor(QPalette.Link, QColor(66, 155, 248)) palette.setColor(QPalette.Highlight, QColor(66, 155, 248)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) self.color = 0
class Window(QtWidgets.QDialog): def __init__(self): super().__init__() self.setGeometry(50, 50, 300, 400) self.setWindowTitle("Rolev Player") # LIBRARY ROOT DIR FOLDER self.search_label = QtWidgets.QLabel("Select a music folder:", self) self.search_label.setGeometry(10, 5, 205, 10) self.btn_root_folder = QtWidgets.QPushButton("Browse", self) self.btn_root_folder.setGeometry(215, 20, 75, 25) # the text field of the currently selected root directory self.dir_text_field = QtWidgets.QLineEdit(self) self.dir_text_field.setGeometry(10, 20, 200, 25) self.btn_root_folder.clicked.connect(self.on_btn_root_folder) # CURRENT MEDIA LABEL self.current_media_label = QtWidgets.QLabel("Now Playing: ", self) self.current_media_label.setGeometry(10, 260, 250, 15) # CURRENT ALBUM COVER self.current_album_cover = QtWidgets.QLabel("Image", self) self.current_album_cover.setGeometry(10, 180, 75, 75) self.current_album_cover.setScaledContents(True) # ARTIST DROP BOX self.artist_select_label = QtWidgets.QLabel("Artist", self) self.artist_select_label.setGeometry(10, 50, 250, 25) self.artist_select = QtWidgets.QComboBox(self) self.artist_select.setGeometry(10, 70, 250, 25) self.artist_select.activated[str].connect(self.on_artist_selection) # ALBUMS DROP BOX self.album_select_label = QtWidgets.QLabel("Albums", self) self.album_select_label.setGeometry(10, 90, 250, 25) self.album_select = QtWidgets.QComboBox(self) self.album_select.setGeometry(10, 110, 250, 25) self.album_select.activated[str].connect(self.on_album_selection) # SONGS DROP BOX self.song_select_label = QtWidgets.QLabel("Current Playlist", self) self.song_select_label.setGeometry(10, 130, 250, 25) self.song_select = QtWidgets.QComboBox(self) self.song_select.setGeometry(10, 150, 250, 25) self.song_select.activated[str].connect(self.on_song_selection) # PLAYLIST self.playlist = QMediaPlaylist() self.playlist.currentIndexChanged.connect(self.meta_data_changed) # MEDIA PLAYER self.player = QMediaPlayer() self.player.setPlaylist(self.playlist) self.player.playlist().setPlaybackMode(QMediaPlaylist.Loop) self.player.setVolume(50) self.player.durationChanged.connect(self.on_dur_change) self.player.positionChanged.connect(self.on_pos_change) # VOLUME SLIDER self.slider_volume_label = QtWidgets.QLabel("Volume", self) self.slider_volume_label.setGeometry(10, 345, 50, 25) self.slider_volume = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) self.slider_volume.setGeometry(60, 350, 130, 20) self.slider_volume.setRange(0, 100) self.slider_volume.setValue(50) self.slider_volume.valueChanged.connect(self.volume_change) # PROGRESS SLIDER self.slider_progress_label = QtWidgets.QLabel("Progress", self) self.slider_progress_label.setGeometry(10, 315, 50, 25) self.slider_progress = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) self.slider_progress.setGeometry(60, 320, 130, 20) self.slider_progress.sliderMoved.connect(self.progress_change) # LYRICS SEARCH self.btn_lyrics = QtWidgets.QPushButton("Search\n Lyrics", self) self.btn_lyrics.setGeometry(220, 310, 70, 80) self.btn_lyrics.clicked.connect(self.on_lyrics) # ALBUM INFO SEARCH self.btn_album_info = QtWidgets.QPushButton( "Search\nAlbum\nInfo", self) self.btn_album_info.setGeometry(105, 180, 75, 75) self.btn_album_info.clicked.connect(self.on_album_info) # ARTIST INFO SEARCH self.btn_artist_info = QtWidgets.QPushButton( "Search\nArtist\nInfo", self) self.btn_artist_info.setGeometry(200, 180, 75, 75) self.btn_artist_info.clicked.connect(self.on_artist_info) # PREV SONG BUTTON self.btn_prev = QtWidgets.QPushButton("Prev", self) self.btn_prev.setGeometry(10, 280, 75, 25) self.btn_prev.clicked.connect(self.on_btn_prev) # NEXT SONG BUTTON self.btn_next = QtWidgets.QPushButton("Next", self) self.btn_next.setGeometry(200, 280, 75, 25) self.btn_next.clicked.connect(self.on_btn_next) # PLAY/PAUSE BUTTON self.btn_play_pause = QtWidgets.QPushButton("Play", self) self.btn_play_pause.setGeometry(105, 280, 75, 30) self.btn_play_pause.clicked.connect(self.on_btn_play_pause) self.show() def on_btn_root_folder(self): self.root_dir = QtWidgets.QFileDialog().getExistingDirectory() self.dir_text_field.setText(self.root_dir) self.library = LibraryLoader.load_music_from_dir( self.dir_text_field.text()) self.artist_select.clear() self.album_select.clear() self.song_select.clear() self.playlist.clear() self.btn_play_pause.setText("Play") self.artist_select.addItem("All Artists") for artist in self.library: self.artist_select.addItem(artist) for album in self.library[artist]: self.album_select.addItem(album) self.load_all_songs() def on_artist_selection(self): current_artist = self.artist_select.currentText() self.album_select.clear() self.song_select.clear() self.playlist.clear() self.btn_play_pause.setText("Play") self.album_select.addItem("All Albums") if current_artist == "All Artists": for artist in self.library: for album in self.library[artist]: self.album_select.addItem(album) self.load_all_songs() else: for album in self.library[current_artist]: self.album_select.addItem(album) self.load_all_from_artist(current_artist) def load_all_songs(self): for artist in self.library: for album in self.library[artist]: for song in self.library[artist][album]: self.song_select.addItem(song[0]) self.playlist.addMedia( QMediaContent(QtCore.QUrl.fromLocalFile(song[1]))) def load_all_from_artist(self, artist): for album in self.library[artist]: for song in self.library[artist][album]: self.song_select.addItem(song[0]) self.playlist.addMedia( QMediaContent(QtCore.QUrl.fromLocalFile(song[1]))) def on_album_selection(self): current_artist = self.artist_select.currentText() current_album = self.album_select.currentText() self.song_select.clear() self.playlist.clear() self.btn_play_pause.setText("Play") if current_album == "All Albums" and current_artist == "All Artists": self.load_all_songs() elif current_album == "All Albums": self.load_all_from_artist(current_artist) elif current_artist == "All Artists": for artist in self.library: for album in self.library[artist]: if album == self.album_select.currentText(): for song in self.library[artist][album]: self.song_select.addItem(song[0]) self.playlist.addMedia( QMediaContent( QtCore.QUrl.fromLocalFile(song[1]))) else: for song in self.library[current_artist][current_album]: self.song_select.addItem(song[0]) self.playlist.addMedia( QMediaContent(QtCore.QUrl.fromLocalFile(song[1]))) def on_song_selection(self): index = self.song_select.currentIndex() self.playlist.setCurrentIndex(index) # GETTING THE CURRENT SONG METADATA # Returns a SONG OBJECT and not the current song title # For the title of the currently playing song use get_current_title() def get_current_song(self): curr_url = self.playlist.currentMedia().canonicalUrl().toString()[8:] if curr_url: return LibraryLoader.create_song(curr_url) def get_current_artist(self): if self.get_current_song() is not None: return self.get_current_song().artist def get_current_album(self): if self.get_current_song() is not None: return self.get_current_song().album def get_current_path(self): if self.get_current_song() is not None: return self.get_current_song().path def get_current_album_path(self): if self.get_current_path() is not None: return self.get_current_path().rsplit("/", 1)[0] def get_current_title(self): if self.get_current_song() is not None: return self.get_current_song().name def on_lyrics(self): if self.get_current_song() is not None: curr_artist = self.get_current_artist() curr_song = self.get_current_title() found_lyrics = RequestLyrics.search_song_lyrics( curr_artist, curr_song) choice = QtWidgets.QMessageBox.question( self, "Lyrics", found_lyrics[0], QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if choice == QtWidgets.QMessageBox.Yes: webbrowser.open(found_lyrics[1]) else: QtWidgets.QMessageBox.information( self, "Lyrics", "No lyrics found or no media is loaded!") def on_album_info(self): album = self.get_current_album() artist = self.get_current_artist() if (album is None) or (artist is None): print("Please, load a song first!") else: artist_info, album_info = AlbumArtwork.album_artist_info( artist, album) if album_info is not None: webbrowser.open(album_info) def on_artist_info(self): album = self.get_current_album() artist = self.get_current_artist() if (album is None) or (artist is None): print("Please, load a song first!") else: artist_info, album_info = AlbumArtwork.album_artist_info( artist, album) if artist_info is not None: webbrowser.open(artist_info) def on_btn_play_pause(self): if self.player.state() in (0, 2): self.player.play() if self.player.state() == 1: self.btn_play_pause.setText("Pause") else: self.player.pause() self.btn_play_pause.setText("Play") def on_btn_next(self): self.player.playlist().next() def on_btn_prev(self): self.player.playlist().previous() def on_dur_change(self, length): self.slider_progress.setMaximum(length) def on_pos_change(self, position): self.slider_progress.setValue(position) def volume_change(self): volume = self.slider_volume.value() self.player.setVolume(volume) def progress_change(self): position = self.slider_progress.value() self.player.setPosition(position) def meta_data_changed(self): now_playing = self.get_current_title() self.current_media_label.setText("Now Playing: " + now_playing) # Updating the currently playing album cover curr_album_path = self.get_current_album_path() curr_album = self.get_current_album() curr_artist = self.get_current_artist() cover_url = AlbumArtwork.album_cover( curr_album_path, curr_artist, curr_album) self.current_album_cover.setPixmap(QPixmap(cover_url)) Scrobbler.scrobble(self.get_current_artist(), self.get_current_title())
class PlaybackPanel(SpecialLabel): desktop_lyric_state_changed_signal = pyqtSignal(bool) playmode_changed_signal = pyqtSignal(int, int) media_player_notify_signal = pyqtSignal(int) muted_changed_signal = pyqtSignal(int) mark_favorite_completed_signal = pyqtSignal() current_media_changed_signal = pyqtSignal() music_ended_signal = pyqtSignal() update_window_lyric_signal = pyqtSignal(str, str) show_artist_info_signal = pyqtSignal(str) dont_hide_main_window_signal = pyqtSignal() def __init__(self, parent=None): super(PlaybackPanel, self).__init__(parent) self.initial_mediaplayer() self.create_actions() self.setup_ui() self.create_connections() self.initial_params() def create_connections(self): self.artistHeadLabel.clicked.connect(self.show_artist_info) self.desktopLyric.hide_desktop_lyric_signal.connect(self.desktop_lyric_closed) self.seekSlider.valueChanged.connect(self.slider_value_changed) self.seekSlider.sliderPressed.connect(self.slider_pressed) self.seekSlider.sliderReleased.connect(self.seek) self.mediaPlayer.positionChanged.connect(self.tick) self.mediaPlayer.mutedChanged.connect(self.muted_changed_signal.emit) self.mediaPlayer.stateChanged.connect(self.state_changed) self.mediaPlayer.durationChanged.connect(self.duration_changed) self.mediaPlayer.mediaStatusChanged.connect(self.media_status_changed) self.mediaPlayer.currentMediaChanged.connect(self.current_media_changed) def initial_mediaplayer(self): self.mediaPlayer = QMediaPlayer() self.mediaPlayer.setNotifyInterval(500) self.set_volume(globalSettings.Volume) def initial_params(self): self.playlist = None self.artistName = "Zheng-Yejian" self.clickPlayFlag = False # 用来标志一首歌是否是主动点击选中的 self.timerFlag = False self.timeStart = 0 self.timeSpan = 0 self.sourcePath = "" self.errorType = Configures.NoError self.currentSourceRow = -1 self.nearPlayedSongs = [] self.downloadDir = globalSettings.DownloadfilesPath self.songinfosManager = SonginfosManager() self.totalTime = Configures.ZeroTime self.playmode = Configures.PlaymodeRandom # 播放模式指示器 playlistTemp = Playlist() playlistTemp.fill_list(Configures.PlaylistFavorite) self.lovedSongs = playlistTemp.get_titles() def set_playlist(self, playlist): self.playlist = playlist self.currentSourceRow = self.playlist.get_current_row() def create_actions(self): self.nextAction = QAction(QIcon(IconsHub.ControlNext), "下一首", self, enabled=True, triggered=self.next_song) self.playAction = QAction(QIcon(IconsHub.ControlPlay), "播放/暂停", self, enabled=True, triggered=self.play_music) self.previousAction = QAction( QIcon(IconsHub.ControlPrevious), "上一首", self, enabled=True, triggered=self.previous_song ) self.stopAction = QAction( QIcon(IconsHub.ControlStop), "停止", self, enabled=True, triggered=self.stop_music_but_timing ) def get_play_button_action(self): return self.playAction def get_previous_button_action(self): return self.previousAction def get_next_button_action(self): return self.nextAction def get_stop_button_action(self): return self.stopAction def set_download_dir(self, dir): self.downloadDir = dir def get_loved_songs(self): return self.lovedSongs def get_songinfos_manager(self): return self.songinfosManager def setup_ui(self): self.setFixedHeight(50) # 桌面歌词标签 self.desktopLyric = desktop_lyric.DesktopLyric() self.desktopLyric.set_color(globalSettings.DesktoplyricColors) # 3个标签 self.artistHeadLabel = LabelButton() self.artistHeadLabel.setToolTip(self.tr("查看歌手信息")) self.artistHeadLabel.setFixedSize(QSize(42, 42)) self.artistHeadLabel.setScaledContents(True) self.artistHeadLabel.setPixmap(QPixmap(IconsHub.Anonymous)) self.musicTitleLabel = NewLabel() self.musicTitleLabel.setObjectName("musicTitleLabel") self.musicTitleLabel.setFixedSize(QSize(370, 20)) self.musicTitleLabel.setText("Zheng-Yejian._.XYPLAYER") self.timeLabel = QLabel("00:00/00:00") self.timeLabel.setObjectName("timeLabel") self.timeLabel.setFixedHeight(20) self.timeLabel.setAlignment(Qt.AlignRight and Qt.AlignVCenter) # 五个基本按键 self.playmodeButton = QToolButton(clicked=self.change_playmode) self.playmodeButton.setFocusPolicy(Qt.NoFocus) self.playmodeButton.setIcon(QIcon(IconsHub.PlaymodeRandom)) self.playmodeButton.setIconSize(QSize(25, 25)) self.playmodeButton.setToolTip("随机播放") self.favoriteButton = QToolButton(clicked=self.mark_as_favorite) self.favoriteButton.setFocusPolicy(Qt.NoFocus) self.favoriteButton.setToolTip("收藏") self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setIconSize(QSize(20, 20)) self.previousButton = QToolButton() self.previousButton.setFocusPolicy(Qt.NoFocus) self.previousButton.setIconSize(QSize(40, 40)) self.previousButton.setShortcut(QKeySequence("Ctrl + Left")) self.previousButton.setDefaultAction(self.previousAction) self.playButton = QToolButton() self.playButton.setFocusPolicy(Qt.NoFocus) self.playButton.setIconSize(QSize(40, 40)) self.playButton.setShortcut(QKeySequence("Ctrl + Down")) self.playButton.setDefaultAction(self.playAction) self.nextButton = QToolButton() self.nextButton.setFocusPolicy(Qt.NoFocus) self.nextButton.setIconSize(QSize(40, 40)) self.nextButton.setFocusPolicy(Qt.NoFocus) self.nextButton.setShortcut(QKeySequence("Ctrl + Right")) self.nextButton.setDefaultAction(self.nextAction) self.desktopLyricButton = QToolButton(clicked=self.show_desktop_lyric) self.desktopLyricButton.setToolTip(self.tr("桌面歌词")) self.desktopLyricButton.setFocusPolicy(Qt.NoFocus) self.desktopLyricButton.setIcon(QIcon(IconsHub.DesktopLyric)) self.desktopLyricButton.setIconSize(QSize(25, 25)) self.seekSlider = QSlider(Qt.Horizontal) self.seekSlider.setObjectName("seekSlider") self.seekSlider.setFixedHeight(20) self.seekSlider.setFocusPolicy(Qt.NoFocus) self.seekSlider.setRange(0, 0) hbox1 = QHBoxLayout() hbox1.addWidget(self.favoriteButton) hbox1.addWidget(self.musicTitleLabel) hbox1.addStretch() hbox1.addWidget(self.timeLabel) vbox1 = QVBoxLayout() vbox1.addLayout(hbox1) vbox1.setSpacing(5) vbox1.addWidget(self.seekSlider) mainLayout = QHBoxLayout(self) mainLayout.setContentsMargins(2, 0, 0, 0) mainLayout.addWidget(self.artistHeadLabel) mainLayout.addWidget(self.previousButton) mainLayout.addWidget(self.playButton) mainLayout.addWidget(self.nextButton) mainLayout.addLayout(vbox1) mainLayout.addWidget(self.playmodeButton) mainLayout.addWidget(self.desktopLyricButton) def show_desktop_lyric(self): if self.desktopLyric.isHidden(): beToOff = True self.desktopLyric.show() self.desktopLyric.original_place() else: beToOff = False self.desktopLyric.hide() self.desktop_lyric_state_changed_signal.emit(beToOff) def desktop_lyric_closed(self): self.desktop_lyric_state_changed_signal.emit(False) def change_playmode(self): oldPlaymode = self.playmode if self.playmode == Configures.PlaymodeRandom: self.set_new_playmode(Configures.PlaymodeOrder) elif self.playmode == Configures.PlaymodeOrder: self.set_new_playmode(Configures.PlaymodeSingle) elif self.playmode == Configures.PlaymodeSingle: self.set_new_playmode(Configures.PlaymodeRandom) self.playmode_changed_signal.emit(oldPlaymode, self.playmode) def set_new_playmode(self, playmode): self.playmode = playmode if playmode == Configures.PlaymodeRandom: iconPath = IconsHub.PlaymodeRandom toolTip = Configures.PlaymodeRandomText elif playmode == Configures.PlaymodeOrder: iconPath = IconsHub.PlaymodeOrder toolTip = Configures.PlaymodeOrderText else: iconPath = IconsHub.PlaymodeSingle toolTip = Configures.PlaymodeSingleText self.playmodeButton.setIcon(QIcon(iconPath)) self.playmodeButton.setToolTip(toolTip) def ui_initial(self): self.mediaPlayer.stop() self.totalTime = "00:00" self.playAction.setIcon(QIcon(IconsHub.ControlPlay)) self.musicTitleLabel.setText("Zheng-Yejian._.XYPLAYER") self.artistName = "Zheng-Yejian" self.artistHeadLabel.setPixmap(QPixmap(IconsHub.Anonymous)) self.seekSlider.setRange(0, 0) self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("收藏") self.timeLabel.setText("00:00/00:00") def set_volume(self, volume): self.mediaPlayer.setVolume(volume) def set_muted(self, muted): self.mediaPlayer.setMuted(muted) def tick(self): currentTime = self.mediaPlayer.position() self.seekSlider.setValue(currentTime) cTime = format_position_to_mmss(currentTime // 1000) self.timeLabel.setText(cTime + "/" + self.totalTime) self.media_player_notify_signal.emit(currentTime) def slider_value_changed(self, value): cTime = format_position_to_mmss(value // 1000) self.timeLabel.setText("%s/%s" % (cTime, self.totalTime)) self.media_player_notify_signal.emit(value) def slider_pressed(self): self.mediaPlayer.positionChanged.disconnect(self.tick) def seek(self): if self.mediaPlayer.state() == QMediaPlayer.StoppedState: self.mediaPlayer.play() self.mediaPlayer.setPosition(self.seekSlider.value()) else: self.mediaPlayer.setPosition(self.seekSlider.value()) self.mediaPlayer.play() self.mediaPlayer.positionChanged.connect(self.tick) def duration_changed(self, duration): self.seekSlider.setMaximum(duration) exactTotalTime = format_position_to_mmss(self.mediaPlayer.duration() // 1000) self.timeLabel.setText("%s/%s" % (Configures.ZeroTime, exactTotalTime)) if self.totalTime != exactTotalTime: self.totalTime = exactTotalTime self.playlist.set_music_time_at(self.currentSourceRow, exactTotalTime) def check_favorite(self): if self.currentSourceRow >= 0: if self.playlist.get_music_title_at(self.currentSourceRow) in self.lovedSongs: self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("取消收藏") else: self.favoriteButton.setIcon(QIcon(IconsHub.FavoritesNo)) self.favoriteButton.setToolTip("收藏") if self.playlist.get_name() == Configures.PlaylistFavorite: self.favoriteButton.setToolTip("收藏") def mark_as_favorite(self): if ( self.playlist.get_name() == Configures.PlaylistFavorite or not self.playlist.length() or self.currentSourceRow < 0 ): return path = self.playlist.get_music_path_at(self.currentSourceRow) title = self.playlist.get_music_title_at(self.currentSourceRow) if self.playlist.get_name() == Configures.PlaylistOnline: musicName = get_full_music_name_from_title(title) musicPath = os.path.join(self.downloadDir, musicName) musicPathO = os.path.join(Configures.MusicsDir, musicName) if not os.path.exists(musicPath) and not os.path.exists(musicPathO): QMessageBox.information(self, "提示", "请先下载该歌曲再添加喜欢!") return if os.path.exists(musicPath): path = musicPath else: path = musicPathO elif not os.path.exists(path): QMessageBox.information(self, "提示", "路径'" + "%s" % path + "'无效,无法标记喜欢!") return playlistTemp = Playlist() playlistTemp.fill_list(Configures.PlaylistFavorite) if title in self.lovedSongs: playlistTemp.remove_item_at(self.lovedSongs.index(title)) playlistTemp.commit_records() self.lovedSongs.remove(title) self.favoriteButton.setIcon(QIcon(IconsHub.FavoritesNo)) self.favoriteButton.setToolTip("收藏") else: playlistTemp.add_item_from_path(path) playlistTemp.commit_records() self.lovedSongs.append(title) self.favoriteButton.setIcon(QIcon(IconsHub.Favorites)) self.favoriteButton.setToolTip("取消收藏") self.mark_favorite_completed_signal.emit() def show_artist_info(self): if self.artistName: self.show_artist_info_signal.emit(self.artistName) def decide_to_play_or_pause(self, row): if row != self.currentSourceRow: self.set_media_source_at_row(row, clickPlayFlag=True) elif self.mediaPlayer.state() in (QMediaPlayer.PausedState, QMediaPlayer.StoppedState): self.mediaPlayer.play() elif self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() def set_media_source_at_row(self, row, clickPlayFlag=False): if not self.playlist.length() or row < 0: return self.stop_music() self.clickPlayFlag = clickPlayFlag self.playlist.set_current_row(row) sourcePath = self.playlist.get_music_path_at(row) self.title = self.playlist.get_music_title_at(row) self.sourceTrace = "local" if self.playlist.get_music_id_at(row) == Configures.LocalMusicId else "online" self.artistName, self.musicName = get_artist_and_musicname_from_title(self.title) self.playlistName = self.playlist.get_name() self.totalTime = self.playlist.get_music_time_at(row) self.album = self.playlist.get_music_album_at(row) self.errorType = Configures.NoError isAnUrl = False if not os.path.exists(sourcePath): if self.playlist.get_name() == Configures.PlaylistOnline: if sourcePath == Configures.NoLink: musicId = self.playlist.get_music_id_at(row) sourcePath = SearchOnline.get_song_link(musicId) if sourcePath: self.playlist.set_music_path_at(row, sourcePath) else: self.errorType = Configures.UrlError isAnUrl = True else: self.errorType = Configures.PathError sourcePath = "/usr/share/sounds/error_happened.ogg" if self.errorType == Configures.NoError: self.sourcePath = sourcePath self.musicFileName = get_base_name_from_path(sourcePath) self.playedDate = get_time_of_now() self.songinfosManager.update_datas_of_item( self.musicFileName, self.playedDate, self.musicName, self.artistName, self.totalTime, self.album, self.playlistName, ) if not self.timerFlag: self.timerFlag = True self.timeSpan = 0 if isAnUrl: url = QUrl(sourcePath) else: url = QUrl.fromLocalFile(sourcePath) self.play_from_url(url) else: self.timerFlag = False self.dont_hide_main_window_signal.emit() if self.errorType == Configures.DisnetError: QMessageBox.critical( self, "错误", "联网出错!\n无法联网播放歌曲'%s'!\n您最好在网络畅通时下载该曲目!" % self.playlist.get_music_title_at(row) ) elif self.errorType == Configures.PathError: QMessageBox.information(self, "提示", "路径'%s'无效,请尝试重新下载并添加对应歌曲!" % self.playlist.get_music_path_at(row)) def play_from_url(self, url): mediaContent = QMediaContent(url) self.mediaPlayer.setMedia(mediaContent) self.mediaPlayer.play() def state_changed(self, newState): if self and newState in [QMediaPlayer.PlayingState, QMediaPlayer.PausedState, QMediaPlayer.StoppedState]: if not self.playlist.length(): return iconPath = IconsHub.ControlPause if newState in [QMediaPlayer.StoppedState, QMediaPlayer.PausedState]: iconPath = IconsHub.ControlPlay icon = QIcon(iconPath) self.playAction.setIcon(icon) if self.timerFlag: if newState == QMediaPlayer.PlayingState: self.timeStart = time.time() else: self.timeSpan += time.time() - self.timeStart def media_status_changed(self, status): if status == QMediaPlayer.EndOfMedia: self.music_finished() def music_finished(self): if self.errorType == Configures.NoError: self.next_song() def play_music(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def stop_music_but_timing(self): self.mediaPlayer.stop() self.seekSlider.setValue(0) self.media_player_notify_signal.emit(-0.5) def stop_music(self): self.stop_music_but_timing() if self.timerFlag: self.timerFlag = False InfosList = [ self.playedDate, self.musicFileName, self.musicName, self.artistName, self.album, "%i" % change_mmss_to_seconds(self.totalTime), "%.1f" % self.timeSpan, self.playlistName, self.sourcePath, "%i" % (self.title in self.lovedSongs), self.sourceTrace, Configures.Playmodes[self.playmode], "%i" % self.clickPlayFlag, ] log_playback_history(organized_list_as_str(InfosList)) self.songinfosManager.update_time_span_relate_of_item(self.musicFileName, self.timeSpan, self.clickPlayFlag) self.clickPlayFlag = False def get_next_random_row(self): listTemp = list(self.playlist.get_ids() - set(self.nearPlayedSongs)) ran = random.randint(0, len(listTemp) - 1) return self.playlist.get_items_queue().index(listTemp[ran]) def get_next_single_row(self): nextRow = self.currentSourceRow if nextRow < 0: nextRow = 0 return nextRow def get_next_order_row(self, reverse=False): if reverse: if self.currentSourceRow < 0: self.currentSourceRow = 0 return (self.currentSourceRow - 1) % self.playlist.length() return (self.currentSourceRow + 1) % self.playlist.length() def previous_song(self): self.play_source_on_next_row(reverse=True) def next_song(self): self.play_source_on_next_row() def play_source_on_next_row(self, reverse=False): if not self.playlist.length(): return if self.mediaPlayer.position() > 20: self.music_ended_signal.emit() nextRow = 0 if self.playmode == Configures.PlaymodeRandom: nextRow = self.get_next_random_row() elif self.playmode == Configures.PlaymodeOrder: nextRow = self.get_next_order_row(reverse) elif self.playmode == Configures.PlaymodeSingle: nextRow = self.get_next_single_row() self.set_media_source_at_row(nextRow) def current_media_changed(self): if not self.playlist.length(): return self.current_media_changed_signal.emit() self.update_parameters() self.update_near_played_queue() self.check_favorite() def update_parameters(self): self.currentSourceRow = self.playlist.get_current_row() self.musicTitleLabel.setText(self.title) self.playAction.setText(self.musicName) imagePath = SearchOnline.get_artist_image_path(self.artistName) if imagePath: pixmap = QPixmap(imagePath) else: pixmap = QPixmap(IconsHub.Anonymous) self.artistHeadLabel.setPixmap(pixmap) musicId = self.playlist.get_music_id_at(self.currentSourceRow) self.update_window_lyric_signal.emit(self.title, musicId) def update_near_played_queue(self): self.currentSourceId = self.playlist.get_music_path_at(self.currentSourceRow) if self.playlist.get_name() == Configures.PlaylistOnline: self.currentSourceId = self.playlist.get_music_id_at(self.currentSourceRow) if self.currentSourceId not in self.nearPlayedSongs: self.nearPlayedSongs.append(self.currentSourceId) while len(self.nearPlayedSongs) >= self.playlist.length() * 4 / 5: del self.nearPlayedSongs[0] def add_title_into_loved_songs(self, title): self.lovedSongs.append(title)
class MusicPlayer(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.options = self.parent().options self.ffmpeg = self.options['paths']['ffmpeg_bin'] self.thumbnails = self.options['paths']['thumbnails'] self.thumb_width = self.options['thumbnail']['width'] self.thumb_height = self.options['thumbnail']['height'] self.jumping = False self.blocked = False self.durations = {} self.playback_value = 0 self.text = ["None", "Repeat", "Random"] self.playlist_list = [] self.values = [ QMediaPlaylist.Loop, QMediaPlaylist.CurrentItemInLoop, QMediaPlaylist.Random ] # Thumbnail widget self.image_label = QLabel() # Control widgets self.playButton = QToolButton(clicked=self.play) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton = QToolButton(clicked=self.stop) self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.stopButton.setEnabled(False) self.playbackButton = QToolButton(clicked=self.playback_mode) self.playbackButton.setText(self.text[0]) self.nextButton = QToolButton(clicked=self.next_song) self.nextButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) self.previousButton = QToolButton(clicked=self.previous_song) self.previousButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipBackward)) self.muteButton = QToolButton(clicked=self.mute_clicked) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.volumeSlider = QSlider(Qt.Horizontal, sliderMoved=self.change_volume) self.volumeSlider.setRange(0, 100) self.volumeSlider.setPageStep(1) self.volumeSlider.setValue(50) # Player and playlist setup self.player = QMediaPlayer() self.player.setVolume(50) self.player.stateChanged.connect(self.waveform) self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(self.values[0]) self.playlist.setCurrentIndex(1) self.player.setPlaylist(self.playlist) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.playlistView.setContextMenuPolicy(Qt.CustomContextMenu) self.playlistView.customContextMenuRequested.connect( self.list_view_menu) self.playlist.currentIndexChanged.connect( lambda position: self.change_thumbnail(position)) song_search = QLineEdit() song_search.textChanged.connect(self.search) song_search.setClearButtonEnabled(True) # Playlist self.playlist_name = QComboBox() self.playlist_name.currentTextChanged.connect(self.switch_playlist) self.refresh_lists() self.up_button = QToolButton(clicked=self.move_up) self.up_button.setIcon(self.style().standardIcon(QStyle.SP_ArrowUp)) self.down_button = QToolButton(clicked=self.move_down) self.down_button.setIcon(self.style().standardIcon( QStyle.SP_ArrowDown)) # Sound wave widget self.wave_graphic = WaveGraphic(self) #self.wave_graphic.hide() # Testing slider again self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.slider.sliderMoved.connect(self.seek) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) # Shortcuts QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self, song_search.setFocus) # Layouts setup playlist_layout = QHBoxLayout() playlist_layout.addWidget(self.playlist_name) playlist_layout.addWidget(self.up_button) playlist_layout.addWidget(self.down_button) control_layout = QHBoxLayout() control_layout.setContentsMargins(0, 0, 0, 0) control_layout.addWidget(self.stopButton) control_layout.addWidget(self.previousButton) control_layout.addWidget(self.playButton) control_layout.addWidget(self.nextButton) control_layout.addWidget(self.muteButton) control_layout.addWidget(self.volumeSlider) control_layout.addWidget(self.playbackButton) display_layout = QVBoxLayout() display_layout.addWidget(song_search) display_layout.addWidget(self.playlistView) display_layout.addLayout(playlist_layout) music_layout = QVBoxLayout() music_layout.addWidget(self.image_label) music_layout.addWidget(self.slider) music_layout.addLayout(control_layout) main_layout = QHBoxLayout() main_layout.addLayout(music_layout) main_layout.addLayout(display_layout) main_2_layout = QVBoxLayout() main_2_layout.addLayout(main_layout) main_2_layout.addWidget(self.wave_graphic) self.setLayout(main_2_layout) def waveform(self, status): if status == QMediaPlayer.PlayingState: self.wave_graphic.start() elif status == QMediaPlayer.PausedState: self.wave_graphic.pause() else: self.wave_graphic.stop() def list_view_menu(self, point): menu = QMenu("Menu", self) recommend_action = QAction('&Recommend Songs', self) menu.addAction(recommend_action) # TODO: [FEATURE] add rename song recommend_action.triggered.connect( lambda: self.parent().call_download_manager(self.get_links())) rename_action = QAction('&Rename', self) menu.addAction(rename_action) # TODO: [FEATURE] add rename song rename_action.triggered.connect(lambda: print("rename")) # Show the context menu. menu.exec_(self.playlistView.mapToGlobal(point)) def get_links(self): title = self.playlistView.selectedIndexes()[0].data() link = getYoutubeURLFromSearch(title) if len(link) > 1: return youtube_recommendations(link) def move_up(self): index = self.playlistView.currentIndex().row() if index - 1 >= 0: item, above = self.playlist.media(index), self.playlist.media( index - 1) self.playlist.removeMedia(index) self.playlist.removeMedia(index - 1) self.playlist.insertMedia(index - 1, item) self.playlist.insertMedia(index, above) self.blocked = True self.playlistView.setCurrentIndex( self.playlistModel.index(index - 1, 0)) self.blocked = False self.stop() def move_down(self): index = self.playlistView.currentIndex().row() if index + 1 <= self.playlistModel.rowCount(): item, below = self.playlist.media(index), self.playlist.media( index + 1) self.playlist.removeMedia(index + 1) self.playlist.removeMedia(index) self.playlist.insertMedia(index, below) self.playlist.insertMedia(index + 1, item) self.blocked = True self.playlistView.setCurrentIndex( self.playlistModel.index(index + 1, 0)) self.blocked = False self.stop() def search(self, part_of_song): for index in range(self.playlistModel.rowCount()): item = self.playlistModel.data(self.playlistModel.index( index, 0)).lower() self.playlistView.setRowHidden(index, part_of_song.lower() not in item) def change_thumbnail(self, position=0): self.playlistView.setCurrentIndex(self.playlistModel.index( position, 0)) song = self.playlistView.selectedIndexes()[0].data() if self.wave_graphic.is_song_cached(song): self.wave_graphic.load_waves(song) else: wc_ = WaveConverter(song, self.wave_graphic.set_wav) wc_.convert() if self.playlistView.currentIndex().data() is None or self.blocked: return max_ratio = 0 img = None for item in listdir(self.thumbnails): if item.endswith('.jpg'): ratio = similar( item, self.playlistView.currentIndex().data().replace( '.mp3', '.jpg')) if ratio > max_ratio: max_ratio = ratio img = item if img: p = QPixmap(self.thumbnails + img) self.image_label.setPixmap( p.scaled(self.thumb_width, self.thumb_height, Qt.KeepAspectRatio)) def switch_playlist(self, current_text): self.playlist.clear() if current_text == "No Playlist": self.refresh() else: if read_playlist(current_text): songs = read_playlist(current_text).split('\n') for song in songs: self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(song))) def refresh(self): # Change it so it will go to same song. if self.playlist_name.currentText() != "No Playlist": return paths = fetch_options()['paths']['music_path'].split(';') current_songs = [ self.playlistModel.data(self.playlistModel.index(row, 0)) for row in range(self.playlistModel.rowCount()) ] for path in paths: if not path: continue for item in listdir(path): if isfile(join(path, item)) and item.endswith(".mp3") and ( item not in current_songs): self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(join(path, item)))) def refresh_lists(self): path = fetch_options()['paths']['playlist'] self.playlist_name.clear() self.playlist_list = ["No Playlist"] self.playlist_name.addItem("No Playlist") for item in listdir(path): if isfile(join(path, item)) and item.endswith(".lst"): self.playlist_list.append(item.split('.')[0]) self.playlist_name.addItem(item.split('.')[0]) def playback_mode(self): # Normal -> Loop -> Random def up_value(value, max_value=3): if value + 1 == max_value: return 0 return value + 1 self.playback_value = up_value(self.playback_value) self.playlist.setPlaybackMode(self.values[self.playback_value]) self.playbackButton.setText(self.text[self.playback_value]) def jump(self, index): if index.isValid() and not self.blocked: self.playlist.setCurrentIndex(index.row()) self.jumping = True self.play() def play(self): if self.blocked: return if self.player.state() != QMediaPlayer.PlayingState or self.jumping: self.player.play() self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) self.jumping = False else: self.player.pause() self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self.stopButton.setEnabled(True) def change_volume(self, value): self.player.setVolume(value) def stop(self): if self.player.state() != QMediaPlayer.StoppedState: self.player.stop() self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton.setEnabled(False) def next_song(self): self.playlist.next() self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) def previous_song(self): self.playlist.previous() self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) def mute_clicked(self): self.player.setMuted(not self.player.isMuted()) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume if not self.player.isMuted() else QStyle. SP_MediaVolumeMuted)) def durationChanged(self, duration): duration /= 1000 self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) def seek(self, seconds): self.player.setPosition(seconds * 1000)
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.playlist = [] self.files = [] self.menu = QMenu() self.menu.addAction(icons["ti-file"] + " Open a file", lambda: print("file")) self.menu.addAction(icons["ti-files"] + " Open a files", lambda: print("files"), "Ctrl+O") self.menu.addAction(icons["ti-folder"] + " Open a folder", lambda: print("folder"), "Ctrl+Shift+O") self.menu.setStyleSheet("font-family: themify;") self.setMinimumSize(500, 60) self.move(100, 100) self.player = QMediaPlayer() self.titleBar = CustomTitleBar(self, "AnosePlayer", "ti-music-alt") self.prevBut = QPushButton(icons["ti-control-skip-backward"], self) self.pausBut = QPushButton(icons["ti-control-pause"], self) self.nextBut = QPushButton(icons["ti-control-skip-forward"], self) self.progress = QProgressBar(self) self.openFile = QPushButton(icons["ti-plus"], self) self.prevBut.setObjectName("Control") self.pausBut.setObjectName("Control") self.nextBut.setObjectName("Control") self.openFile.setObjectName("Control") self.progress.setTextVisible(False) self.openFile.setMenu(self.menu) self.player.setVolume(10) self.player.positionChanged.connect(self.updateTime) self.player.durationChanged.connect(self.showDuration) self.player.mediaChanged.connect(self.changedMedia) self.player.volumeChanged.connect(self.showVolume) self.player.stateChanged.connect(lambda *args: print(args)) self.prevBut.clicked.connect(self.previousSong) self.pausBut.clicked.connect(self.playPause) self.nextBut.clicked.connect(self.nextSong) self.player.setMedia( QMediaContent( QUrl.fromLocalFile( "/home/martin/Music/Principal/System Of A Down - ATWA.mp3") )) with open("theme.css", "r") as file: self.setStyleSheet(file.read()) def oFile(self): file = QFileDialog.getExistingDirectory( self, "QFileDialog.getOpenFileName()", "", "All Files (*);;Python Files (*.py)") # def oFiles(self): def oFolde(self): file = QFileDialog.getExistingDirectory( self, "QFileDialog.getOpenFileName()", "", "All Files (*);;Python Files (*.py)") def updateTime(self, time): self.progress.setValue(time) self.progress.repaint() print(self.progress.value()) def showDuration(self, totalTime): self.progress.setMaximum(totalTime) print(self.progress.maximum()) def changedMedia(self, *args): print(args) def showVolume(self, volume): print(volume) def changeTime(self, time): self.player.setPosition(time) def previousSong(self): if self.i - 1 >= 0: self.i -= 1 self.player.setMedia( QMediaContent(QUrl.fromLocalFile(self.playlist[self.i]))) def playPause(self): if self.player.state() == 1: self.player.pause() self.pausBut.setText(icons["ti-control-play"]) else: self.player.play() self.pausBut.setText(icons["ti-control-pause"]) def nextSong(self): if self.i + 1 >= len(self.playlist): self.playlist.append(choice(self.files)) self.i += 1 self.player.setMedia( QMediaContent(QUrl.fromLocalFile(self.playlist[self.i]))) def resizeEvent(self, e): self.titleBar.setGeometry(0, 0, self.width(), 20) self.prevBut.setGeometry(0, 20, 30, 30) self.pausBut.setGeometry(30, 20, 30, 30) self.nextBut.setGeometry(60, 20, 30, 30) self.progress.setGeometry(100, 25, 390, 20) self.openFile.setGeometry(0, 50, 30, 30)
class Player(QGraphicsVideoItem): isSubtitle = pyqtSignal(bool) subtitlePos = pyqtSignal(int) def __init__(self, parent=None): super().__init__() self.parent = parent self.player = QMediaPlayer() self.player.setVolume(int(settings().value("Player/volume") or 100)) self.player.setVideoOutput(self) self.timer = QTimer(self) self.timer.timeout.connect(self.timerPos) self.player.currentMediaChanged.connect(self.signalStart) self.player.currentMediaChanged.connect(self.parent.subtitleitem.subtitleControl) self.player.currentMediaChanged.connect(self.videoConfigure) """self.player.mediaStatusChanged.connect(self.metadata) def metadata(self, data): if data and self.player.isMetaDataAvailable(): print(self.player.metaData("VideoCodec"))""" def videoConfigure(self, media): video_name = os.path.basename(media.canonicalUrl().toLocalFile()) videos = settings().value("Player/video_names") or [] videos_time = settings().value("Player/videos_time") or [] try: self.player.setPosition(int(videos_time[videos.index(video_name)])) except ValueError: pass def timerStart(self): self.timer.start(200) def signalStart(self, content): srt = content.canonicalUrl().toLocalFile().split(".") srt.pop(-1) srt.append("srt") srt = ".".join(srt) if QFile.exists(srt): self.isSubtitle.emit(True) self.timer.start(100) else: self.isSubtitle.emit(False) self.timer.stop() def timerPos(self): self.subtitlePos.emit(self.player.position()) def playerPlayOrOpen(self, arg=None): if type(arg) == list and len(arg) > 1: content = QMediaContent(QUrl.fromLocalFile(arg[1])) self.player.setMedia(content) self.play() def addVideo(self, video): content = QMediaContent(QUrl.fromLocalFile(video)) self.player.setMedia(content) self.play() def addYoutubeVideo(self, video): dm = DownloadManager(self) content = QMediaContent(dm.addUrl(video)) self.player.setMedia(content) self.play() def sliderChanged(self, pos): self.player.setPosition(pos) def play(self): self.player.play() def stop(self): self.player.stop() def pause(self): self.player.pause() def setMuted(self, mute): self.player.setMuted(mute) def mutedState(self): if self.player.isMuted(): self.setMuted(False) else: self.setMuted(True) def isMuted(self): return self.player.isMuted() def setVolume(self, value): self.player.setVolume(value) def volume(self): return self.player.volume()
class DPlayerCore(QWidget): def __init__(self): """Initialize player and load playlist if any.""" super().__init__() self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.shuffling = False self.repeatingPlaylist = False self.repeatingSong = False self.musicOrder = [] self.loadPlaylist(QUrl( 'file://{}/lastListened.m3u'.format(os.getcwd()))) self.lyricsApi = 'http://api.musixmatch.com/ws/1.1/' self.lyricsApiKey = '4b364f0652e471aa50813a22cdf830ea' self.lastFMapi = 'http://ws.audioscrobbler.com/2.0/' self.lastFMapikey = '052c43a00a4fc294bb3c9e0c38bdf710' self.lastFMsecret = '14c66392fa9c6c142a41ccc2b0674e19' self.username = None self.password = None self.network = None self.error = 'Something went wrong! Try again later.' def play(self): """Start the player.""" self.player.play() def pause(self): """Pause the player.""" self.player.pause() def stop(self): """Stop the player.""" self.player.stop() def previous(self): """Play previous song.""" self.playlist.previous() def next(self): """Play next song.""" self.playlist.next() def mute(self): """Mute the player.""" self.player.setMuted(True) def unmute(self): """Unmute the player.""" self.player.setMuted(False) def setVolume(self, value): """Set player's volume to value.""" self.player.setVolume(value) def add(self, fileNames): """Add fileNames to the playlist.""" for name in fileNames: url = QUrl.fromLocalFile(QFileInfo(name).absoluteFilePath()) self.playlist.addMedia(QMediaContent(url)) self.musicOrder.append([name]) self.added(len(fileNames)) def added(self, added): """Saves music info in musicOrder.""" for name, index in zip( self.musicOrder[self.playlist.mediaCount() - added:], range(self.playlist.mediaCount() - added, len(self.musicOrder))): name = name[0] artist = self.getArtist(name)[0] title = self.getTitle(name)[0] album = self.getAlbum(name)[0] seconds = self.getDuration(name) duration = QTime(0, seconds // 60, seconds % 60) duration = duration.toString('mm:ss') self.musicOrder[index].extend( [artist, title, album, duration]) def remove(self, songIndexes): """Remove songIndexes from the playlist.""" for index in songIndexes: self.songChanged = True del self.musicOrder[index] self.playlist.removeMedia(index) self.songChanged = False def savePlaylist(self, path): """Save playlist to path.""" if path.toString()[len(path.toString()) - 4:] != '.m3u': path = QUrl('{}.m3u'.format(path.toString())) self.playlist.save(path, 'm3u') def loadPlaylist(self, path): """Load playlist form path.""" count = self.playlist.mediaCount() self.playlist.load(path) for index in range(count, self.playlist.mediaCount()): self.musicOrder.append( [self.playlist.media(index).canonicalUrl().path()]) self.added(self.playlist.mediaCount() - count) def clearPlaylist(self): """Delete all songs in the playlist.""" self.playlist.clear() self.musicOrder = [] def shuffle(self, value): """Shuffle playlist if value = True.""" self.shuffling = value if self.repeatingSong: return if self.shuffling: self.playlist.setPlaybackMode(QMediaPlaylist.Random) elif self.repeatingPlaylist: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) def repeatPlaylist(self, value): """Repeat playlist after the last song is finished if value = True.""" self.repeatingPlaylist = value if self.repeatingSong or self.shuffling: return if self.repeatingPlaylist: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) def repeatSong(self, value): """Repeat current song if value = True.""" self.repeatingSong = value if self.repeatingSong: self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) elif self.shuffling: self.playlist.setPlaybackMode(QMediaPlaylist.Random) elif self.repeatingPlaylist: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) def sort(self, column, order): """Sort playlist by column in order.""" ordered = sorted(self.musicOrder, key=itemgetter(column + 1), reverse=order) self.clearPlaylist() for song in ordered: url = QUrl.fromLocalFile(QFileInfo(song[0]).absoluteFilePath()) self.playlist.addMedia(QMediaContent(url)) self.musicOrder = ordered def findLyrics(self, index): """Returns lyrics for song at index.""" if self.musicOrder[index][2] == 'Unknown': return 'Unknown song.' searchSong = '{}track.search?q_track={}'.format( self.lyricsApi, self.musicOrder[index][2].replace(' ', '%20')) if self.musicOrder[index][1] != 'Unknown': searchSong = '{}&q_artist={}'.format( searchSong, self.musicOrder[index][1].replace(' ', '%20')) searchSong = '{}&f_has_lyrics=1&apikey={}'.format( searchSong, self.lyricsApiKey) try: requestSong = requests.get(searchSong) except requests.ConnectionError: return self.error songJson = requestSong.json() if requestSong.status_code != 200 or \ songJson['message']['header']['available'] == 0: return self.error songId = songJson[ 'message']['body']['track_list'][0]["track"]["track_id"] searchLyrics = '{}track.lyrics.get?track_id={}&apikey={}'.format( self.lyricsApi, songId, self.lyricsApiKey) try: requestLyrics = requests.get(searchLyrics) except requests.ConnectionError: return self.error if requestLyrics.status_code != 200 or \ songJson['message']['header']['available'] == 0: return self.error return requestLyrics.json()[ 'message']['body']['lyrics']['lyrics_body'][:-58] # spam and bacon def findInfo(self, index): """Returns info about artist and album for index if any.""" info = [] if self.musicOrder[index][1] != 'Unknown': artist = self.artistInfo(self.musicOrder[index][1]) if artist != self.error: info += artist if self.musicOrder[index][1] != 'Unknown' and \ self.musicOrder[index][3] != 'Unknown': album = self.albumInfo(self.musicOrder[index][1], self.musicOrder[index][3]) if album != self.error: info += album if info: return info else: return ['Unknown artist and song!'] def artistInfo(self, artist): """Returns info about artist if any.""" try: response = requests.get( ('{}/?method=artist.getinfo&artist={}&api_key={}&' 'format=json&autocorrect=1').format( self.lastFMapi, artist, self.lastFMapikey)) except Exception: return self.error if response.status_code != 200: return self.error artist = 'Artist: {}'.format(response.json()['artist']['name']) bio = 'Bio: {}'.format( response.json()['artist']['bio']['summary'].replace('.', '.\n')) spam = bio.find('<a') bio = bio[:spam] return [artist, bio] def albumInfo(self, artist, album): """Returns info about album if any.""" try: response = requests.get( ('{}/?method=album.getinfo&artist={}&album={}&api_key={}&' 'format=json&autocorrect=1').format( self.lastFMapi, artist, album, self.lastFMapikey)) except Exception: return self.error if response.status_code != 200 or \ 'album' not in response.json().keys(): return self.error album = 'Album: {}'.format(response.json()['album']['name']) tracks = ['Tracks: '] t = response.json()['album']['tracks']['track'] for track, index in zip(t, range(len(t))): tracks.append('{}. {}'.format(index + 1, track['name'])) info = [album, '\n'.join(tracks)] if 'wiki' in response.json()['album'].keys(): wiki = response.json()['album']['wiki'] if 'published' in wiki.keys(): info.append('Published: {}'.format(wiki['published'])) if 'summary' in wiki.keys(): summary = wiki['summary'].replace('.', '.\n') spam = summary.find('<a') info.append('Summary: {}'.format(summary[:spam])) if 'Musical style' in wiki.keys(): info.append('Musical style: {}'.format(wiki['Musical style'])) return info def login(self, username, password): """Creates lastFM network.""" self.username = username self.password = pylast.md5(password) try: self.network = pylast.LastFMNetwork(api_key=self.lastFMapikey, api_secret=self.lastFMsecret, username=self.username, password_hash=self.password) except Exception: self.username = None self.password = None self.network = None return False return True def logout(self): """Destoys lastFM network and current user info.""" self.username = None self.password = None self.network = None def loveTrack(self, index): """Love track at index in lastFM.""" if self.network is None: return False track = self.network.get_track(self.musicOrder[index][1], self.musicOrder[index][2]) try: track.love() except Exception: return False return True def unloveTrack(self, index): """Unlove track at index in lastFM.""" if self.network is None: return False track = self.network.get_track(self.musicOrder[index][1], self.musicOrder[index][2]) try: track.unlove() except Exception: return False return True def isMuted(self): """Returns True if player is muted.""" return self.player.isMuted() def getArtist(self, song): """Returns the artist of song.""" if song[-4:] == '.mp3': obj = EasyID3(song) if 'artist' in obj.keys(): return obj['artist'] elif 'TAG' in mediainfo(song).keys(): obj = mediainfo(song)['TAG'] if 'artist' in obj.keys(): return [obj['artist']] elif 'ARTIST' in obj.keys(): return [obj['ARTIST']] else: return ['Unknown'] else: return ['Unknown'] def getTitle(self, song): """Returns the title of song.""" if song[-4:] == '.mp3': obj = EasyID3(song) if 'title' in obj.keys(): return obj['title'] elif 'TAG' in mediainfo(song).keys(): obj = mediainfo(song)['TAG'] if 'title' in obj.keys(): return [obj['title']] elif 'TITLE' in obj.keys(): return [obj['TITLE']] else: return ['Unknown'] else: return ['Unknown'] def getAlbum(self, song): """Returns the album of song.""" if song[-4:] == '.mp3': obj = EasyID3(song) if 'album' in obj.keys(): return obj['album'] elif 'TAG' in mediainfo(song).keys(): obj = mediainfo(song)['TAG'] if 'album' in obj.keys(): return [obj['album']] elif 'ALBUM' in obj.keys(): return [obj['ALBUM']] else: return ['Unknown'] else: return ['Unknown'] def getDuration(self, song): """Returns the duration of song.""" if song[-4:] == '.mp3': return MP3(song).info.length return int(float(mediainfo(song)['duration']))
class EventAction(): def __init__(self): #self.parent = parent self.isLoop = 0 #0循环列表,1单曲循环 self.isRandom = 0 #0不随机,1随机 self.fileList = [] #曲目名称列表 self.randomList =[] #播放列表 self.soundID = 0 #当前歌曲ID self.playStat = False #当前播放状态 (0未播放,1播放) self.openPath = "F:/mp3/" #歌曲目录 self.isPreview = 0 #试用开关,0正常播放,1列表中的歌曲每首歌曲放10秒 self.currentVolume = 0.1#默认的起始音量 self.isInitPlay = 1 #是否是初始播放 #==>>打开目录 self.config=configparser.ConfigParser() self.config.read('config.ini') self.openDir() #打开目录<<== self.playObj = QMediaPlayer() self.currentImg = "" #当前图片 self.songText = {} #歌词 self.songTextKey=[] #歌词KEY #打开歌曲目录 def openDir(self): self.openPath = self.config.get('Save','musicPath') isMusicDir = os.path.isdir(self.openPath)#检查是否为目录 if isMusicDir: dirFile = os.listdir(self.openPath)#目录中的所有文件 #遍历有效音乐文件 i=0; for file in dirFile: fileName,fileType=os.path.splitext(file) if fileType==".mp3" or fileType==".wav": self.fileList.append(file) self.randomList.append(i) i+=1 if self.isRandom==1: self.shuffleMusic(1) #随机(打乱播放顺序) def shuffleMusic(self,isshuffle): if isshuffle: random.shuffle(self.randomList)#乱序 else: self.randomList.sort()#排序 #初始化播放 def initPlay(self): self.soundID = int(self.config.get('Save','soundID')) self.playStat = self.config.get('Save','playStat') self.pastTime = self.config.getint('Save','pastTime') self.currentVolume = self.config.getint('Save','volume') self.isRandom = self.config.getint('Save','isRandom') self.isLoop = self.config.getint('Save','isLoop') if self.soundID!="": self.play(self.soundID) if self.isRandom:#打乱列表 self.shuffleMusic(1) self.playObj.setVolume(self.currentVolume) #播放 def play(self,i): source = self.openPath + self.fileList[i] self.playObj.setMedia(QMediaContent(QUrl.fromLocalFile(source))) #解析文件中的ID3V2 self.currentImg = "" f = QFile(source) if f.open(QIODevice.ReadOnly): #读取标签 headData = f.read(10) data = headData[:0] if self.id3v2(headData):#检测是否有ID3 #标签的大小计算 tag = headData[6:10] tagSize = (tag[0]&0x7f)*0x200000+(tag[1]&0x7f)*0x4000+(tag[2]&0x7f)*0x80+(tag[3]&0x7f) data =f.read(tagSize) while len(data)>10: data = self.resolve(data) f.close() self.playObj.play() def testPlay(self): #ps =QMediaMetaData() #print("QMediaMetaData",ps) #print("metaData",self.playObj.metaData(QMediaMetaData.Title)) #print("position",self.playObj.position()) #print("playlist",self.playObj.playlist) #print("availability",self.playObj.availability()) #print("bufferStatus",self.playObj.bufferStatus()) #print("currentMedia",self.playObj.currentMedia()) #print("currentNetworkConfiguration",self.playObj.currentNetworkConfiguration()) #print("duration",self.playObj.duration()) #print("error",self.playObj.error()) #print("errorString",self.playObj.errorString()) #print("isAudioAvailable",self.playObj.isAudioAvailable()) #print("isMuted",self.playObj.isMuted()) #print("isSeekable",self.playObj.isSeekable()) #print("media",self.playObj.media()) #print("media:::::::A",self.playObj.media().canonicalResource().audioBitRate()) #print("media:::::::B",self.playObj.media().canonicalResource().audioCodec()) #print("media:::::::C",self.playObj.media().canonicalResource().channelCount()) #print("media:::::::D",self.playObj.media().canonicalResource().dataSize()) #print("media:::::::e",self.playObj.media().canonicalResource().isNull()) #print("media:::::::f",self.playObj.media().canonicalResource().language()) #print("media:::::::g",self.playObj.media().canonicalResource().mimeType()) #print("media:::::::h",self.playObj.media().canonicalResource().request()) #print("isVideoAvailable",self.playObj.isVideoAvailable()) #print("mediaStatus",self.playObj.mediaStatus()) #print("mediaStream",self.playObj.mediaStream()) #print("playbackRate",self.playObj.playbackRate()) #print("state",self.playObj.state()) #print("volume",self.playObj.volume()) # print("volume",self.playObj.filename) pass #换歌之前先停止,释放内存 def stopPlay(self): self.playObj.pause() #上一首 def prevPlay(self): self.stopPlay() if self.isRandom: key = self.searchID(self.soundID)-1 if key<0: key=0 self.soundID = self.randomList[key] else: self.soundID-=1 if self.soundID< 0: self.soundID = len(self.randomList)-1 self.play(self.soundID) #下一首 def nextPlay(self): self.stopPlay() if self.isRandom: key = self.searchID(self.soundID)+1 if key>(len(self.randomList)-1): key=len(self.randomList)-1 self.soundID = self.randomList[key] else: self.soundID+=1 if self.soundID > (len(self.randomList)-1): self.soundID = 0 #print("next:::",self.soundID) self.play(self.soundID) #快退 def rewindPlay(self): #print("<<") rewindTime = int(self.playObj.position()) - 10*1000 if rewindTime < 0: rewindTime = 0 self.playObj.setPosition(rewindTime) #快进 def forwardPlay(self): #print(">>") forwardTime = int(self.playObj.position()) + 10*1000 if forwardTime > int(self.playObj.duration()): forwardTime = int(self.playObj.duration()) self.playObj.setPosition(forwardTime) #播放/暂停 def playORpause(self): if self.playObj.state()==1: self.playObj.pause() else: self.playObj.play() #音量加 def raisevolPlay(self): self.playObj.setVolume(self.playObj.volume()+10) self.currentVolume = self.playObj.volume() #音量减 def lowervolPlay(self): self.playObj.setVolume(self.playObj.volume()-10) self.currentVolume = self.playObj.volume() #静音 def mutePlay(self): if self.playObj.isMuted(): self.playObj.setMuted(False) else: self.playObj.setMuted(True) #volume #跟据v找K def searchID(self,v): for index, item in enumerate(self.randomList): if item ==v: return index return 0 #解析文件中是否有id3v2 def id3v2(self,headData): if str(headData[:3],encoding=("utf-8")) != "ID3": return False return True #解析文件中的歌词与图片 def resolve(self,data): tagName = str(data[:4],encoding=("utf-8")) size = data[4:8] #sizeS = size[0]*0x1000000 + size[1]*0x10000 + size[2]*0x100 + size[3] sizeS=int.from_bytes(size, byteorder='big') flags = data[8:10] tagContent = data[10:sizeS+10] if tagName=="TEXT":#歌词 #print("歌词") condingType=int.from_bytes(tagContent[:1], byteorder='big') if condingType == 0:#0代表字符使用ISO-8859-1编码方式; try: content = str(tagContent[1:],encoding="gbk") except: content ="" elif condingType == 1:#1代表字符使用UTF-16编码方式; try: content = str(tagContent[1:],encoding="UTF-16") except: content ="" elif condingType == 2:#2代表字符使用 UTF-16BE编码方式; content ="" elif condingType == 3:#3代表字符使用UTF-8编码方式。 try: content = str(tagContent[1:],encoding="UTF-8") except: content ="" if content!="": temp={} self.songTextKey=[] contentSplit = content.splitlines() for k in range(len(contentSplit)): if contentSplit[k][1].isdigit(): xxx = contentSplit[k].split("]") tempKey = "%d" %(int(xxx[0][1:3])*60 +int(xxx[0][4:6]) ) temp[str(tempKey)] = xxx[1] self.songTextKey.append(tempKey) else: endKey = contentSplit[k].find("]",0) self.songTextKey.append(k) temp[str(k)] = contentSplit[k][1:endKey] self.songText = temp else: self.songText = {} elif tagName=="APIC":#图片 #print("图片") self.currentImg = tagContent[17:] return data[10+sizeS:]
class MainUi(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.init_ui() self.player = QMediaPlayer(self) def init_ui(self): self.setFixedSize(550, 325) self.main_widget = QtWidgets.QWidget() # 创建窗口主部件 self.main_layout = QtWidgets.QGridLayout() # 创建主部件的网格布局 self.main_widget.setLayout(self.main_layout) # 设置窗口主部件布局为网格布局 self.left_widget = QtWidgets.QWidget() # 创建左侧部件 self.left_widget.setObjectName('left_widget') self.left_layout = QtWidgets.QGridLayout() # 创建左侧部件的网格布局层 self.left_widget.setLayout(self.left_layout) # 设置左侧部件布局为网格 self.left_widget.setStyleSheet(''' QPushButton{border:none;color:white;} QPushButton#left_label{ border:none; border-bottom:1px solid white; font-size:18px; font-weight:700; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } QPushButton#left_button:hover{border-left:4px solid red;font-weight:700;} ''') self.right_widget = QtWidgets.QWidget() # 创建右侧部件 self.right_widget.setObjectName('right_widget') self.right_layout = QtWidgets.QGridLayout() self.right_widget.setLayout(self.right_layout) # 设置右侧部件布局为网格 self.right_bar_widget = QtWidgets.QWidget() # 右侧顶部搜索框部件 self.right_bar_layout = QtWidgets.QGridLayout() # 右侧顶部搜索框网格布局 self.right_bar_widget.setLayout(self.right_bar_layout) self.search_icon = QtWidgets.QLabel(chr(0xf002) + ' ' + '搜索 ') self.search_icon.setFont(qtawesome.font('fa', 16)) self.right_bar_widget_search_input = QtWidgets.QLineEdit("") self.right_bar_widget_search_input.setPlaceholderText( "输入歌手、歌曲或用户,回车进行搜索") self.right_bar_layout.addWidget(self.search_icon, 0, 0, 1, 1) self.right_bar_layout.addWidget(self.right_bar_widget_search_input, 0, 1, 1, 8) self.right_layout.addWidget(self.right_bar_widget, 0, 0, 1, 9) self.right_bar_widget_search_input.returnPressed.connect( self.Get_song_name) self.right_bar_widget_search_input.setStyleSheet('''QLineEdit{ border:1px solid gray; width:300px; border-radius:10px; padding:2px 4px; }''') self.right_widget.setStyleSheet(''' QWidget#right_widget{ color:#232C51; background:white; border-top:1px solid darkGray; border-bottom:1px solid darkGray; border-right:1px solid darkGray; border-top-right-radius:10px; border-bottom-right-radius:10px; } QLabel#right_lable{ border:none; font-size:16px; font-weight:700; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } ''') # icon = QtGui.QIcon() # icon.addPixmap(QtGui.QPixmap("ico/瓜板.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) # self.setWindowIcon(icon) # self.setToolTip("") self.main_layout.addWidget(self.left_widget, 0, 0, 12, 2) # 左侧部件在第0行第0列,占8行3列 self.main_layout.addWidget(self.right_widget, 0, 2, 12, 10) # 右侧部件在第0行第3列,占8行9列 self.setCentralWidget(self.main_widget) # 设置窗口主部件 self.left_close = QtWidgets.QPushButton("") # 关闭按钮 self.left_visit = QtWidgets.QPushButton("") # 空白按钮 self.left_mini = QtWidgets.QPushButton("") # 最小化按钮 self.left_close.setFixedSize(15, 15) # 设置关闭按钮的大小 self.left_visit.setFixedSize(15, 15) # 设置按钮大小 self.left_mini.setFixedSize(15, 15) # 设置最小化按钮大小 self.left_layout.addWidget(self.left_mini, 0, 0, 1, 1) # 放置最小化按钮 self.left_layout.addWidget(self.left_close, 0, 2, 1, 1) # 放置关闭按钮 self.left_layout.addWidget(self.left_visit, 0, 1, 1, 1) # 放置空白按钮 self.left_close.setStyleSheet( '''QPushButton{background:#F76677;border-radius:5px;}QPushButton:hover{background:red;}''' ) self.left_visit.setStyleSheet( '''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:yellow;}''' ) self.left_mini.setStyleSheet( '''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''' ) self.left_close.clicked.connect(self.left_close_event) # 添加关闭功能 self.setWindowFlag(QtCore.Qt.FramelessWindowHint) # 隐藏边框 self.setWindowOpacity(0.95) # 设置窗口透明度 # self.setAttribute(QtCore.Qt.WA_TranslucentBackground) # 设置窗口背景透明 self.main_layout.setSpacing(0) # 鼠标长按事件 def mousePressEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self.m_drag = True self.m_DragPosition = event.globalPos() - self.pos() event.accept() self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 鼠标移动事件 def mouseMoveEvent(self, QMouseEvent): if QtCore.Qt.LeftButton and self.m_drag: self.move(QMouseEvent.globalPos() - self.m_DragPosition) QMouseEvent.accept() # 鼠标释放事件 def mouseReleaseEvent(self, QMouseEvent): self.m_drag = False self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) def left_close_event(self): self.close() def Get_song_name(self): song_name = self.right_bar_widget_search_input.text() # 提取歌曲id a, song_id = Cloud_Music_API.single_search(song_name) #print(song_id) # 获取url song_url = Cloud_Music_API.song_url(song_id[1]) # 播放音乐 content = QMediaContent(QtCore.QUrl(song_url)) self.player.setMedia(content) self.player.setVolume(30) self.player.play() self.duration = self.player.duration() # 音乐的时长
class AudioPlayer(QMainWindow): def __init__(self): super(AudioPlayer, self).__init__() self.setGeometry(150, 150, 600, 450) self.setWindowTitle('Prototype!!') self.isButtonClick = False self.current_time = 0 self.media_obj = audiosegment.empty() self.play_process = threading.Thread(target=play, args=(self.media_obj,)) self.initUI() def initUI(self): menu = self.menuBar() # create menu bar file_menu = menu.addMenu('File') # create file button options_menu = menu.addMenu('Options') # create options button wid = QWidget() self.setCentralWidget(wid) # create 'Open FIle' actions, add to 'File' button open_file = QAction('Open File', self) open_file.triggered.connect(self.openFile) open_file.setShortcut("Ctrl+O") file_menu.addAction(open_file) # create 'Close File' action, add to 'File' button close_file = QAction('Close File', self) close_file.triggered.connect(self.exit) close_file.setShortcut("Ctrl+W") file_menu.addAction(close_file) # create 'Exit' action, add to 'File' button exit_file = QAction('Close File', self) exit_file.triggered.connect(self.exit) exit_file.setShortcut("Ctrl+W") file_menu.addAction(exit_file) # create 'Color' action, add to 'Options' button color_option = QAction('Color', self) color_option.triggered.connect(self.show_color_dialog) color_option.setShortcut("Ctrl+2") options_menu.addAction(color_option) # create 'Shape' action, add to 'Options' button shape_option = QAction('Shape', self) # shape_option.triggered.connect() shape_option.setShortcut("Ctrl+3") options_menu.addAction(shape_option) # create 'Foliage' action, add to 'Options' button foliage_option = QAction('Foliage', self) # foliage_option.triggered.connect() foliage_option.setShortcut("Ctrl+3") options_menu.addAction(foliage_option) # Creating button for pause/play self.player = QMediaPlayer() self.playlist = QMediaPlaylist() videoWidget = QVideoWidget() self.pal = QPalette() self.pal.setColor(QPalette.Foreground, Qt.green) videoWidget.setPalette(self.pal) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.errorLabel = QLabel() self.errorLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) self.songLabel = QLabel() self.songLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) self.playButton.setShortcut("Space") controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) layout = QVBoxLayout() layout.addWidget(videoWidget) layout.addLayout(controlLayout) layout.addWidget(self.songLabel) layout.addWidget(self.errorLabel) # Set widget to contain window contents wid.setLayout(layout) # self.mediaPlayer.setVideoOutput(videoWidget) self.player.stateChanged.connect(self.mediaStateChanged) self.player.positionChanged.connect(self.positionChanged) self.player.durationChanged.connect(self.durationChanged) self.player.error.connect(self.handleError) def openFile(self): song = QFileDialog.getOpenFileName(self, "Open Song", "~", "Sound Files (*.mp3 *.ogg *.wav *.m4a)") songName = song[0].split("/") songName = songName[-1].split(".") self.songLabel.setText(songName[0]) if song[0] != '': url = QUrl.fromLocalFile(song[0]) if self.playlist.mediaCount() == 0: self.playButton.setEnabled(True) self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.player.setVolume(100) self.player.play() else: self.playlist.addMedia(QMediaContent(url)) def exit(self): sys.exit() def play(self): if self.player.state() == QMediaPlayer.PlayingState: self.player.pause() else: self.player.play() def mediaStateChanged(self, state): if self.player.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) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): self.player.setPosition(position) def handleError(self): self.playButton.setEnabled(False) self.errorLabel.setText("Error: " + self.player.errorString()) def show_color_dialog(self): QColorDialog.getColor()
class VideoWindow(QMainWindow): """ Class: Video player window. """ # Main window size. WIN_SIZE = [800, 600] def __init__(self, parent=None): """ Function: Setup user interface of Video player window. """ super(VideoWindow, self).__init__(parent) self.setWindowTitle("Video player") self.resize(VideoWindow.WIN_SIZE[0], VideoWindow.WIN_SIZE[1]) self.setWindowIcon(self.style().standardIcon(QStyle.SP_DriveDVDIcon)) self.video_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.record_start_time = None self.record_end_time = None self.video_name = "" self.widget_video = QVideoWidget() self.statusbar = QtWidgets.QStatusBar(self) self.setStatusBar(self.statusbar) self.button_play = QPushButton() self.button_play.setEnabled(False) self.button_play.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self.button_play.clicked.connect(self.play_video) self.video_slider = QSlider(Qt.Horizontal) self.video_slider.setRange(0, 0) self.video_slider.sliderMoved.connect(self.set_position) self.video_duration = 0 # Action 'Open'. self.action_open = QAction(QIcon('open.png'), '&Open', self) self.action_open.setShortcut('Ctrl+O') self.action_open.setStatusTip('Open a video') self.action_open.triggered.connect(self.open_video) # Menu bar. self.menu_bar = self.menuBar() self.menu_menu = self.menu_bar.addMenu('&Menu') self.menu_menu.addAction(self.action_open) # Widget. self.widget_window = QWidget(self) self.setCentralWidget(self.widget_window) self.layout_operation = QHBoxLayout() self.layout_operation.setContentsMargins(0, 0, 0, 0) self.label_rotate = QLabel('Degree of rotation') self.combobox_degree = QComboBox() degrees = ['0', '90', '180', '270'] self.combobox_degree.addItems(degrees) self.button_subclip_video = QPushButton('Subclip (Video)') self.button_subclip_audio = QPushButton('Subclip (Audio)') self.layout_operation.addWidget(self.label_rotate) self.layout_operation.addWidget(self.combobox_degree) self.layout_operation.addWidget(self.button_subclip_video) self.layout_operation.addWidget(self.button_subclip_audio) self.layout_record = QHBoxLayout() self.layout_record.setContentsMargins(0, 0, 0, 0) self.button_start = QPushButton('Start') self.button_end = QPushButton('End') self.button_clear = QPushButton('Clear') self.layout_record.addWidget(self.button_start) self.layout_record.addWidget(self.button_end) self.layout_record.addWidget(self.button_clear) self.button_start.clicked.connect(self.record_start) self.button_end.clicked.connect(self.record_end) self.button_subclip_video.clicked.connect(self.record_subclip_video) self.button_subclip_audio.clicked.connect(self.record_subclip_audio) self.button_clear.clicked.connect(self.record_clear) # Widget layout. self.layout_widget = QHBoxLayout() self.layout_widget.setContentsMargins(0, 0, 0, 0) self.layout_widget.addWidget(self.button_play) self.layout_widget.addWidget(self.video_slider) self.layout_window = QVBoxLayout() self.layout_window.addWidget(self.widget_video) self.layout_window.addLayout(self.layout_record) self.layout_window.addLayout(self.layout_operation) self.layout_window.addLayout(self.layout_widget) # Window layout. self.widget_window.setLayout(self.layout_window) self.video_player.setVideoOutput(self.widget_video) self.video_player.stateChanged.connect(self.media_state_changed) self.video_player.positionChanged.connect(self.position_changed) self.video_player.durationChanged.connect(self.duration_changed) self.video_player.error.connect(self.error_control) QShortcut(Qt.Key_Up, self, self.arrow_up) QShortcut(Qt.Key_Down, self, self.arrow_down) QShortcut(Qt.Key_Left, self, self.arrow_left_event) QShortcut(Qt.Key_Right, self, self.arrow_right_event) QShortcut(Qt.Key_Space, self, self.play_video) def arrow_up(self): if self.video_player.state() != QMediaPlayer.StoppedState: self.video_player.setVolume( min(self.video_player.volume() + 10, 100)) def arrow_down(self): if self.video_player.state() != QMediaPlayer.StoppedState: self.video_player.setVolume(max(self.video_player.volume() - 10, 0)) def arrow_left_event(self): """ Slot function: Action after the key 'arrow left' is pressed. Fast-forward to 10 seconds later. """ self.set_position(self.video_slider.value() - 10 * 1000) def arrow_right_event(self): """ Slot function: Action after the key 'arrow right' is pressed. Go back to 10 seconds ago. """ self.set_position(self.video_slider.value() + 10 * 1000) def mousePressEvent(self, event): """ Slot function: The starting position of the slider is 50. Note: This function still can't not accurately move the slider to the clicked position. """ slider_start_pos = self.video_slider.geometry().topLeft().x() if 42 <= self.height() - event.pos().y() <= 62: position = self.video_slider.minimum() + ( event.pos().x() - slider_start_pos ) / self.video_slider.width() * self.video_duration if position != self.video_slider.sliderPosition(): self.set_position(position) def open_video(self): """ Slot function: Open a video from the file system. """ video_name, _ = QFileDialog.getOpenFileName(self, "Open Movie", QDir.homePath()) self.video_name = video_name if video_name != '': self.video_player.setMedia( QMediaContent(QUrl.fromLocalFile(video_name))) self.button_play.setEnabled(True) self.video_player.play() index = video_name.rfind('/') self.statusbar.showMessage("Info: Playing the video '" + video_name[(index + 1):] + "' ...") def play_video(self): """ Slot function: The slot function for the 'play' button. If the video player is currently paused, then play the video; otherwise, pause the video. """ if self.video_player.state() == QMediaPlayer.PlayingState: self.video_player.pause() else: self.video_player.play() def media_state_changed(self, state): """ Slot function: If the playing state changes, change the icon for the 'play' button. If the video player is currently playing, change the icon to 'pause'; otherwise, change the icon to 'play'. """ if self.video_player.state() == QMediaPlayer.PlayingState: self.button_play.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.button_play.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def position_changed(self, position): """ Slot function: Change the position of the slider. """ self.video_slider.setValue(position) def duration_changed(self, duration): """ Slot function: If the duration of the video changed, change the range of the slider. This slot function is called after opening a video. """ self.video_slider.setRange(0, duration) self.video_duration = duration self.record_start_time = 0 self.record_end_time = 0 def set_position(self, position): """ Slot function: Change the progress of the video. """ self.video_player.setPosition(position) def error_control(self): """ Slot function: If an error occurs while opening the video, this slot function is called. """ self.button_play.setEnabled(False) self.statusbar.showMessage( "Error: An error occurs while opening the video.") def record_start(self): self.record_start_time = self.video_slider.sliderPosition() if self.record_end_time is not None and self.record_end_time != 0 and self.record_start_time > self.record_end_time: self.record_start_time, self.record_end_time = self.record_end_time, self.record_start_time self._show_record_time() def record_end(self): self.record_end_time = self.video_slider.sliderPosition() if self.record_start_time is not None and self.record_start_time > self.record_end_time: self.record_start_time, self.record_end_time = self.record_end_time, self.record_start_time self._show_record_time() def _show_record_time(self): if self.record_start_time is not None and self.record_end_time is not None: self.statusbar.showMessage( "Info: Starting time: ({}), and Ending time: ({}) (Duration: {})." .format(self.record_start_time / 1000, self.record_end_time / 1000, self.video_duration / 1000)) def _check_duration(self): if self.video_name == "": self.statusbar.showMessage("Error: Please open a video first.") elif self.record_start_time == self.record_end_time: self.statusbar.showMessage("Error: Duration can NOT be 0.") elif self.record_start_time > self.record_end_time: self.statusbar.showMessage( "Error: The start time should be earlier than the end time.") else: return True return False def record_subclip_video(self): if self._check_duration(): self.statusbar.showMessage( "Info: Please wait until the process ends.") self.thread = Thread() self.thread.set_params(Thread.MSG_CUT_VIDEO, self.video_name, self.record_start_time / 1000, self.record_end_time / 1000, self.combobox_degree.currentText()) self.thread.signal_return_value.connect(self.thread_done) self.thread.start() def record_subclip_audio(self): if self._check_duration(): self.statusbar.showMessage( "Info: Please wait until the process ends.") self.thread = Thread() self.thread.set_params(Thread.MSG_EXTRACT_AUDIO, self.video_name, self.record_start_time / 1000, self.record_end_time / 1000) self.thread.signal_return_value.connect(self.thread_done) self.thread.start() def record_clear(self): self.record_start_time = 0 self.record_end_time = 0 self.statusbar.showMessage( "Info: Starting time: ({}), and Ending time: ({}).".format( self.record_start_time, self.record_end_time)) def thread_done(self, return_value, video_name): if return_value: self.statusbar.showMessage( "Info: The process has done and saved as {}.".format( video_name))
class MainWindow(ui_mainwindow, qtbaseclass): # 详情页面 detail = None # 播放列表dock栏,初始隐藏 playListDockView = None # 当前播放列表 playList = [] # 当前播放的歌曲在列表中的索引号 songIndex = 0 # 当前播放的歌曲 song = None # 播放器 player = None # api func = netease # 是否循环播放 loop = True # 记录上次音量值 lastVolume = 0 def __init__(self, parent=None): if parent == None: parent = self ui_mainwindow.__init__(parent) qtbaseclass.__init__(parent) self.setupUi(self) self.setWindowTitle("Music") self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.setWindowIcon(QIcon('resource/format.ico')) with open('QSS/mainWindow.qss', 'r') as f: style = f.read() self.setStyleSheet(style) # 初始化 self.initList() self.initPlayWidgets() self.initTabWidgets() self.initDetailView() self.initPlayListDockView() def initList(self): # 初始化列表信息 # 设置推荐列表 self.recommandList.addItem( QListWidgetItem(QIcon('resource/music.png'), " 发现音乐")) self.recommandList.addItem( QListWidgetItem(QIcon('resource/signal.png'), " 私人FM")) self.recommandList.addItem( QListWidgetItem(QIcon('resource/movie.png'), " MV")) self.recommandList.setCurrentRow(0) # 设置我的音乐 self.myList.addItem( QListWidgetItem(QIcon('resource/notes.png'), " 本地音乐")) # 设置收藏与创建的歌单 # 未实现(动态添加) def initPlayWidgets(self): ''' 初始化播放控件状态''' self.player = QMediaPlayer(self) # self.player.setVolume(100) # 设置音量同时设置进度条 self.volumeSlider.setValue(100) self.player.stateChanged.connect(self.slot_player_stateChanged) self.player.positionChanged.connect(self.slot_player_positionChanged) self.player.durationChanged.connect(self.slot_player_durationChanged) # 隐藏暂停按键 self.pauseButton.hide() self.noVolume.hide() def initTabWidgets(self): # 初始化主窗口中TabWdidget self.detailView.hide() self.tabWidget.clear() netEase = SongsFrame(self) self.tabWidget.addTab(netEase, '网易云音乐') def initDetailView(self): # 初始化详情页 self.detail = AlbumDetailView(self) self.detailView.setWidget(self.detail) self.detail.addSongs.connect(self.slot_addSongs) def initPlayListDockView(self): # 主显示区域添加播放列表DOCK self.playListDockView = PlayListDockWidget(self) self.playListDockView.hide() # 初始状态为隐藏 self.playListDockView.doubleClicked.connect( self.slot_playList_doubleClicked) self.mainHorizontalLayout.addWidget(self.playListDockView) def mouseMoveEvent(self, event): if event.buttons() == QtCore.Qt.MiddleButton: # if event.globalPos().x() > self.pos().x(): # print("Y") # else: # print('N') self.move(event.globalPos()) event.accept() else: super().mouseMoveEvent(event) def slot_prev_page_clicked(self): '''上一页''' if self.tabWidget.isHidden(): self.tabWidget.show() self.detailView.hide() def slot_next_page_clicked(self): '''下一页''' # if self.detailView.isHidden(): # self.tabWidget.hide() # self.detailView.show() pass def slot_prev_song_clicked(self): '''上一首歌''' self.player.stateChanged.disconnect() self.songIndex = self.songIndex - 1 if self.songIndex < 0: self.songIndex = 0 else: self.song = self.playList[self.songIndex] if self.set_player_media(): self.player.play() self.playListDockView.setSelectRow(self.songIndex) self.player.stateChanged.connect(self.slot_player_stateChanged) def slot_next_song_clicked(self): '''下一首歌''' self.player.stateChanged.disconnect() self.songIndex = (self.songIndex + 1) % len(self.playList) self.song = self.playList[self.songIndex] if self.set_player_media(): self.player.play() self.playListDockView.setSelectRow(self.songIndex) self.player.stateChanged.connect(self.slot_player_stateChanged) def slot_play_clicked(self): '''播放 点击事件''' if self.player.mediaStatus() > 1 and self.player.mediaStatus() < 7: self.player.play() else: # 未添加 音乐 QMessageBox.warning(self, '警告', '播放列表为空!请先添加音乐到播放列表。') def slot_pause_clicked(self): '''暂停 点击事件''' self.player.pause() # self.playButton.show() # self.pauseButton.hide() def slot_addSongs(self, songsList): '''添加歌曲''' # 去重合并列表 ids = [x.id for x in self.playList] for song in songsList: if song.id not in ids: self.playList.append(song) # 播放列表变化,更新列表显示 self.playListDockView.setList(self.playList) # 初始化song if self.song == None: self.song = self.playList[self.songIndex] self.set_player_media() def slot_player_stateChanged(self): '''播放器状态变化''' if not self.playList: return if self.player.state() == QMediaPlayer.StoppedState: if self.loop: self.songIndex = (self.songIndex + 1) % len(self.playList) self.song = self.playList[self.songIndex] if self.set_player_media(): self.player.play() else: self.playButton.show() self.pauseButton.hide() elif self.player.state() == QMediaPlayer.PausedState: self.playButton.show() self.pauseButton.hide() elif self.player.state() == QMediaPlayer.PlayingState: self.playButton.hide() self.pauseButton.show() self.countTime.setText(self.song.time) def slot_player_positionChanged(self, pos): '''播放时间改变控件位置''' t = pos / 1000 mins = t // 60 secs = t % 60 curTime = QtCore.QTime(0, mins, secs).toString('mm:ss') self.currentTime.setText(curTime) self.timeSlider.setValue(pos) def slot_player_durationChanged(self, duration): '''设置进度条最大值''' self.timeSlider.setRange(0, duration) def set_player_media(self): '''设置播放器音乐媒体,成功返回True,否则False''' try: mp3 = self.func.singsUrl([self.song.id]) if mp3: mp3 = mp3[0]['url'] self.player.setMedia(QMediaContent(QtCore.QUrl(mp3))) return True except: # 网络异常 QMessageBox.warning(self, '获取音乐地址失败!请检查网络后重试!', '警告') return False def slot_playList_clicked(self): '''播放列表按钮 点击事件''' if self.playListDockView.isHidden(): self.playListDockView.show() else: self.playListDockView.hide() def slot_playList_doubleClicked(self, songIndex): '''播放列表双击事件 songIndex -- 为当前双击歌曲在列表中的索引号。 执行动作:立即播放该歌曲 ''' self.songIndex = songIndex if self.set_player_media(): self.player.play() def slot_volumeSlider_valueChanged(self, value): '''音量调节''' self.player.setVolume(value) if value == 0: self.noVolume.show() self.volume.hide() else: self.noVolume.hide() self.volume.show() def slot_noVolume_clicked(self): '''静音按钮点击事件,动作:切成原始音量''' # self.volumeSlider.setValue(0) self.player.setMuted(False) self.noVolume.hide() self.volume.show() def slot_volume_clicked(self): '''音量按钮点击事件,动作:切成静音''' # self.volumeSlider.setValue(0) self.player.setMuted(True) self.noVolume.show() self.volume.hide()
class MainWindow(QMainWindow): def __init__(self, height, width, amount_mines, parent=None): super(MainWindow, self).__init__(parent) uic.loadUi(Path(__file__).parent / "ui" / "main_window.ui", self) # Sounds self.sound_beginner_mode = str( Path(__file__).parent / "sounds" / "beginner_mode.wav") self.sound_intermediate_mode = str( Path(__file__).parent / "sounds" / "intermediate_mode.wav") self.sound_expert_mode = str( Path(__file__).parent / "sounds" / "expert_mode.wav") self.sound_beginner_win = str( Path(__file__).parent / "sounds" / "beginner_win.wav") self.sound_intermediate_win = str( Path(__file__).parent / "sounds" / "intermediate_win.wav") self.sound_expert_win = str( Path(__file__).parent / "sounds" / "expert_win.wav") self.sound_flag = str(Path(__file__).parent / "sounds" / "flag.wav") self.sound_no_flag = str( Path(__file__).parent / "sounds" / "no_flag.wav") self.sound_reset = str( Path(__file__).parent / "sounds" / "reset_game.wav") self.sound_click = str(Path(__file__).parent / "sounds" / "click.wav") self.sound_boom = str(Path(__file__).parent / "sounds" / "boom.wav") self.sound_bye = str(Path(__file__).parent / "sounds" / "bye.wav") self.sound_donate = str( Path(__file__).parent / "sounds" / "donate.wav") # Qt: connect reset button self.pushButton_reset.clicked.connect(self.on_reset_clicked) self.pushButton_beginner.clicked.connect(self.change_to_beginner_mode) self.pushButton_intermediate.clicked.connect( self.change_to_intermediate_mode) self.pushButton_expert.clicked.connect(self.change_to_expert_mode) self.actionSupport_Tutor_Exilius.triggered.connect( self.open_twitch_support_page) self.action_About_Qt.triggered.connect(self.on_about_qt) self.height = height self.width = width self.amount_mines = amount_mines self.minesweeper = None self.current_mode = GameMode.BEGINNER # Media Player - to play bye.wav synchronously self.player = QMediaPlayer() self.player.setVolume(100) # Timer self.timer = QTimer() self.timer.timeout.connect(self.update_lcd_timer) self.initial_clicked = False palette = self.lcdNumber_amount_mines.palette() palette.setColor(palette.WindowText, QtGui.QColor(255, 0, 0)) palette.setColor(palette.Light, QtGui.QColor(255, 0, 0)) palette.setColor(palette.Dark, QtGui.QColor(255, 0, 0)) self.lcdNumber_amount_mines.setPalette(palette) self.lcdNumber_playing_time.setPalette(palette) self.reset() def playsound(self, sound_file): try: print("Play sound:", sound_file) if sound_file == self.sound_bye: self.player.setMedia( QMediaContent(QUrl.fromLocalFile(sound_file))) self.player.play() else: QSound.play(sound_file) except Exception as e: print("Played too fast?") print(e) def closeEvent(self, event): # small hack :) # DO FIRST: link next close event to self.force_closeEvent(..) self.closeEvent = self.force_closeEvent # end of playing 'self.sound_bye' will occure next close() # --> self.force_closeEvent(..) will be called self.player.stateChanged.connect(self.on_bye_played) self.playsound(self.sound_bye) event.ignore() def force_closeEvent(self, event): event.accept() def on_bye_played(self, state): if state == QMediaPlayer.StoppedState: self.close() def on_reset_clicked(self): self.reset() self.playsound(self.sound_reset) def on_about_qt(self): QMessageBox.aboutQt(self) def change_to_beginner_mode(self): self.current_mode = GameMode.BEGINNER self.height = 8 self.width = 8 self.amount_mines = 10 self.reset() self.playsound(self.sound_beginner_mode) def change_to_intermediate_mode(self): self.current_mode = GameMode.INTERMEDIATE self.height = 16 self.width = 16 self.amount_mines = 40 self.reset() self.playsound(self.sound_intermediate_mode) def change_to_expert_mode(self): self.current_mode = GameMode.EXPERT self.height = 16 self.width = 32 self.amount_mines = 99 self.reset() self.playsound(self.sound_expert_mode) def start_game_timer(self): self.timer.start(1000) def stop_game_timer(self): self.timer.stop() def update_lcd_timer(self): value = self.lcdNumber_playing_time.intValue() self.lcdNumber_playing_time.display(value + 1) def initialise_field(self): self.clear_layout(self.gridLayout) button_size = (40, 40) font = QFont() font.setPointSize(15) font.setBold(False) if self.current_mode == GameMode.INTERMEDIATE: font.setPointSize(11) button_size = (32, 32) elif self.current_mode == GameMode.EXPERT: font.setPointSize(11) button_size = (32, 32) for h in range(self.height): for w in range(self.width): button = QPushButton() button.setFixedSize(button_size[0], button_size[1]) button.setFont(font) button.meta = (h, w) button.mouseReleaseEvent = functools.partial( self.on_mouse_release_event, button) button.mousePressEvent = functools.partial( self.on_mouse_press_event, button) button.maybe_mine = False button.pressed = False button.paired_cell = self.minesweeper.field[h][w] self.gridLayout.addWidget(button, h, w) self.minesweeper.field[h][w].paired_button = button # resizing this way doesn't work. self.setFixedSize(self.sizeHint()) QTimer.singleShot(0, lambda: self.setFixedSize(self.sizeHint())) # see: https://forum.qt.io/topic/4500/resize-top-level-window-to-fit-contents/4 def on_mouse_press_event(self, button, ev): cell_visible = button.paired_cell.visible if not cell_visible and not button.maybe_mine and not button.pressed: # and ev.button() == PyQt5.QtCore.Qt.LeftButton: button.pressed = True button.setStyleSheet("border: 3px inset #aaa;") def on_mouse_release_event(self, button, ev): h, w = button.meta cell_visible = button.paired_cell.visible expected_amount_mines_in_area = button.paired_cell.amount.value if ev.button() == PyQt5.QtCore.Qt.LeftButton: if not cell_visible and not button.maybe_mine and button.pressed: button.pressed = False button.setStyleSheet("border: 0px") self.playsound(self.sound_click) if cell_visible and self.all_mines_in_area_marked( expected_amount_mines_in_area, (h, w)): # todo: implement step_in_all_fields_area() self.step_in_neighbors((h, w)) elif not button.maybe_mine: self.step_in(*button.meta) elif ev.button() == PyQt5.QtCore.Qt.RightButton: # ignore visible fields if not button.paired_cell.visible: if button.maybe_mine: self.playsound(self.sound_no_flag) button.setStyleSheet("") button.setText("") self.increment_mines_lcd() button.maybe_mine = not button.maybe_mine else: if self.decrement_mines_lcd(): self.playsound(self.sound_flag) button.setStyleSheet( "border: 1px solid black; background-color: #efefef;" ) button.setText("🚩") button.maybe_mine = not button.maybe_mine else: button.setStyleSheet("") ev.accept() def all_mines_in_area_marked(self, expected_amount_mines_in_area, pos): mines_in_area = self.minesweeper.on_neighbors(pos, lambda pos: None) print("marked:", mines_in_area) return mines_in_area == expected_amount_mines_in_area def step_in_neighbors(self, pos): # pass # not implemented yet self.minesweeper.step_in_neighbors(pos) def increment_mines_lcd(self): value = self.lcdNumber_amount_mines.intValue() self.lcdNumber_amount_mines.display(value + 1) def decrement_mines_lcd(self): value = self.lcdNumber_amount_mines.intValue() if value > 0: self.lcdNumber_amount_mines.display(value - 1) return True else: return False def clear_layout(self, layout): while layout.count(): child = layout.takeAt(0) if child.widget(): child.widget().deleteLater() def start(self, initial_click_pos): self.start_game_timer() self.minesweeper.start(initial_click_pos) def reset(self): self.minesweeper = Game(self, self.height, self.width, self.amount_mines) self.lcdNumber_amount_mines.display(self.amount_mines) self.initial_clicked = False self.initialise_field() self.enable_field() self.stop_game_timer() self.lcdNumber_playing_time.display(0) self.pushButton_reset.setText("😊") def step_in(self, h, w): try: if not self.initial_clicked: self.start((h, w)) self.initial_clicked = True else: self.minesweeper.step_in(h, w) self.update_ui() except Exception as e: print(e) def update_ui(self): field = self.minesweeper.field for h in range(self.minesweeper.field_height): for w in range(self.minesweeper.field_width): if field[h][w].visible: text = str(field[h][w].amount.value) if text == "9": text = "💣" elif text == "0": text = "" field[h][w].paired_button.setStyleSheet( "border: 1px solid #333") # field[h][w].paired_button.setVisible(False) else: field[h][w].paired_button.setStyleSheet( "border: 1px solid #333") field[h][w].paired_button.setText(text) if self.minesweeper.won(): if self.current_mode == GameMode.BEGINNER: self.playsound(self.sound_beginner_win) elif self.current_mode == GameMode.INTERMEDIATE: self.playsound(self.sound_intermediate_win) else: self.playsound(self.sound_expert_win) self.pushButton_reset.setText("😁") self.stop_game_timer() # self.show_message_box("Finished", "You WON!") self.disable_field() def game_over(self): self.playsound(self.sound_boom) self.pushButton_reset.setText("😵") self.stop_game_timer() # self.show_message_box("Finished", "GAME OVER :(") self.disable_field() def disable_field(self): for h in range(self.minesweeper.field_height): for w in range(self.minesweeper.field_width): self.minesweeper.field[h][w].paired_button.setEnabled(False) def enable_field(self): for h in range(self.minesweeper.field_height): for w in range(self.minesweeper.field_width): self.minesweeper.field[h][w].paired_button.setEnabled(True) def show_message_box(self, title, text): msg = QMessageBox(self) msg.setWindowTitle(title) msg.setText(text) msg.exec_() def open_twitch_support_page(self): self.playsound(self.sound_donate) webbrowser.open("https://streamlabs.com/tutorexilius")
class Controller: def __init__(self, view, log): self.log = log self.view = view self._player = QMediaPlayer() self._player.mediaStatusChanged.connect(self._player_status_changed) self._player.mediaChanged.connect(self._player_media_changed) self._player.currentMediaChanged.connect(self._player_current_media_changed) self._player.stateChanged.connect(self._player_state_changed) self._player.positionChanged.connect(self._player_position_changed) self._player.durationChanged.connect(self._player_duration_changed) self._searched_tracks = [] self.playlists = [] self.playing_playlist = 0 self.last_colored_item = None def _player_status_changed(self, status): self.log.debug('_player_status_changed: %s', str(status)) if status in [QMediaPlayer.EndOfMedia, QMediaPlayer.InvalidMedia]: self.next() if status in [QMediaPlayer.EndOfMedia, QMediaPlayer.NoMedia, QMediaPlayer.UnknownMediaStatus, QMediaPlayer.InvalidMedia]: self.view.set_title() else: try: pos = self.playlists[self.playing_playlist].active_track if pos >= 0: track = self.playlists[self.playing_playlist].tracks[pos] self.view.set_title(track.title) self.update_list_position(pos) except IndexError: self.log.error('Index error in _player_status_changed') def _player_media_changed(self, media): self.log.debug('_player_media_changed: %s' % str(media)) def _player_current_media_changed(self, media): self.log.debug('_player_current_media_changed: %s' % str(media)) def _player_state_changed(self, state): self.log.debug('_player_state_changed: %s' % str(state)) def _player_duration_changed(self, duration): self.log.debug('_player_duration_changed: %s' % str(duration)) self.view.track_position.setMaximum(duration) def _player_position_changed(self, pos): self.view.track_position.setValue(pos) def volume_changed(self, value): self._player.setVolume(value) def update_status(self): total_duration = 0 playlist_index = self.view.tabs.currentIndex() for track in self.playlists[playlist_index].tracks: total_duration += track.duration self.view.playlist_status.setText("%i tracks. Total duration %i:%02i:%02i:%02i" % (self.playlists[playlist_index].count(), total_duration // 86400, total_duration // 3600 % 24, total_duration // 60 % 60, total_duration % 60)) def add_track(self, track, playlist_index=None): if playlist_index is None: playlist_index = self.view.tabs.currentIndex() self.playlists[playlist_index].add(track) self.view.tabs.widget(playlist_index).addItem(track.title) def remove_track(self, track_pos=None): if track_pos is None: track_pos = self.view.tabs.currentWidget().currentRow() if track_pos != -1: self.view.tabs.currentWidget().takeItem(track_pos) playlist_index = self.view.tabs.currentIndex() self.playlists[playlist_index].remove(track_pos) self.update_status() def remove_all_tracks(self): playlist_index = self.view.tabs.currentIndex() self.playlists[playlist_index].clear() self.view.tabs.currentWidget().clear() self.update_status() def next(self): self.log.debug('next') # if we close last tab with current track, after it ended, we stop playing # todo: need check, that if we close not last tab with current song, we also need stop after song ended if self.playing_playlist >= len(self.playlists): return next_pos = self.playlists[self.playing_playlist].get_next_track(shuffle=bool(self.view.shuffle.checkState())) if next_pos is not None: self.playlists[self.playing_playlist].active_track = next_pos url = self.playlists[self.playing_playlist].tracks[next_pos].stream_url() self._player.setMedia(QMediaContent(QUrl(url))) self.play() def previous(self): self.log.debug('previous') prev_pos = self.playlists[self.playing_playlist].get_prev_track(shuffle=bool(self.view.shuffle.checkState())) if prev_pos is not None: self.playlists[self.playing_playlist].active_track = prev_pos url = self.playlists[self.playing_playlist].tracks[prev_pos].stream_url() self._player.setMedia(QMediaContent(QUrl(url))) self.play() def play(self): self.log.debug('play') self._player.play() def pause(self): self.log.debug('pause') self._player.pause() def update_list_position(self, position): showed_list = self.view.tabs.currentWidget() if self.last_colored_item: self.last_colored_item.setBackground(QBrush()) if (position >= 0) and (position <= showed_list.count()): self.last_colored_item = showed_list.item(position) self.last_colored_item.setBackground(QBrush(QColor('red'))) def change_track(self): self.log.debug('change_track') playlist_index = self.view.tabs.currentIndex() self.playing_playlist = playlist_index position = self.view.tabs.currentWidget().currentRow() self.playlists[self.playing_playlist].active_track = position self.log.debug('position: %i' % position) url = self.playlists[self.playing_playlist].tracks[position].stream_url() self._player.setMedia(QMediaContent(QUrl(url))) if self._player.state() in [QMediaPlayer.StoppedState, QMediaPlayer.PausedState]: self.play() def change_track_position(self): self._player.setPosition(self.view.track_position.value()) def remove_dublicates(self): selected_playlist = self.view.tabs.currentIndex() playlist = self.playlists[selected_playlist] processed_ids = [] position_for_removing = [] for index in range(len(playlist.tracks)): if playlist.tracks[index].id in processed_ids: position_for_removing.append(index) else: processed_ids.append(playlist.tracks[index].id) self.log.debug('tracks count: %i' % len(playlist.tracks)) counter = 0 for index in reversed(position_for_removing): self.log.debug('track index for removing: %i' % index) self.remove_track(track_pos=index) counter += 1 self.log.info('Removed %i tracks.' % counter) def save_track(self, playlist_pos=None, track_pos=None): if track_pos is None: track_pos = self.view.tabs.currentWidget().currentRow() if playlist_pos is None: playlist_pos = self.view.tabs.currentIndex() playlist = self.playlists[playlist_pos] track = playlist.tracks[track_pos] track.save() def download_playlist(self): selected_playlist = self.view.tabs.currentIndex() playlist = self.playlists[selected_playlist] for track_pos in range(playlist.count()): self.log.info('Saving %i/%s track...' % (track_pos+1, playlist.count())) self.save_track(playlist_pos=selected_playlist, track_pos=track_pos) self.log.info('Saving done.') def load_playlist(self): playlist_index = self.view.tabs.currentIndex() playlist = self.playlists[playlist_index] loaded_playlist = sc_load_playlist(playlist.name) if not loaded_playlist: self.log.error('Playlist not exists.') return self.remove_all_tracks() for track in loaded_playlist: self.add_track(track) self.update_status() def save_playlist(self): playlist_index = self.view.tabs.currentIndex() playlist = self.playlists[playlist_index] sc_save_playlist(playlist.name, playlist) def add_playlist(self, name): self.playlists.append(Playlist(name)) def remove_playlist(self, index): self.log.debug('remove playlist with index = %i' % index) del (self.playlists[index]) def search_tracks(self): self.view.search_list.clear() tracks = sc_search_tracks(self.view.input.text()) self._searched_tracks = tracks total_duration = 0 for track in self._searched_tracks: self.view.search_list.addItem(track.title) total_duration += track.duration self.view.search_status.setText("Founded %i tracks. Total duration %i:%02i:%02i:%02i" % (len(self._searched_tracks), total_duration // 86400000, total_duration // 3600000 % 24, total_duration // 60000 % 60, total_duration // 1000 % 60)) def search_similar(self): self.view.search_list.clear() position = self.view.tabs.currentWidget().currentRow() playlist_index = self.view.tabs.currentIndex() track = self.playlists[playlist_index].tracks[position] related_tracks = track.search_related() self._searched_tracks = related_tracks total_duration = 0 for track in self._searched_tracks: self.view.search_list.addItem(track.title) total_duration += track.duration self.view.search_status.setText("Founded %i tracks. Total duration %i:%02i:%02i:%02i" % (len(self._searched_tracks), total_duration // 86400000, total_duration // 3600000 % 24, total_duration // 60000 % 60, total_duration // 1000 % 60)) def clicked_add_track(self): position = self.view.search_list.currentRow() self.add_track(self._searched_tracks[position]) def clicked_add_all_tracks(self): for row in range(self.view.search_list.count()): self.add_track(self._searched_tracks[row]) def load_current_state(self): if not os.path.isfile('state.pickle'): return f = open('state.pickle', 'rb') state = pickle.load(f) f.close() loaded_playlists = state['playlists'] self.log.debug('loaded %i playlists.' % len(loaded_playlists)) for i in range(len(loaded_playlists) - len(self.playlists)): self.view.tab_add() self.playlists.clear() index = 0 for playlist in loaded_playlists: self.log.debug('playlist: %s, len: %i' % (playlist.name, len(playlist.tracks))) self.add_playlist(playlist.name) for track in playlist.tracks: self.add_track(track, playlist_index=index) index += 1 self.log.debug(len(self.playlists)) self.log.debug('curent tab: %i' % state['current_playlist']) self.view.tabs.setCurrentIndex(state['current_playlist']) self.log.debug('volume: %i' % state['volume']) self.view.volume.setValue(state['volume']) self.view.shuffle.setCheckState(state['shuffle']) def save_current_state(self): state = dict() self.log.debug('playlists count: %i' % len(self.playlists)) state['playlists'] = self.playlists state['current_playlist'] = self.view.tabs.currentIndex() state['volume'] = self.view.volume.value() state['shuffle'] = self.view.shuffle.checkState() f = open('state.pickle', 'wb') pickle.dump(state, f) f.close()
class videoPlayer(QWidget): # 视频播放类 def __init__(self, titleName): # 构造函数 super(videoPlayer, self).__init__() # 类的继承 self.length = 0 # 视频总时长 self.position = 0 # 视频当前时长 self.count = 0 self.player_status = -1 # 设置窗口 self.setGeometry(300, 50, 1200, 800) #大小,与桌面放置位置 self.setWindowIcon(QIcon(':/images/video_player_icon.png')) # 程序图标 self.setWindowTitle(titleName) # 窗口名称 self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint) # 设置窗口背景 self.palette = QPalette() self.palette.setColor(QPalette.Background, Qt.black) self.setPalette(self.palette) self.now_position = QLabel("/ 00:00") # 目前时间进度 self.all_duration = QLabel('00:00') # 总的时间进度 self.all_duration.setStyleSheet('''QLabel{color:#ffffff}''') self.now_position.setStyleSheet('''QLabel{color:#ffffff}''') #视频插件 self.video_widget = QVideoWidget(self) self.video_widget.setGeometry(QRect(0, 0, 1200, 700)) #大小,与桌面放置位置 #self.video_widget.resize(1200, 700) # 设置插件宽度与高度 #self.video_widget.move(0, 30) # 设置插件放置位置 self.video_palette = QPalette() self.video_palette.setColor(QPalette.Background, Qt.black) # 设置播放器背景 self.video_widget.setPalette(self.video_palette) video_widget_color="background-color:#000000" self.video_widget.setStyleSheet(video_widget_color) #布局容器 self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(0) #self.verticalLayout.setContentsMargins(0, 5, 0, 10) self.layout = QHBoxLayout() self.layout.setSpacing(15) # 各个插件的间距 # 设置播放器 self.player = QMediaPlayer(self) self.player.setVideoOutput(self.video_widget) #设置播放按钮事件 self.player.durationChanged.connect(self.get_duration_func) self.player.positionChanged.connect(self.progress) # 媒体播放时发出信号 self.player.mediaStatusChanged.connect(self.playerStatusChanged) self.player.error.connect(self.player_error) # 播放按钮 self.play_btn = QPushButton(self) self.play_btn.setIcon(QIcon(':/images/play_btn_icon.png')) # 设置按钮图标,下同 self.play_btn.setIconSize(QSize(35,35)) self.play_btn.setStyleSheet('''QPushButton{border:none;}QPushButton:hover{border:none;border-radius:35px;}''') self.play_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.play_btn.setToolTip("播放") self.play_btn.setFlat(True) #self.play_btn.hide() #isHidden() #判定控件是否隐藏 #isVisible() 判定控件是否显示 self.play_btn.clicked.connect(self.start_button) #音量条 self.volume_slider = QSlider(Qt.Horizontal) # 声音设置 self.volume_slider.setMinimum(0) # 音量0到100 self.volume_slider.setMaximum(100) self.volume_slider.valueChanged.connect(self.volumes_change) self.volume_slider.setStyleSheet('''QSlider{} QSlider::sub-page:horizontal:disabled{background: #00009C; border-color: #999; } QSlider::add-page:horizontal:disabled{background: #eee; border-color: #999; } QSlider::handle:horizontal:disabled{background: #eee; border: 1px solid #aaa; border-radius: 4px; } QSlider::add-page:horizontal{background: #575757; border: 0px solid #777; height: 10px;border-radius: 2px; } QSlider::handle:horizontal:hover{background:qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #2A8BDA, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; } QSlider::sub-page:horizontal{background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4); background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,stop: 0 #5DCCFF, stop: 1 #1874CD); border: 1px solid #4A708B; height: 10px; border-radius: 2px; } QSlider::groove:horizontal{border: 1px solid #4A708B; background: #C0C0C0; height: 5px; border-radius: 1px; padding-left:-1px; padding-right:-1px;} QSlider::handle:horizontal{background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #45ADED, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; }''') #视频播放进度条 self.video_slider = QSlider(Qt.Horizontal, self) # 视频进度拖拖动 self.video_slider.setMinimum(0) # 视频进度0到100% #self.video_slider.setMaximum(100) self.video_slider.setSingleStep(1) self.video_slider.setGeometry(QRect(0, 0, 200, 10)) self.video_slider.sliderReleased.connect(self.video_silder_released) self.video_slider.sliderPressed.connect(self.video_silder_pressed) self.video_slider.setStyleSheet('''QSlider{} QSlider::sub-page:horizontal:disabled{background: #00009C; border-color: #999; } QSlider::add-page:horizontal:disabled{background: #eee; border-color: #999; } QSlider::handle:horizontal:disabled{background: #eee; border: 1px solid #aaa; border-radius: 4px; } QSlider::add-page:horizontal{background: #575757; border: 0px solid #777; height: 10px;border-radius: 2px; } QSlider::handle:horizontal:hover{background:qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #2A8BDA, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; } QSlider::sub-page:horizontal{background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4); background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,stop: 0 #5DCCFF, stop: 1 #1874CD); border: 1px solid #4A708B; height: 10px; border-radius: 2px; } QSlider::groove:horizontal{border: 1px solid #4A708B; background: #C0C0C0; height: 5px; border-radius: 1px; padding-left:-1px; padding-right:-1px;} QSlider::handle:horizontal{background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0.6 #45ADED, stop:0.778409 rgba(255, 255, 255, 255)); width: 11px; margin-top: -3px; margin-bottom: -3px; border-radius: 5px; }''') #静音按钮 self.mute_button = QPushButton('') self.mute_button.clicked.connect(self.mute) self.mute_button.setIconSize(QSize(30,30)) self.mute_button.setStyleSheet('''QPushButton{border:none;}QPushButton:hover{border:none;}''') self.mute_button.setCursor(QCursor(Qt.PointingHandCursor)) self.mute_button.setToolTip("播放") self.mute_button.setFlat(True) self.mute_button.setIcon(QIcon(':/images/sound_btn_icon.png')) #暂停按钮 self.pause_btn = QPushButton('') self.pause_btn.setIcon(QIcon(':/images/stop_btn_icon.png')) self.pause_btn.clicked.connect(self.stop_button) self.pause_btn.setIconSize(QSize(35,35)) self.pause_btn.setStyleSheet('''QPushButton{border:none;}QPushButton:hover{border:none;}''') self.pause_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.pause_btn.setToolTip("播放") self.pause_btn.setFlat(True) self.pause_btn.hide() #音量值和音量显示标签 self.volume_value = QLabel() self.volume_value.setText(' ' * 5) self.volume_value.setStyleSheet('''QLabel{color:#ffffff;}''') self.volume_t = QLabel() self.volume_t.setStyleSheet('''QLabel{color:#ffffff;}''') #视频文件打开按钮 self.open_btn = QPushButton('Open') self.open_btn.clicked.connect(self.getfile) #全屏按钮 self.screen_btn = QPushButton('') self.screen_btn.setIcon(QIcon(QPixmap(':/images/fullsrceen_btn_icon.png'))) self.screen_btn.setIconSize(QSize(38,38)) self.screen_btn.setStyleSheet('''QPushButton{border:none;}QPushButton:hover{border:1px solid #F3F3F5;border-radius:35px;}''') self.screen_btn.setCursor(QCursor(Qt.PointingHandCursor)) self.screen_btn.setToolTip("播放") self.screen_btn.setFlat(True) self.screen_btn.clicked.connect(self.fullscreen) #添加按钮组件 self.verticalLayout.addStretch() self.layout.addWidget(self.play_btn, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.pause_btn, 0, Qt.AlignCenter | Qt.AlignVCenter) # 插件,与前一个模块的距离,位置 self.layout.addWidget(self.all_duration,0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.now_position, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.video_slider, 15, Qt.AlignVCenter | Qt.AlignVCenter) self.layout.addWidget(self.mute_button , 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.volume_slider, 0, Qt.AlignCenter | Qt.AlignVCenter) self.layout.addWidget(self.volume_value, 0, Qt.AlignCenter | Qt.AlignVCenter) #self.layout.addWidget(self.screen_btn) #self.layout.addWidget(self.open_btn) self.verticalLayout.addLayout(self.layout) #self.verticalLayout.addLayout(self.layout) self.setLayout(self.verticalLayout) def player_error(self, errorCode): print('error = ' + str(errorCode)) try: if errorCode == 0: pass elif errorCode == 1: self.showAlertWindow('errorCode:1 \n\n无效视频源。') elif errorCode == 2: self.showAlertWindow('errorCode:2 \n\n不支持的媒体格式') elif errorCode == 3: self.showAlertWindow('errorCode:3 \n\n网络错误') elif errorCode == 4: self.showAlertWindow('errorCode:4 \n\n没有权限播放该视频') elif errorCode == 5: self.showAlertWindow('errorCode:5 \n\n视频服务不存在,无法继续播放。') else: self.showAlertWindow('未知错误') except: self.showAlertWindow('视频加载异常') def video_silder_pressed(self): if self.player.state != 0: self.player.pause() def playerStatusChanged(self, status): self.player_status = status if status == 7: self.play_btn.show() self.pause_btn.hide() #print('playerStatusChanged =' + str(status) + '...............') def resizeEvent(self, e): #print(e.size().width(), e.size().height()) newSize = e.size() self.video_widget.setGeometry(0, 0, newSize.width(), newSize.height() - 50) #self.video_widget.setGeometry(0, 0, 0, 0) def closeEvent(self, e): self.player.stop() def get_duration_func(self, d): try: end_number = int(d / 1000 / 10) + 1 #print('end_number = ' + str(end_number)) sum = 0 for n in range (1,end_number): sum = sum + n vv = int((100 / (d / 1000)) * (d / 1000)) self.video_slider.setMaximum(d) #self.video_slider.setMaximum(vv + sum) #print(100 + sum) all_second = int(d / 1000 % 60) # 视频播放时间 all_minute = int(d / 1000 / 60) if all_minute < 10: if all_second < 10: self.all_duration.setText('0' + str(all_minute) + ':0' + str(all_second)) else: self.all_duration.setText('0' + str(all_minute) + ':' + str(all_second)) else: if all_second < 10: self.all_duration.setText(str(all_minute) + ':0' + str(all_second)) else: self.all_duration.setText(str(all_minute) + ':' + str(all_second)) except Exception as e: pass def mouseDoubleClickEvent(self, e): try: #print('mouseDoubleClickEvent................... = ' + str(self.player.state())) if self.player.state() == 2: #视频暂停 self.player.play() self.play_btn.hide() self.pause_btn.show() elif self.player.state() == 1: # 正在播放 self.player.pause() self.play_btn.show() self.pause_btn.hide() else: #视频停止 self.play_btn.hide() self.pause_btn.show() self.player.setPosition(0) self.video_slider.setValue(0) self.player.play() except Exception as e: pass def start_button(self): # 视频播放按钮 try: self.play_btn.hide() self.pause_btn.show() if self.player_status == 7: self.video_slider.setValue(0) self.player.setPosition(0) self.player.play() except Exception as e: pass def stop_button(self): # 视频暂停按钮 self.play_btn.show() self.pause_btn.hide() self.player.pause() def getfile(self, filepath): # 打开视频文件 try: #print(str(filepath)) url = QUrl.fromLocalFile(filepath) if url.isValid(): self.player.setMedia(QMediaContent(url)) # 返回该文件地址,并把地址放入播放内容中 self.player.setVolume(50) # 设置默认打开音量即为音量条大小 self.volume_value.setText(str(50)) self.volume_slider.setValue(50) else: self.showAlertWindow('视频地址无效') except Exception as e: self.showAlertWindow() def clearVolumeValue(): self.volume_value.setText(' ' * 5) def volumes_change(self): # 拖动进度条设置声音 try: size = self.volume_slider.value() if size: # 但进度条的值不为0时,此时音量不为静音,音量值即为进度条值 self.player.setMuted(False) self.player.setVolume(size) volume_value = str(size) + ' ' * 4 self.volume_value.setText(volume_value) #print(size) self.mute_button.setIcon(QIcon(':/images/sound_btn_icon.png')) else: self.player.setMuted(True) self.mute_button.setIcon(QIcon(':/images/mute_btn_icon.png')) self.player.setVolume(0) volume_value = '0' + ' ' * 4 self.volume_value.setText(volume_value) if len(str(size)) == 1: volume_value = str(size) + ' ' * 4 elif len(str(size)) == 2: volume_value = str(size)+ ' ' * 3 else: volume_value = str(size) + ' ' * 2 self.volume_value.setText(volume_value) except Exception as e: pass def mute(self): try: if self.player.isMuted(): self.mute_button.setIcon(QIcon(':/images/sound_btn_icon.png')) self.player.setMuted(False) self.volume_slider.setValue(50) volume_value = '50' + ' ' * 4 self.volume_value.setText(volume_value) else: self.mute_button.setIcon(QIcon(':/images/mute_btn_icon.png')) self.player.setMuted(True) # 若不为静音,则设置为静音,音量置为0 self.volume_slider.setValue(0) volume_value = '0' + ' ' * 4 self.volume_value.setText(volume_value) except Exception as e: pass def progress(self): # 视频进度条自动释放与播放时间 try: self.length = self.player.duration() + 1 self.position = self.player.position() #print(str(self.length) + ':' + str(self.position)) self.count += 1 video_silder_maximum = self.video_slider.maximum() #video_silder_value = int(((video_silder_maximum / (self.length / 1000)) * (self.position / 1000))) #self.video_slider.setValue(video_silder_value + self.count) self.video_slider.setValue(self.position) #print('video_slider_value = ' + str(video_silder_value + self.count)) now_second = int(self.position / 1000 % 60) now_minute = int(self.position / 1000 / 60) #print(str(now_minute) + ':' + str(now_second)) if now_minute < 10: if now_second < 10: self.now_position.setText('/ 0' + str(now_minute) + ':0' + str(now_second)) else: self.now_position.setText('/ 0' + str(now_minute) + ':' + str(now_second)) else: #print('now_minute < 10' + str(now_minute) + ':' + str(now_second)) if now_second < 10: #print('now_second < 10' + str(now_minute) + ':' + str(now_second)) #self.now_position.setText(str(now_minute) + ':0' + str(now_second)) self.now_position.setText('/ ' + str(now_minute) + ':0' + str(now_second)) else: #print('now_second > 10' + str(now_minute) + ':' + str(now_second)) self.now_position.setText('/ ' + str(now_minute) + ':' + str(now_second)) except Exception as e: pass def video_silder_released(self): # 释放滑条时,改变视频播放进度 try: #print('video_silder_released......') if self.player.state() != 0: self.player.setPosition(self.video_slider.value()) self.player.play() else: #如果视频是停止状态,则拖动进度条无效 self.video_slider.setValue(0) except Exception as e: pass def fullscreen(self): self.showFullScreen() def keyPressEvent(self, event): # 重新改写按键 if event.key() == Qt.Key_Escape: self.winquit() def winquit(self): # 退出窗口 self.showNormal() def showAlertWindow(self, msg = '视频加载出错!'): reply = QMessageBox.information(self, "消息框标题", msg, QMessageBox.Yes) def setWindowTitleName(self, titleName): self.setWindowTitle(titleName) # 窗口名称
class VideoPlayer(QWidget): def __init__(self, parent=None, mute=True): QWidget.__init__(self, parent) self.ui = Ui_VideoPlayer() self.error_handler = lambda txt: None savecwd = os.getcwd() os.chdir('view/ui') self.ui.setupUi(self) os.chdir(savecwd) self.ui.bn_size.hide() self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) # self.item=QGraphicsVideoItem() # self.ui.mid_frame_grid_layout.addItem(self.item,0,0) # self.media_player.setVideoOutput(self.item) self.media_player_widget = QVideoWidget(self.ui.mid_frame) self.ui.mid_frame_grid_layout.addWidget(self.media_player_widget, 0, 0) self.media_player.setVideoOutput(self.media_player_widget) # self.media_player.stateChanged.connect(self.state_changed) self.media_player.bufferStatusChanged.connect( self.buffer_status_changed) self.media_player.mediaStatusChanged.connect(self.media_status_changed) self.media_player.positionChanged.connect(self.positionChanged) self.media_player.durationChanged.connect(self.durationChanged) self.media_player.error.connect(self.handleError) # self.media_player.metaDataChanged.connect(self.meta_data_changed) self.ui.bn_mute.setChecked(mute) self.mute() self.connect_to_playlist(connected=False, toggle_playlist=lambda: None) self.ui.dial_volume.setFixedWidth(50) # binding self.ui.bn_play.clicked.connect(self.media_player.play) self.ui.bn_pause.clicked.connect(self.media_player.pause) self.ui.bn_mute.clicked.connect(self.mute) self.ui.bn_stop.clicked.connect(self.media_player.stop) self.ui.bn_next.clicked.connect(self.next) self.ui.bn_prev.clicked.connect(self.prev) self.ui.bn_playlist.clicked.connect(self.show_playlist) self.ui.bn_uget.clicked.connect(self.on_uget_pressed) self.ui.progress_slider.sliderMoved.connect( self.media_player.setPosition) # self.ui.spin_volume.valueChanged.connect(self.media_player.setVolume) self.ui.dial_volume.valueChanged.connect(self.media_player.setVolume) self.url = '' self.altermate = list() self.duration = '0:00' self.change_position = None self.uget_handler = lambda fname='', url='': None # self.on_end_of_playing=lambda :None def set_error_handler(self, handler): self.error_handler = handler def icons_set(self, bn, fname_off, fname_on=None): icon = QIcon() icon.addPixmap(QPixmap(fname_off), QIcon.Normal, QIcon.Off) if fname_on is not None: icon.addPixmap(QPixmap(fname_on), QIcon.Normal, QIcon.On) bn.setIcon(icon) def connect_to_playlist(self, connected=False, goto_prev=lambda: None, goto_next=lambda: None, toggle_playlist=None): self.goto_next = goto_next self.goto_prev = goto_prev if toggle_playlist is not None: self.toggle_playlist = toggle_playlist self.connected = connected if self.connected: self.ui.playlist_frame.show() self.ui.bn_add.hide() self.ui.bn_minus.show() else: self.ui.playlist_frame.hide() self.ui.bn_add.show() self.ui.bn_minus.hide() def set_plus_handler(self, handler=lambda: None): self.ui.bn_add.clicked.connect(handler) def set_minus_handler(self, handler=lambda: None): self.ui.bn_minus.clicked.connect(handler) def set_uget_handler(self, handler=lambda fname='', url='': None): self.uget_handler = handler def on_uget_pressed(self, url=None): self.uget_handler(fname=urlparse( url.rstrip('/'))[2].rpartition('/')[2], url=url) def set_url(self, url=''): self.url = url self.altermate = list() self.ui.bn_size.hide() self.media_player.setMedia(QMediaContent(QUrl(url))) uget_menu = QMenu(self) uget_menu_action = QAction('Standart quality', self, triggered=self.get_handler( self.on_uget_pressed, url)) uget_menu.addAction(uget_menu_action) self.ui.bn_uget.setMenu(uget_menu) def change_url(self, url): position = self.media_player.position() self.media_player.stop() self.media_player.setMedia(QMediaContent(QUrl(url))) self.media_player.play() self.change_position = position def add_alternate_url(self, caption='', url=''): self.ui.bn_size.show() self.altermate.append(dict(caption=caption, url=url)) menu = QMenu(self) uget_menu = QMenu(self) for item in self.altermate: menu_action = QAction(item['caption'], self, triggered=self.get_handler( self.change_url, item['url'])) menu.addAction(menu_action) uget_menu_action = QAction(item['caption'], self, triggered=self.get_handler( self.on_uget_pressed, item['url'])) uget_menu.addAction(uget_menu_action) self.ui.bn_size.setMenu(menu) self.ui.bn_uget.setMenu(uget_menu) def get_handler(self, function, arg): return lambda: function(arg) def play(self): self.media_player.play() def pause(self): self.media_player.pause() def stop(self): self.media_player.stop() def next(self): self.goto_next() def prev(self): self.goto_prev() def show_playlist(self): self.toggle_playlist() def mute(self): if self.ui.bn_mute.isChecked(): self.media_player.setMuted(True) else: self.media_player.setMuted(False) self.media_player.setVolume(self.ui.dial_volume.value()) def little_forvard(self, s=30): self.media_player.setPosition(self.media_player.position() + s * 1000) def media_status_changed(self, status): # print('Media status=', status) if status == QMediaPlayer.StalledMedia: self.ui.progress_buffer.show() else: self.ui.progress_buffer.hide() if status == QMediaPlayer.BufferedMedia: if self.change_position is not None: # print('Changing position') self.media_player.setPosition(self.change_position) self.change_position = None if status == QMediaPlayer.EndOfMedia: self.goto_next() def buffer_status_changed(self, status): # print('Buffer status=', status) self.ui.progress_buffer.setValue(status) # def state_changed(self,status): # print('State=', status) def state(self): return self.media_player.state() def positionChanged(self, position): self.ui.progress_slider.setValue(position) self.ui.lbl_time.setText( self.time_format(position) + ' / ' + self.duration) def durationChanged(self, duration): self.ui.progress_slider.setRange(0, duration) self.duration = self.time_format(duration) def time_format(self, ms): dur = ms // 1000 minutes = dur // 60 secundes = dur - minutes * 60 return '%d:%02d' % (minutes, secundes) def handleError(self): print("Error in " + self.url + ': ' + self.media_player.errorString()) self.error_handler('Player error: ' + self.media_player.errorString())
class QgsFmvPlayer(QMainWindow, Ui_PlayerWindow): """ Video Player Class """ def __init__(self, iface, path, parent=None, meta_reader=None, pass_time=None, initialPt=None, isStreaming=False): """ Constructor """ super(QgsFmvPlayer, self).__init__(parent) self.setupUi(self) self.parent = parent self.iface = iface self.fileName = path self.initialPt = initialPt self.meta_reader = meta_reader self.isStreaming = isStreaming self.createingMosaic = False self.currentInfo = 0.0 self.data = None # Create Draw Toolbar self.DrawToolBar.addAction(self.actionMagnifying_glass) self.DrawToolBar.addSeparator() # Draw Polygon QToolButton self.toolBtn_DPolygon.setDefaultAction(self.actionDraw_Polygon) self.DrawToolBar.addWidget(self.toolBtn_DPolygon) # Draw Point QToolButton self.toolBtn_DPoint.setDefaultAction(self.actionDraw_Pinpoint) self.DrawToolBar.addWidget(self.toolBtn_DPoint) # Draw Point QToolButton self.toolBtn_DLine.setDefaultAction(self.actionDraw_Line) self.DrawToolBar.addWidget(self.toolBtn_DLine) self.DrawToolBar.addAction(self.actionRuler) self.DrawToolBar.addSeparator() # # Censure QToolButton # self.toolBtn_Cesure.setDefaultAction(self.actionCensure) # self.DrawToolBar.addWidget(self.toolBtn_Cesure) # self.DrawToolBar.addSeparator() # # # Object Tracking # self.DrawToolBar.addAction(self.actionObject_Tracking) self.toolBtn_Cesure.setVisible(False) # Hide Color Button self.btn_Color.hide() self.RecGIF = QMovie(":/imgFMV/images/record.gif") self.videoWidget.customContextMenuRequested[QPoint].connect( self.contextMenuRequested) self.menubarwidget.customContextMenuRequested[QPoint].connect( self.contextMenuBarRequested) self.duration = 0 self.playerMuted = False self.HasFileAudio = False self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.pass_time = pass_time self.player.setNotifyInterval(700) # Metadata Callback Interval self.playlist = QMediaPlaylist() self.player.setVideoOutput( self.videoWidget.videoSurface()) # Abstract Surface self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.stateChanged.connect(self.setCurrentState) self.playerState = QMediaPlayer.LoadingMedia self.playFile(path) self.sliderDuration.setRange(0, self.player.duration() / 1000) self.volumeSlider.setValue(self.player.volume()) self.volumeSlider.enterEvent = self.showVolumeTip self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.setMinimumWidth(500) self.metadataDlg.hide() self.converter = Converter() self.BitratePlot = CreatePlotsBitrate() def HasAudio(self, videoPath): """ Check if video have Metadata or not """ try: p = _spawn([ '-i', videoPath, '-show_streams', '-select_streams', 'a', '-preset', 'ultrafast', '-loglevel', 'error' ], t="probe") stdout_data, _ = p.communicate() if stdout_data == b'': qgsu.showUserAndLogMessage( QCoreApplication.translate( "QgsFmvPlayer", "This video doesn't have Audio ! ")) self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) return False return True except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Audio check Failed! : "), str(e)) self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) def get_metadata_from_buffer(self, currentTime): """ Metadata CallBack """ try: # There is no way to spawn a thread and call after join() without blocking the video UI thread. # callBackMetadata can be as fast as possible, it will always create a small video lag every time meta are read. # To get rid of this, we fill a buffer (BufferedMetaReader) in the QManager with some Metadata in advance, # and hope they'll be ready to read here in a totaly non-blocking # way (increase the buffer size if needed in QManager). stdout_data = self.meta_reader.get(currentTime) # qgsu.showUserAndLogMessage( # "", "stdout_data: " + str(stdout_data) + " currentTime: " + str(currentTime), onlyLog=True) if stdout_data == 'NOT_READY': self.metadataDlg.menuSave.setEnabled(False) qgsu.showUserAndLogMessage( "", "Buffer value read but is not ready, increase buffer size. : ", onlyLog=True) return #Values need to be read, pause the video a short while elif stdout_data == 'BUFFERING': qgsu.showUserAndLogMessage("Buffering metadata...", "", duration=4, level=QGis.Info) self.player.pause() QTimer.singleShot(2500, lambda: self.player.play()) return elif stdout_data == b'' or len(stdout_data) == 0: self.metadataDlg.menuSave.setEnabled(False) qgsu.showUserAndLogMessage( "", "Buffer returned empty metadata, check pass_time. : ", onlyLog=True) return self.packetStreamParser(stdout_data) except Exception as inst: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Metadata Buffer Failed! : "), str(inst)) def packetStreamParser(self, stdout_data): ''' Common packet process''' for packet in StreamParser(stdout_data): try: if isinstance(packet, UnknownElement): qgsu.showUserAndLogMessage( "Error interpreting klv data, metadata cannot be read.", "the parser did not recognize KLV data", level=QGis.Warning, onlyLog=True) continue data = packet.MetadataList() self.data = data if self.metadataDlg.isVisible( ): # Only add metada to table if this QDockWidget is visible (speed plugin) self.metadataDlg.menuSave.setEnabled(True) self.addMetadata(data) UpdateLayers(packet, parent=self, mosaic=self.createingMosaic) QApplication.processEvents() return except Exception: None # qgsu.showUserAndLogMessage(QCoreApplication.translate( # "QgsFmvPlayer", "Meta update failed! "), " Packet:" + str(packet) + ", error:" + str(inst), level=QGis.Warning) def callBackMetadata(self, currentTime, nextTime): """ Metadata CallBack """ try: port = int(self.fileName.split(':')[2]) t = callBackMetadataThread(cmds=[ '-i', self.fileName.replace(str(port), str( port + 1)), '-ss', currentTime, '-to', nextTime, '-map', 'data-re', '-preset', 'ultrafast', '-f', 'data', '-' ]) t.start() t.join(1) if t.is_alive(): t.p.terminate() t.join() qgsu.showUserAndLogMessage("", "callBackMetadataThread self.stdout: " + str(t.stdout), onlyLog=True) if t.stdout == b'': return self.packetStreamParser(t.stdout) except Exception as e: qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Metadata Callback Failed! : "), str(e)) def GetPacketData(self): ''' Return Current Packet data ''' return self.data def addMetadata(self, packet): ''' Add Metadata to List ''' self.clearMetadata() row = 0 for key in sorted(packet.keys()): self.metadataDlg.VManager.insertRow(row) self.metadataDlg.VManager.setItem(row, 0, QTableWidgetItem(str(key))) self.metadataDlg.VManager.setItem( row, 1, QTableWidgetItem(str(packet[key][0]))) self.metadataDlg.VManager.setItem( row, 2, QTableWidgetItem(str(packet[key][1]))) row += 1 self.metadataDlg.VManager.setVisible(False) self.metadataDlg.VManager.resizeColumnsToContents() self.metadataDlg.VManager.setVisible(True) self.metadataDlg.VManager.verticalScrollBar().setSliderPosition( self.sliderPosition) def clearMetadata(self): ''' Clear Metadata List ''' try: self.sliderPosition = self.metadataDlg.VManager.verticalScrollBar( ).sliderPosition() self.metadataDlg.VManager.setRowCount(0) except Exception: None def saveInfoToJson(self): """ Save video Info to json """ out_json, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Json"), isSave=True, exts="json") if not out_json: return taskSaveInfoToJson = QgsTask.fromFunction( 'Save Video Info to Json Task', self.converter.probeToJson, fname=self.fileName, output=out_json, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskSaveInfoToJson) return def showVideoInfo(self): ''' Show default probe info ''' taskSaveInfoToJson = QgsTask.fromFunction( 'Show Video Info Task', self.converter.probeShow, fname=self.fileName, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskSaveInfoToJson) return def state(self): ''' Return Current State ''' return self.playerState def setCurrentState(self, state): ''' Set Current State ''' if state != self.playerState: self.playerState = state if state == QMediaPlayer.StoppedState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) return def showColorDialog(self): ''' Show Color dialog ''' self.ColorDialog = ColorDialog(parent=self) self.ColorDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) # Fail if not uncheked self.actionMagnifying_glass.setChecked(False) self.ColorDialog.exec_() QApplication.processEvents() self.ColorDialog.contrastSlider.setValue(80) self.ColorDialog.contrastSlider.triggerAction( QAbstractSlider.SliderMove) return def createMosaic(self, value): ''' Function for create Video Mosaic ''' home = os.path.expanduser("~") qgsu.createFolderByName(home, "QGIS_FMV") homefmv = os.path.join(home, "QGIS_FMV") root, _ = os.path.splitext(os.path.basename(self.fileName)) qgsu.createFolderByName(homefmv, root) self.createingMosaic = value # Create Group CreateGroupByName() return def contextMenuBarRequested(self, point): ''' Context Menu Menu Bar ''' menu = QMenu('ToolBars') toolbars = self.findChildren(QToolBar) for toolbar in toolbars: action = menu.addAction(toolbar.windowTitle()) action.setCheckable(True) action.setChecked(toolbar.isVisible()) action.setObjectName(toolbar.windowTitle()) action.triggered.connect(lambda _: self.ToggleQToolBar()) menu.exec_(self.mapToGlobal(point)) return def ToggleQToolBar(self): ''' Toggle ToolBar ''' toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if self.sender().objectName() == toolbar.windowTitle(): toolbar.toggleViewAction().trigger() def contextMenuRequested(self, point): ''' Context Menu Video ''' menu = QMenu('Video') # actionColors = menu.addAction( # QCoreApplication.translate("QgsFmvPlayer", "Color Options")) # actionColors.setShortcut("Ctrl+May+C") # actionColors.triggered.connect(self.showColorDialog) actionMute = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Mute/Unmute")) actionMute.setShortcut("Ctrl+Shift+U") actionMute.triggered.connect(self.setMuted) menu.addSeparator() actionAllFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract All Frames")) actionAllFrames.setShortcut("Ctrl+Shift+A") actionAllFrames.triggered.connect(self.ExtractAllFrames) actionCurrentFrames = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Extract Current Frame")) actionCurrentFrames.setShortcut("Ctrl+Shift+Q") actionCurrentFrames.triggered.connect(self.ExtractCurrentFrame) menu.addSeparator() actionShowMetadata = menu.addAction( QCoreApplication.translate("QgsFmvPlayer", "Show Metadata")) actionShowMetadata.setShortcut("Ctrl+Shift+M") actionShowMetadata.triggered.connect(self.OpenQgsFmvMetadata) menu.exec_(self.mapToGlobal(point)) # Start Snnipet FILTERS def grayFilter(self, value): ''' Gray Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetGray(value) self.videoWidget.UpdateSurface() return def MirrorHorizontalFilter(self, value): ''' Mirror Horizontal Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetMirrorH(value) self.videoWidget.UpdateSurface() return def edgeFilter(self, value): ''' Edge Detection Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetEdgeDetection(value) self.videoWidget.UpdateSurface() return def invertColorFilter(self, value): ''' Invert Color Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetInvertColor(value) self.videoWidget.UpdateSurface() return def autoContrastFilter(self, value): ''' Auto Contrast Video Filter ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetAutoContrastFilter(value) self.videoWidget.UpdateSurface() return def monoFilter(self, value): ''' Filter Mono Video ''' self.UncheckFilters(self.sender(), value) self.videoWidget.SetMonoFilter(value) self.videoWidget.UpdateSurface() return def magnifier(self, value): ''' Magnifier Glass Utils ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetMagnifier(value) self.videoWidget.UpdateSurface() return def pointDrawer(self, value): ''' Draw Point ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetPointDrawer(value) self.videoWidget.UpdateSurface() def lineDrawer(self, value): ''' Draw Line ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetLineDrawer(value) self.videoWidget.UpdateSurface() def polygonDrawer(self, value): ''' Draw Polygon ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetPolygonDrawer(value) self.videoWidget.UpdateSurface() def ojectTracking(self, value): ''' Object Tracking ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetObjectTracking(value) self.videoWidget.UpdateSurface() def VideoRuler(self, value): ''' Video Ruler ''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetRuler(value) if value: self.player.pause() self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) else: self.videoWidget.ResetDrawRuler() self.player.play() self.btn_play.setIcon(QIcon(":/imgFMV/images/pause.png")) self.videoWidget.UpdateSurface() def VideoCensure(self, value): ''' Censure Video Parts''' self.UncheckUtils(self.sender(), value) self.videoWidget.SetCensure(value) self.videoWidget.UpdateSurface() return def UncheckUtils(self, sender, value): ''' Uncheck Utils Video ''' self.actionMagnifying_glass.setChecked(False) self.actionDraw_Pinpoint.setChecked(False) self.actionDraw_Line.setChecked(False) self.actionDraw_Polygon.setChecked(False) self.actionObject_Tracking.setChecked(False) self.actionRuler.setChecked(False) self.actionCensure.setChecked(False) self.videoWidget.RestoreDrawer() sender.setChecked(value) return def UncheckFilters(self, sender, value): ''' Uncheck Filters Video ''' self.actionGray.setChecked(False) self.actionInvert_Color.setChecked(False) self.actionMono_Filter.setChecked(False) self.actionCanny_edge_detection.setChecked(False) self.actionAuto_Contrast_Filter.setChecked(False) self.actionMirroredH.setChecked(False) self.videoWidget.RestoreFilters() sender.setChecked(value) return # End Snnipet FILTERS def isMuted(self): ''' Is muted video property''' return self.playerMuted def setMuted(self): ''' Muted video ''' if self.player.isMuted(): self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) self.player.setMuted(False) self.volumeSlider.setEnabled(True) else: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) self.player.setMuted(True) self.volumeSlider.setEnabled(False) return def stop(self): ''' Stop video''' # Prevent Error in a Video Utils.Disable Magnifier if self.actionMagnifying_glass.isChecked(): self.actionMagnifying_glass.trigger() # Stop Video self.fakeStop() return def volume(self): ''' Volume Slider ''' return self.volumeSlider.value() def setVolume(self, volume): ''' Tooltip and set Volume value and icon ''' self.player.setVolume(volume) self.showVolumeTip(volume) if 0 < volume <= 30: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_30.png")) elif 30 < volume <= 60: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_60.png")) elif 60 < volume <= 100: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_up.png")) elif volume == 0: self.btn_volume.setIcon(QIcon(":/imgFMV/images/volume_off.png")) def EndMedia(self): ''' Button end video position ''' if self.player.isVideoAvailable(): self.player.setPosition(self.player.duration()) self.videoWidget.update() return def StartMedia(self): ''' Button start video position ''' if self.player.isVideoAvailable(): self.player.setPosition(0) self.videoWidget.update() return def forwardMedia(self): ''' Button forward Video ''' forwardTime = int(self.player.position()) + 10 * 1000 if forwardTime > int(self.player.duration()): forwardTime = int(self.player.duration()) self.player.setPosition(forwardTime) def rewindMedia(self): ''' Button rewind Video ''' rewindTime = int(self.player.position()) - 10 * 1000 if rewindTime < 0: rewindTime = 0 self.player.setPosition(rewindTime) def AutoRepeat(self, checked): ''' Button AutoRepeat Video ''' if checked: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) else: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) return def showVolumeTip(self, _): ''' Volume Slider Tooltip Trick ''' self.style = self.volumeSlider.style() self.opt = QStyleOptionSlider() self.volumeSlider.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.volumeSlider.mapToGlobal(pos_local) QToolTip.showText(pos_global, str(self.volumeSlider.value()) + " %", self) def showMoveTip(self, currentInfo): ''' Player Silder Move Tooptip Trick ''' self.style = self.sliderDuration.style() self.opt = QStyleOptionSlider() self.sliderDuration.initStyleOption(self.opt) rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle) self.tip_offset = QPoint(5, 15) pos_local = rectHandle.topLeft() + self.tip_offset pos_global = self.sliderDuration.mapToGlobal(pos_local) tStr = _seconds_to_time(currentInfo) QToolTip.showText(pos_global, tStr, self) def durationChanged(self, duration): ''' Duration video change signal ''' duration /= 1000 self.duration = duration self.sliderDuration.setMaximum(duration) def positionChanged(self, progress): ''' Current Video position change ''' progress /= 1000 if not self.sliderDuration.isSliderDown(): self.sliderDuration.setValue(progress) self.updateDurationInfo(progress) def updateDurationInfo(self, currentInfo): ''' Update labels duration Info and CallBack Metadata ''' duration = self.duration self.currentInfo = currentInfo if currentInfo or duration: totalTime = _seconds_to_time(duration) currentTime = _seconds_to_time(currentInfo) tStr = currentTime + " / " + totalTime currentTimeInfo = _seconds_to_time_frac(currentInfo) # Get Metadata from buffer if not self.isStreaming: self.get_metadata_from_buffer(currentTimeInfo) else: qgsu.showUserAndLogMessage("", "Streaming on ", onlyLog=True) nextTime = currentInfo + self.pass_time / 1000 nextTimeInfo = _seconds_to_time_frac(nextTime) self.callBackMetadata(currentTimeInfo, nextTimeInfo) else: tStr = "" self.labelDuration.setText(tStr) def handleCursor(self, status): ''' Change cursor ''' if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def statusChanged(self, status): ''' Signal Status video change ''' self.handleCursor(status) if status is QMediaPlayer.LoadingMedia or status is QMediaPlayer.StalledMedia or status is QMediaPlayer.InvalidMedia: self.videoAvailableChanged(False) elif status == QMediaPlayer.InvalidMedia: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", self.player.errorString()), level=QGis.Warning) self.videoAvailableChanged(False) else: self.videoAvailableChanged(True) def playFile(self, videoPath): ''' Play file from path ''' try: RemoveVideoLayers() RemoveGroupByName() # if "udp://" in videoPath: # host, port = videoPath.split("://")[1].split(":") # receiver = UDPClient(host, int(port), type="udp") # receiver.show() # self.close() # return # if "tcp://" in videoPath: # host, port = videoPath.split("://")[1].split(":") # receiver = UDPClient(host, port, type="tcp") # receiver.show() # self.close() # return self.fileName = videoPath self.playlist = QMediaPlaylist() if self.isStreaming: url = QUrl(videoPath) else: url = QUrl.fromLocalFile(videoPath) qgsu.showUserAndLogMessage("", "Added: " + str(url), onlyLog=True) self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.setWindowTitle( QCoreApplication.translate("QgsFmvPlayer", 'Playing : ') + os.path.basename(os.path.normpath(videoPath))) CreateVideoLayers() self.clearMetadata() self.HasFileAudio = True if not self.HasAudio(videoPath): self.actionAudio.setEnabled(False) self.actionSave_Audio.setEnabled(False) self.HasFileAudio = False # Recenter map on video initial point if self.initialPt: rect = QgsRectangle(self.initialPt[1], self.initialPt[0], self.initialPt[1], self.initialPt[0]) self.iface.mapCanvas().setExtent(rect) self.iface.mapCanvas().refresh() self.playClicked(True) except Exception as e: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", 'Open Video File : '), str(e), level=QGis.Warning) def ReciconUpdate(self, _): ''' Record Button Icon Effect ''' self.btn_Rec.setIcon(QIcon(self.RecGIF.currentPixmap())) def StopRecordAnimation(self): '''Stop record gif animation''' self.RecGIF.frameChanged.disconnect(self.ReciconUpdate) self.RecGIF.stop() self.btn_Rec.setIcon(QIcon(":/imgFMV/images/record.png")) # TODO: Make in other thread def RecordVideo(self, value): ''' Cut Video ''' currentTime = _seconds_to_time(self.currentInfo) if value is False: self.endRecord = currentTime _, file_extension = os.path.splitext(self.fileName) out, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save video record"), isSave=True, exts=file_extension[1:]) if not out: self.StopRecordAnimation() return p = _spawn([ '-i', self.fileName, '-ss', self.startRecord, '-to', self.endRecord, '-preset', 'ultrafast', '-c', 'copy', out ]) p.communicate() qgsu.showUserAndLogMessage( QCoreApplication.translate("QgsFmvPlayer", "Save file succesfully!")) self.StopRecordAnimation() else: self.startRecord = currentTime self.RecGIF.frameChanged.connect(self.ReciconUpdate) self.RecGIF.start() return def videoAvailableChanged(self, available): ''' Buttons for video available ''' # self.btn_Color.setEnabled(available) self.btn_CaptureFrame.setEnabled(available) self.gb_PlayerControls.setEnabled(available) return def toggleGroup(self, state): ''' Toggle GroupBox ''' sender = self.sender() if state: sender.setFixedHeight(sender.sizeHint().height()) else: sender.setFixedHeight(15) def fakeStop(self): '''self.player.stop() make a black screen and not reproduce it again''' self.player.pause() self.StartMedia() self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) def playClicked(self, _): ''' Stop and Play video ''' if self.playerState in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.btn_play.setIcon(QIcon(":/imgFMV/images/pause.png")) # Uncheck Ruler self.videoWidget.ResetDrawRuler() self.actionRuler.setChecked(False) self.videoWidget.SetRuler(False) # Play Video self.player.play() elif self.playerState == QMediaPlayer.PlayingState: self.btn_play.setIcon(QIcon(":/imgFMV/images/play-arrow.png")) self.player.pause() def seek(self, seconds): '''Slider Move''' self.player.setPosition(seconds * 1000) self.showMoveTip(seconds) def convertVideo(self): '''Convert Video To Other Format ''' out, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Video as..."), isSave=True, exts=[ "mp4", "ogg", "avi", "mkv", "webm", "flv", "mov", "mpg", "mp3" ]) if not out: return # TODO : Make Correct format Conversion and embebed metadata info = self.converter.probeInfo(self.fileName) if info is not None: if self.HasFileAudio: audio_codec = info.audio.codec audio_samplerate = info.audio.audio_samplerate audio_channels = info.audio.audio_channels video_codec = info.video.codec video_width = info.video.video_width video_height = info.video.video_height video_fps = info.video.video_fps _, out_ext = os.path.splitext(out) if self.HasFileAudio: options = { 'format': out_ext[1:], 'audio': { 'codec': audio_codec, 'samplerate': audio_samplerate, 'channels': audio_channels }, 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } else: options = { 'format': out_ext[1:], 'video': { 'codec': video_codec, 'width': video_width, 'height': video_height, 'fps': video_fps } } taskConvertVideo = QgsTask.fromFunction('Converting Video Task', self.converter.convert, infile=self.fileName, outfile=out, options=options, twopass=False, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskConvertVideo) def CreateBitratePlot(self): ''' Create video Plot Bitrate Thread ''' sender = self.sender().objectName() if sender == "actionAudio": taskactionAudio = QgsTask.fromFunction( 'Show Audio Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=None, t='audio', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionAudio) elif sender == "actionVideo": taskactionVideo = QgsTask.fromFunction( 'Show Video Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=None, t='video', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionVideo) elif sender == "actionSave_Audio": fileaudio, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Audio Bitrate Plot"), isSave=True, exts=[ "png", "pdf", "pgf", "eps", "ps", "raw", "rgba", "svg", "svgz" ]) if not fileaudio: return taskactionSave_Audio = QgsTask.fromFunction( 'Save Action Audio Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=fileaudio, t='audio', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionSave_Audio) elif sender == "actionSave_Video": filevideo, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Video Bitrate Plot"), isSave=True, exts=[ "png", "pdf", "pgf", "eps", "ps", "raw", "rgba", "svg", "svgz" ]) if not filevideo: return taskactionSave_Video = QgsTask.fromFunction( 'Save Action Video Bitrate', self.BitratePlot.CreatePlot, fileName=self.fileName, output=filevideo, t='video', on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskactionSave_Video) def finishedTask(self, e, result=None): """ Common finish task function """ if e is None: if result is None: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", 'Completed with no exception and no result '\ '(probably manually canceled by the user)'), level=QGis.Warning) else: if "Georeferencing" in result['task']: return qgsu.showUserAndLogMessage( QCoreApplication.translate( "QgsFmvPlayer", "Succesfully " + result['task'] + "!")) if "Bitrate" in result['task']: self.matplot = ShowPlot(self.BitratePlot.bitrate_data, self.BitratePlot.frame_count, self.fileName, self.BitratePlot.output) if result['task'] == 'Show Video Info Task': self.showVideoInfoDialog(self.converter.bytes_value) else: qgsu.showUserAndLogMessage(QCoreApplication.translate( "QgsFmvPlayer", "Failed " + result['task'] + "!"), level=QGis.Warning) raise e def ExtractAllFrames(self): """ Extract All Video Frames Task """ directory = askForFolder( self, QCoreApplication.translate("QgsFmvPlayer", "Save all Frames"), options=QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly) if directory: taskExtractAllFrames = QgsTask.fromFunction( 'Save All Frames Task', self.SaveAllFrames, fileName=self.fileName, directory=directory, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskExtractAllFrames) return def SaveAllFrames(self, task, fileName, directory): vidcap = cv2.VideoCapture(fileName) length = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT)) count = 0 while not task.isCanceled(): _, image = vidcap.read() cv2.imwrite(directory + "\\frame_%d.jpg" % count, image) # save frame as JPEG file task.setProgress(count * 100 / length) count += 1 vidcap.release() cv2.destroyAllWindows() if task.isCanceled(): return None return {'task': task.description()} def ExtractCurrentFrame(self): """ Extract Current Frame Task """ image = self.videoWidget.GetCurrentFrame() output, _ = askForFiles(self, QCoreApplication.translate( "QgsFmvPlayer", "Save Current Frame"), isSave=True, exts=["png", "jpg", "bmp", "tiff"]) if not output: return taskCurrentFrame = QgsTask.fromFunction('Save Current Frame Task', self.SaveCapture, image=image, output=output, on_finished=self.finishedTask, flags=QgsTask.CanCancel) QgsApplication.taskManager().addTask(taskCurrentFrame) return def SaveCapture(self, task, image, output): ''' Save Current Frame ''' image.save(output) if task.isCanceled(): return None return {'task': task.description()} def OpenQgsFmvMetadata(self): """ Open Metadata Dock """ if self.metadataDlg is None: self.metadataDlg = QgsFmvMetadata(parent=self, player=self) self.addDockWidget(Qt.RightDockWidgetArea, self.metadataDlg) self.metadataDlg.show() else: self.metadataDlg.show() return def showVideoInfoDialog(self, outjson): """ Show Video Information Dialog """ view = QTreeView() model = QJsonModel() view.setModel(model) model.loadJsonFromConsole(outjson) self.VideoInfoDialog = QDialog(self) self.VideoInfoDialog.setWindowTitle( QCoreApplication.translate("QgsFmvPlayer", "Video Information : ") + self.fileName) self.VideoInfoDialog.setWindowIcon( QIcon(":/imgFMV/images/video-info.png")) self.verticalLayout = QVBoxLayout(self.VideoInfoDialog) self.verticalLayout.addWidget(view) view.expandAll() view.header().setSectionResizeMode(QHeaderView.ResizeToContents) self.VideoInfoDialog.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint) self.VideoInfoDialog.setObjectName("VideoInfoDialog") self.VideoInfoDialog.resize(500, 400) self.VideoInfoDialog.show() def closeEvent(self, _): """ Close Event """ self.stop() self.parent._PlayerDlg = None self.parent.ToggleActiveFromTitle() RemoveVideoLayers() RemoveGroupByName() ResetData() try: self.metadataDlg.hide() except Exception: None try: self.matplot.close() except Exception: None # Restore Filters State self.videoWidget.RestoreFilters()
playlist = QMediaPlaylist() _list = [] for i in range(1, 12): print("../data/lolita/voice/kiana_%d.mp3" % i) _list.append(QMediaContent(QUrl("../data/lolita/voice/kiana_%d.mp3" % i))) playlist.addMedia(_list) # 只播放当前的 playlist.setPlaybackMode(QMediaPlaylist.CurrentItemOnce) player = QMediaPlayer() # 设置播放列表 player.setPlaylist(playlist) # 设置音量 player.setVolume(100) def play(): playlist.setCurrentIndex(2) player.play() playlist.setCurrentIndex(0) # currentIndex = playlist.currentIndex() + 1 # print(currentIndex) # if currentIndex > playlist.mediaCount(): # currentIndex = 0 # playlist.setCurrentIndex((currentIndex)) # player.play() btn = QPushButton("play", clicked = play) btn.show()
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 Translater(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(Translater, self).__init__(parent) self.setupUi(self) self.version = 2.8 self.version_detail = '\n更新说明:\t增加字体、颜色设置;\n\t增加4种语言发音;\n\t优化语音播放代码。' self.cwd = os.path.expanduser('~') self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() self.data_dict = { 'version': self.version, 'input': '', 'data_info': [], 'language': '', 'output': [], 'in_color': '#000000', 'in_font': ['Arial', 9, False, False, False], 'out_color': '#000000', 'out_font': ['Arial', 9, False, False, False] } self.set_info() f = Faker(locale='zh-CN') self.ua_all = f.user_agent() self.button_fy.clicked.connect(self.tran_act) self.button_clear.clicked.connect(self.clearact) self.actionverson.triggered.connect(self.versionact) self.actionhelp.triggered.connect(self.helpact) self.con_in_color.clicked.connect(lambda: self.change_coloract(1)) self.con_in_size.clicked.connect(lambda: self.change_fontact(1)) self.con_out_color.clicked.connect(lambda: self.change_coloract(0)) self.con_out_size.clicked.connect(lambda: self.change_fontact(0)) self.con_in_voice.clicked.connect(lambda: self.speak_act(1)) self.con_out_voice.clicked.connect(lambda: self.speak_act(0)) self.player = QMediaPlayer() def set_info(self): if os.path.isfile(self.cwd + '/trandata.json'): with open(self.cwd + '/trandata.json', 'r', encoding='utf-8') as fp: self.data_dict = json.load(fp) if 'version' not in self.data_dict.keys(): os.remove(self.cwd + '/trandata.json') self.data_dict['version'] = self.version else: if self.data_dict['version'] != self.version: os.remove(self.cwd + '/trandata.json') self.data_dict['version'] = self.version l = self.data_dict['language'] self.set_language(l) in_font = self.data_dict['in_font'] self.set_fontact(in_font, 1) out_font = self.data_dict['out_font'] self.set_fontact(out_font, 0) in_color = self.data_dict['in_color'] self.con_in.setStyleSheet('color:' + in_color) out_color = self.data_dict['out_color'] self.con_out.setStyleSheet('color:' + out_color) def change_fontact(self, sxt): font_font, b = QFontDialog.getFont() if b: font_f = font_font.family() font_s = font_font.pointSize() font_b = font_font.bold() font_i = font_font.italic() font_u = font_font.underline() font_x = [font_f, font_s, font_b, font_i, font_u] if sxt == 1: self.con_in.setFont(font_font) self.data_dict['in_font'] = font_x else: self.con_out.setFont(font_font) self.data_dict['out_font'] = font_x def set_fontact(self, font, sxt): set_font = QFont() set_font.setFamily(font[0]) set_font.setPointSize(font[1]) set_font.setBold(font[2]) set_font.setItalic(font[3]) set_font.setUnderline(font[4]) if sxt == 1: self.con_in.setFont(set_font) else: self.con_out.setFont(set_font) def change_coloract(self, sxt): color_color = QColorDialog.getColor() get_color = color_color.name() if sxt == 1: self.con_in.setStyleSheet('color:' + get_color) self.data_dict['in_color'] = get_color else: self.con_out.setStyleSheet('color:' + get_color) self.data_dict['out_color'] = get_color def get_info(self, context): ua = ''.join(self.ua_all.split('/')[1:]) m = hashlib.md5() m.update(ua.encode('utf-8')) bv = m.hexdigest() ts = str(int(time.time() * 1000)) salt = ts + str(random.randint(0, 9)) sign_str = 'fanyideskweb' + context + salt + 'Nw(nmmbP%A-r6U3EUn]Aj' mm = hashlib.md5() mm.update(sign_str.encode('utf-8')) sign = mm.hexdigest() self.data_dict['data_info'] = [bv, ts, salt, sign] return bv, ts, salt, sign def get_language(self): if self.radio_en.isChecked(): language = 'en' self.con_in_voice.show() self.label_9.hide() self.con_out_voice.show() self.label_H.hide() if self.radio_ja.isChecked(): language = 'ja' self.con_in_voice.show() self.label_9.hide() self.con_out_voice.show() self.label_H.hide() if self.radio_ko.isChecked(): language = 'ko' self.con_in_voice.show() self.label_9.hide() self.con_out_voice.show() self.label_H.hide() if self.radio_ru.isChecked(): language = 'ru' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_de.isChecked(): language = 'de' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_fr.isChecked(): language = 'fr' self.con_in_voice.show() self.label_9.hide() self.con_out_voice.show() self.label_H.hide() if self.radio_es.isChecked(): language = 'es' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_pt.isChecked(): language = 'pt' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_it.isChecked(): language = 'it' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_ar.isChecked(): language = 'ar' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_id.isChecked(): language = 'id' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() if self.radio_vi.isChecked(): language = 'vi' self.con_in_voice.hide() self.label_9.show() self.con_out_voice.hide() self.label_H.show() self.data_dict['language'] = language return language def set_language(self, l): if l == 'en': self.radio_en.setChecked(True) if l == 'ja': self.radio_ja.setChecked(True) if l == 'ko': self.radio_ko.setChecked(True) if l == 'ru': self.radio_ru.setChecked(True) if l == 'de': self.radio_de.setChecked(True) if l == 'fr': self.radio_fr.setChecked(True) if l == 'es': self.radio_es.setChecked(True) if l == 'pt': self.radio_pt.setChecked(True) if l == 'it': self.radio_it.setChecked(True) if l == 'ar': self.radio_ar.setChecked(True) if l == 'id': self.radio_id.setChecked(True) if l == 'vi': self.radio_vi.setChecked(True) def check_chinese(self, context): li = [ '–', '—', '‘', '’', '“', '”', '…', '、', '。', '〈', '〉', '《', '》', '「', '」', '『', '』', '【', '】', '〔', '〕', '!', '(', ')', ',', '.', ':', ';', '?', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '\n' ] for ch in context: if ch in li: pass elif ch < u'\u4E00' or ch > u'\u9FA5': return False return True def tran(self, context): bv, ts, salt, sign = self.get_info(context) l = self.get_language() headers = { 'User-Agent': self.ua_all, 'Referer': 'http://fanyi.youdao.com/', 'Cookie': '[email protected]; JSESSIONID=aaaCotdaKLvMH7QRFDoix; OUTFOX_SEARCH_USER_ID_NCOO=51303853.7527974; ___rl__test__cookies=' + ts } data = { 'i': context, 'client': 'fanyideskweb', 'salt': salt, 'sign': sign, 'ts': ts, 'bv': bv, 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'lan-select', } if self.check_chinese(context): data['from'] = 'zh-CHS' data['to'] = l self.con_in_voice.hide() self.label_9.show() else: data['from'] = l data['to'] = 'zh-CHS' self.con_out_voice.hide() self.label_H.show() url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' response = post(url, data=data, headers=headers) data_dict = json.loads(response.text) data_dict_con = data_dict['translateResult'] self.result = [] for p in data_dict_con: for s in p: out_content = s['tgt'] self.result.append(out_content) self.data_dict['output'] = self.result return self.result def get_speak(self): if self.radio_en.isChecked(): speak = 'eng' elif self.radio_ja.isChecked(): speak = 'jap' elif self.radio_ko.isChecked(): speak = 'ko' elif self.radio_fr.isChecked(): speak = 'fr' else: speak = 'eng' QMessageBox.warning(self, '错误', '不支持该语种发音,尝试采用英文发音。', QMessageBox.Ok) self.radio_en.setChecked(True) return speak def speak_act(self, x): if x == 1: content = self.con_in.toPlainText() else: content = self.con_out.toPlainText() url = 'http://tts.youdao.com/fanyivoice' le = self.get_speak() voice_url = url + '?word=' + content + '&le=' + le self.player.setMedia(QMediaContent(QUrl(voice_url))) self.player.setVolume(50) self.player.play() self.player.stateChanged.connect(self.play_state) if x == 1: self.con_in_voice.setDisabled(True) else: self.con_out_voice.setDisabled(True) def play_state(self): self.con_in_voice.setEnabled(True) self.con_out_voice.setEnabled(True) def tran_act(self): ''' 翻译 ''' context = self.con_in.toPlainText() if context != '': self.data_dict['input'] = context try: temp = self.tran(context) self.con_out.clear() for i in temp: self.con_out.appendPlainText(i) self.con_out.repaint() except: self.con_out.setPlainText('引擎错误!请检查网络链接!') else: self.con_out.setPlainText('请先输入原文!') def closeEvent(self, event): with open(self.cwd + '/trandata.json', 'w', encoding='utf-8') as f: f.write(json.dumps(self.data_dict, ensure_ascii=False, indent=4)) def clearact(self): self.con_in.clear() self.con_out.clear() def versionact(self): ''' 版本菜单 ''' QMessageBox.about(self, '版本', '版本:V' + str(self.version) + self.version_detail) def helpact(self): ''' 帮助菜单 ''' QMessageBox.about( self, '帮助', '系统默认选择英文\n翻译后所选语种将被记录,作为下次翻译的默认语种。\n支持中文对多种语言、外文对中文的翻译\n系统自动判断用户输入语言是否为中文。\n非中文的原文,暂不支持自动判断语种。\n如需相应的外文翻译中文,请首先选择正确的外文语种。' )
class MainWindow(QMainWindow): def __init__(self, audio_file_name: str): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.icon_alarm_clock = QIcon(str(DIR_ICONS / 'alarm-clock.png')) self.setWindowIcon(self.icon_alarm_clock) self.tray = QSystemTrayIcon(self.icon_alarm_clock) self.tray.setToolTip(self.windowTitle()) self.tray.activated.connect(self._on_tray_activated) self.tray.show() self.read_settings() self._button_group = QButtonGroup() self._button_group.addButton(self.ui.at_time_rb) self._button_group.addButton(self.ui.through_time_rb) self._button_group.buttonClicked.connect(self._update_states) self.ui.start_stop.clicked.connect(self._start_stop) self.ui.more_sleep.clicked.connect(self._more_sleep) self.ui.i_woke_up.clicked.connect(self._i_woke_up) self._timer = QTimer() self._timer.setInterval(100) self._timer.timeout.connect(self._tick) self._timer_inc_volume = QTimer() self._timer_inc_volume.setInterval(500) self._timer_inc_volume.timeout.connect(self._inc_volume_tick) self._woke_up = False self._alarm_time: QTime = None self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(QMediaPlaylist.Loop) url = QUrl.fromLocalFile(audio_file_name) self.playlist.addMedia(QMediaContent(url)) self.player = QMediaPlayer() self.player.setPlaylist(self.playlist) self._update_states() def _update_states(self): self.ui.at_time.setEnabled(self.ui.at_time_rb.isChecked()) self.ui.through_time.setEnabled(self.ui.through_time_rb.isChecked()) self.ui.i_woke_up.setVisible(self._woke_up) self.ui.more_sleep.setVisible(self._woke_up) if self._woke_up: self.ui.start_stop.setChecked(False) self.ui.start_stop.setVisible(not self._woke_up) if self.ui.start_stop.isChecked(): self.ui.start_stop.setText('Стоп') else: self.ui.start_stop.setText('Запустить') # Корректируем высоту окна после возможного скрытия кнопок self.resize(self.width(), self.minimumHeight()) def _inc_volume_tick(self): if self.player.volume() >= 100: self._timer_inc_volume.stop() self.player.setVolume(self.player.volume() + 1) def _tick(self): remain = QTime.currentTime().secsTo(self._alarm_time) if remain < 0: remain += 24 * 3600 elif remain == 0: self._woke_up = True self._timer.stop() self._update_states() self.player.setVolume(1) self.player.play() self._timer_inc_volume.start() self._set_visible(True) hh, mm = divmod(remain, 3600) mm, ss = divmod(mm, 60) alarm_str = self._alarm_time.toString('hh:mm:ss') self.ui.time_remaining.setText(f"Звонок в {alarm_str}. Осталось: {hh:0>2}:{mm:0>2}:{ss:0>2}") def _i_woke_up(self): self._woke_up = False self.player.stop() self._update_states() def _start(self): self._woke_up = False if self.ui.at_time_rb.isChecked(): self._alarm_time = self.ui.at_time.time() elif self.ui.through_time_rb.isChecked(): t = self.ui.through_time.time() self._alarm_time = add_to_current_time(t) self._timer.start() self._update_states() def _stop(self): self._woke_up = False self._timer.stop() self._update_states() def _start_stop(self): if self.ui.start_stop.isChecked(): self._start() else: self._stop() def _more_sleep(self): self._i_woke_up() t = self.ui.through_time.time() self._alarm_time = add_to_current_time(t) self._timer.start() self.ui.start_stop.setChecked(True) self._update_states() def _set_visible(self, visible: bool): self.setVisible(visible) if visible: self.showNormal() self.activateWindow() def _on_tray_activated(self, reason): self._set_visible(not self.isVisible()) def changeEvent(self, event: QEvent): if event.type() == QEvent.WindowStateChange: # Если окно свернули if self.isMinimized(): # Прячем окно с панели задач QTimer.singleShot(0, self.hide) def read_settings(self): ini = QSettings(SETTINGS_FILE_NAME, QSettings.IniFormat) if state := ini.value('MainWindow_State'): self.restoreState(state) if geometry := ini.value('MainWindow_Geometry'): self.restoreGeometry(geometry)
class App(QMainWindow): def __init__(self): super().__init__() self.player = QMediaPlayer() # 播放器 self.playlist = QMediaPlaylist() # 播放列表 self.title = '音乐播放器' self.volumeHint = QLabel('音量: 99%') self.mInfo = { 'cover': './default_cover.jpg', 'music': '', 'singer': '', 'duration': 0 } self.aboutWin = AboutWindow() self.cover = QLabel() self.listWid = QListWidget() # 设置主窗口位置 self.left = 200 self.top = 100 self.width = 500 self.height = 430 self.font = QFont('SansSerif', 10.5) self.color = 1 # 0 - 黑色界面, 1 - 白色界面 self.userAction = 0 # 0 - 停止中, 1 - 播放中 2 - 暂停中 self.initUI() def initUI(self): # 添加文件菜单 menubar = self.menuBar() menubar.setNativeMenuBar(False) # 不使用本地菜单栏以获得全平台统一的效果 filemenu = menubar.addMenu('文件') windowmenu = menubar.addMenu('窗口') fileAct = QAction('打开文件', self) folderAct = QAction('打开文件夹', self) themeAct = QAction('切换[亮/暗]主题', self) aboutAct = QAction('关于', self) fileAct.setShortcut('Ctrl+O') folderAct.setShortcut('Ctrl+D') themeAct.setShortcut('Ctrl+T') aboutAct.setShortcut('Ctrl+H') filemenu.addAction(fileAct) filemenu.addAction(folderAct) windowmenu.addAction(themeAct) windowmenu.addAction(aboutAct) fileAct.triggered.connect(self.openFile) folderAct.triggered.connect(self.addFiles) themeAct.triggered.connect(self.toggleColors) aboutAct.triggered.connect(self.viewAbout) self.listWid.itemDoubleClicked.connect(self.quickplayhandler) self.listWid.setFont(self.font) self.playlist.setPlaybackMode(2) self.setLayout() self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint) # 禁用窗口最大化按钮 self.setFont(self.font) self.setWindowTitle(self.title) self.setWindowIcon(QIcon('icon.ico')) self.setGeometry(self.left, self.top, self.width, self.height) self.setFixedSize(self.width, self.height) self.toggleColors() self.show() def setLayout(self): wid = QWidget(self) self.setCentralWidget(wid) # 添加音量控制 volumeslider = QSlider(Qt.Horizontal, self) volumeslider.setFocusPolicy(Qt.NoFocus) volumeslider.valueChanged[int].connect(self.changeVolume) volumeslider.setValue(100) # 添加歌曲播放控制 playBtn = QPushButton('播放') # 播放 pauseBtn = QPushButton('暂停') # 暂停 stopBtn = QPushButton('清空列表') # 停止 prevBtn = QPushButton('上一首') # 上一首 playback = QComboBox() # 回放模式 nextBtn = QPushButton('下一首') # 下一首 playback.addItem(' 单曲播放') playback.addItem(' 单曲循环') playback.addItem(' 列表播放') playback.addItem(' 列表循环') playback.addItem(' 列表随机') playback.setCurrentIndex(2) # 添加封面 jpg = QPixmap(self.mInfo['cover']).scaled(300, 300) self.cover.setPixmap(jpg) # 添加布局 Area = QVBoxLayout() # centralWidget controls = QHBoxLayout() showLayout = QHBoxLayout() playlistCtrlLayout = QHBoxLayout() # 歌曲播放控制布局 controls.addWidget(playBtn) controls.addWidget(pauseBtn) controls.addWidget(stopBtn) # 播放列表控制布局 playlistCtrlLayout.addWidget(prevBtn) playlistCtrlLayout.addWidget(playback) playlistCtrlLayout.addWidget(nextBtn) # 显示布局 showLayout.addWidget(self.cover) showLayout.addWidget(self.listWid) # 竖直排列 Area.addStretch(1) Area.addLayout(showLayout) Area.addWidget(self.volumeHint) Area.addWidget(volumeslider) Area.addLayout(controls) Area.addLayout(playlistCtrlLayout) wid.setLayout(Area) # 事件绑定 playBtn.clicked.connect(self.playhandler) pauseBtn.clicked.connect(self.pausehandler) playback.currentIndexChanged.connect(self.playbackhandler) stopBtn.clicked.connect(self.stophandler) prevBtn.clicked.connect(self.prevSong) nextBtn.clicked.connect(self.nextSong) self.statusBar().showMessage('文件-打开文件(夹)-选择-开始播放') self.playlist.currentMediaChanged.connect(self.songChanged) def openFile(self): print("点击了文件按钮") song = QFileDialog.getOpenFileName(self, "打开音频", "github-lkxed", "音频文件 (*.mp3 *.ogg *.wav *.m4a)") if song[0] != '': url = QUrl.fromLocalFile(song[0]) if self.playlist.mediaCount() == 0: self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.player.play() self.userAction = 1 self.listWid.addItem(song[0].split('/')[-1].split('.')[0]) print(self.playlist.mediaCount()) else: self.playlist.addMedia(QMediaContent(url)) print(self.playlist.mediaCount()) def addFiles(self): print("点击了文件夹按钮") if self.playlist.mediaCount() != 0: self.folderIterator() print(self.playlist.mediaCount()) else: self.folderIterator() self.player.setPlaylist(self.playlist) self.player.playlist().setCurrentIndex(0) self.player.play() print(self.playlist.mediaCount()) self.userAction = 1 def folderIterator(self): folderChosen = QFileDialog.getExistingDirectory(self, '打开音频文件夹', '.') if folderChosen != None: it = QDirIterator(folderChosen) it.next() while it.hasNext(): if it.fileInfo().isDir() == False and it.filePath() != '.': fInfo = it.fileInfo() print(it.filePath(), fInfo.suffix()) if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'): print('added file', fInfo.fileName()) self.listWid.addItem(fInfo.fileName()) self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) it.next() if it.fileInfo().isDir() == False and it.filePath() != '.': fInfo = it.fileInfo() print(it.filePath(), fInfo.suffix()) if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'): print('added file', fInfo.fileName()) self.listWid.addItem(fInfo.fileName()) self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) # 设置ListItem高度 for x in range(self.listWid.count()): self.listWid.item(x).setSizeHint(QSize(100, 30)) # 处理双击播放事件 def quickplayhandler(self, item): # 若播放列表没有音频了就跳出打开文件对话框 if self.playlist.mediaCount() == 0: self.openFile() # 若播放列表不为空则播放 elif self.playlist.mediaCount() != 0: index = self.listWid.currentRow() self.player.playlist().setCurrentIndex(index) self.player.play() self.userAction = 1 # 处理按钮播放事件 def playhandler(self): if self.userAction == 2: self.player.play() elif self.userAction == 0: # 若播放列表没有音频了就跳出打开文件对话框 if self.playlist.mediaCount() == 0: self.openFile() # 若播放列表不为空则播放 elif self.playlist.mediaCount() != 0: index = self.listWid.currentRow() self.player.playlist().setCurrentIndex(index) self.player.play() self.userAction = 1 else: self.statusBar().showMessage('已经在播放中!') # 处理暂停事件 def pausehandler(self): self.userAction = 2 self.player.pause() # 处理清空列表事件 def stophandler(self): self.userAction = 0 self.player.stop() self.playlist.clear() self.listWid.clear() self.mInfo['cover'] = 'default_cover.jpg' jpg = QPixmap(self.mInfo['cover']).scaled(300, 300) self.cover.setPixmap(jpg) print("Playlist cleared!") self.statusBar().showMessage("列表已清空") def changeVolume(self, value): text = '音量: ' + str(value) + '%' self.volumeHint.setText(text) self.player.setVolume(value) # 上一首事件 def prevSong(self): if self.playlist.currentIndex() == 0: self.playlist.setCurrentIndex(self.playlist.mediaCount()-1) else: self.player.playlist().previous() # 随机播放事件 def playbackhandler(self, index): self.playlist.setPlaybackMode(index) print(self.playlist.playbackMode()) # 下一首事件 def nextSong(self): if self.playlist.mediaCount() == self.playlist.currentIndex()+1: self.playlist.setCurrentIndex(0) else: self.player.playlist().next() # 音频切换事件 def songChanged(self, media): if not media.isNull(): url = media.canonicalUrl() self.showInfo(url) self.statusBar().showMessage(url.fileName()) index = self.player.playlist().currentIndex() self.listWid.setCurrentRow(index) def showInfo(self, url): filepath = url.path()[1:] filename = url.fileName()[:-4] print(filename) if filepath[-3:] == 'm4a': file = mutagen.MP4(filepath) try: img = file.tags['covr'][0] self.mInfo['cover'] = './cover/'+filename+'.jpg' if not os.path.exists('./cover'): os.mkdir('./cover') if not os.path.exists(self.mInfo['cover']): with open(self.mInfo['cover'], 'wb') as f: f.write(img) except: print('找不到封面') self.mInfo['cover'] = './default_cover.jpg' elif filepath[-3:] == 'mp3': file = mutagen.File(filepath) try: img = file.tags['APIC:'].data self.mInfo['cover'] = './cover/'+filename+'.jpg' if not os.path.exists('./cover'): os.mkdir('./cover') if not os.path.exists(self.mInfo['cover']): with open(self.mInfo['cover'], 'wb') as f: f.write(img) except: print('找不到封面') self.mInfo['cover'] = './default_cover.jpg' else: print('音频文件不支持提取封面') self.mInfo['cover'] = './default_cover.jpg' jpg = QPixmap(self.mInfo['cover']).scaled(300, 300) self.cover.setPixmap(jpg) # 主题切换事件 def toggleColors(self): app.setStyle("Fusion") palette = QPalette() # 明亮主题 if self.color == 0: 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(235, 101, 54)) palette.setColor(QPalette.Highlight, QColor(235, 101, 54)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) self.color = 1 # 黑暗主题 elif self.color == 1: palette.setColor(QPalette.Window, Qt.white) palette.setColor(QPalette.WindowText, Qt.black) palette.setColor(QPalette.Base, QColor(240, 240, 240)) palette.setColor(QPalette.AlternateBase, Qt.white) palette.setColor(QPalette.ToolTipBase, Qt.white) palette.setColor(QPalette.ToolTipText, Qt.white) palette.setColor(QPalette.Text, Qt.black) palette.setColor(QPalette.Button, Qt.white) palette.setColor(QPalette.ButtonText, Qt.black) palette.setColor(QPalette.BrightText, Qt.red) palette.setColor(QPalette.Link, QColor(66, 155, 248)) palette.setColor(QPalette.Highlight, QColor(66, 155, 248)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) self.color = 0 def viewAbout(self): self.aboutWin.show()
class PMusic(QWidget): '''central widget''' DEFAULT_IMG = '/usr/share/pmusic/pMusic.png' def __init__(self, parent): '''initialize instance''' super().__init__(parent) self.player = QMediaPlayer() self.player.mediaStatusChanged.connect(self.onmedia_status_changed) self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(QMediaPlaylist.Loop) self.player.setVolume(100) self.resize(parent.width(), parent.height()) self.setContentsMargins(0, 0, 0, 0) self.current_albumart = '' pixmap = QPixmap(PMusic.DEFAULT_IMG) self.img_label = PImage(self, pixmap) self.img_label.resize(self.width(), self.height()) self.img_label.clicked.connect(self.onclick_img_label) self.buttonbar = PButtonBar(self) self.buttonbar.hide() # position: at the bottom self.buttonbar.move(0, self.height() - self.buttonbar.height()) self.buttonbar.clicked_left.connect(self.onclick_prev) self.buttonbar.clicked_mid.connect(self.onclick_main) self.buttonbar.clicked_right.connect(self.onclick_next) # toggle button for shuffle self.shufflebutton = QPushButton(self) self.shufflebutton.hide() self.shufflebutton.setCheckable(True) self.shufflebutton.setText('S') # position: top left corner button_size = int(self.width() * 0.2) self.shufflebutton.setGeometry(0, 0, button_size, button_size) self.shufflebutton.clicked.connect(self.onclick_shuffle) self.quitbutton = QPushButton(self) self.quitbutton.hide() self.quitbutton.setStyleSheet('color: rgb(240, 0, 0)') # red self.quitbutton.setFont(QFont('webdings', 10)) self.quitbutton.setText('r') # cross # position: top right corner self.quitbutton.setGeometry(self.width() - button_size, 0, button_size, button_size) self.quitbutton.clicked.connect(self.onclick_quit) self.show() def enterEvent(self, event): '''on mouse enter, show the buttons''' super().enterEvent(event) self.buttonbar.show() self.shufflebutton.show() self.quitbutton.show() def leaveEvent(self, event): '''on mouse leave, hide the buttons''' super().leaveEvent(event) self.buttonbar.hide() self.shufflebutton.hide() self.quitbutton.hide() @pyqtSlot() def onclick_shuffle(self): '''shuffle button was toggled''' if self.shufflebutton.isChecked(): debug('shuffle: on') self.playlist.setPlaybackMode(QMediaPlaylist.Random) else: debug('shuffle: off') self.playlist.setPlaybackMode(QMediaPlaylist.Loop) @pyqtSlot() def onclick_quit(self): '''quit button was clicked''' debug('quit') self.stop() self.parent().close() @pyqtSlot() def onclick_img_label(self): '''image label was clicked''' debug('onclick_img_label') self.pause() @pyqtSlot() def onclick_prev(self): '''back button was pressed''' debug('onclick_prev') self.playlist.previous() if self.player.state() != QMediaPlayer.PlayingState: debug('player.state == {}'.format(self.player.state())) self.play() @pyqtSlot() def onclick_next(self): '''next button was pressed''' debug('onclick_next') self.playlist.next() if self.player.state() != QMediaPlayer.PlayingState: debug('player.state == {}'.format(self.player.state())) self.play() @pyqtSlot() def onclick_main(self): '''main button was pressed''' debug('onclick_main') # bring up directory selection dialog # have a preference for $HOME/Music/ try: homedir = os.environ['HOME'] if not os.path.isdir(homedir): homedir = os.path.curdir except KeyError: homedir = os.path.curdir music_dir = os.path.join(homedir, 'Music') if not os.path.isdir(music_dir): music_dir = os.path.curdir path = QFileDialog.getExistingDirectory(self, 'Select directory', music_dir, QFileDialog.ShowDirsOnly) debug('path == [{}]'.format(path)) if not path: # cancel return self.stop() self.load_playlist(path) self.play() def onmedia_status_changed(self): '''media changed; player switched to next song''' debug('onmedia_status_changed') debug('player.state == {}'.format(self.player.state())) debug('player.mediastate == {}'.format(self.player.mediaStatus())) # we want to load albumart if the song is in another directory # and display filename on stdout or console log # this is only relevant if the QMediaPlayer is now loading new media if self.player.mediaStatus() == QMediaPlayer.LoadingMedia: media = self.player.currentMedia() if media.isNull(): debug('media isNull') return filename = media.canonicalUrl().path() debug('current media == [{}]'.format(filename)) # make a short path for informational message short_path = filename try: homedir = os.environ['HOME'] + os.path.sep if short_path.startswith(homedir): short_path = filename[len(homedir):] except KeyError: pass if short_path.startswith('Music/'): short_path = short_path[len('Music/'):] print('now playing: {}'.format(short_path)) folder = os.path.dirname(filename) self.load_albumart(folder) elif self.player.mediaStatus() == QMediaPlayer.NoMedia: debug('no media present, change albumart to default image') # change to default image pixmap = QPixmap(PMusic.DEFAULT_IMG) self.img_label.setPixmap(pixmap) self.current_albumart = '' def load_playlist(self, path): '''load new playlist''' debug('load playlist') self.playlist.clear() # Note: not actually sure these formats are all supported ... files = QDirIterator(path, ['*.mp3', '*.ogg', '*.wav', '*.flac'], flags=QDirIterator.Subdirectories) while files.hasNext(): filename = files.next() debug('+ {}'.format(filename)) url = QUrl.fromLocalFile(filename) if not self.playlist.addMedia(QMediaContent(url)): debug('addMedia() => False') self.player.setPlaylist(self.playlist) def load_albumart(self, path): '''load album art''' debug('load albumart, path == {}'.format(path)) # load album art found = False for name in ('cover.jpg', 'Folder.jpg', 'folder.jpg', 'cover.png', 'AlbumArt.jpg', 'AlbumArtSmall.jpg'): filename = os.path.join(path, name) if os.path.isfile(filename): found = True if filename == self.current_albumart: debug('same albumart, already loaded') break debug('loading albumart {}'.format(filename)) pixmap = QPixmap(filename) self.img_label.setPixmap(pixmap) self.current_albumart = filename break if not found: if not self.current_albumart: debug('no albumart found, keeping default image') else: # put default image debug('no albumart found, putting default image') pixmap = QPixmap(PMusic.DEFAULT_IMG) self.img_label.setPixmap(pixmap) self.current_albumart = '' def stop(self): '''stop playing''' debug('stop') self.player.stop() def play(self): '''start playing''' debug('play()') self.player.play() def pause(self): '''pause playing''' if self.player.state() == QMediaPlayer.PlayingState: debug('pause') self.player.pause() elif self.player.state() in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState): self.player.play()
class Player(QMediaPlayer): def __init__(self, parent=None): super(Player, self).__init__(parent) self.parent = parent self.player = QMediaPlayer() self.queueList = QMediaPlaylist() self.player.setPlaylist(self.queueList) self.queueData = [] self.position = 0 self.volume = 100 self.status = 0 # 0: stop, 1: playing/paused self.player.mediaStatusChanged.connect(self.qmp_mediaStatusChanged) self.player.positionChanged.connect(self.qmp_positionChanged) self.player.durationChanged.connect(self.durationChanged) self.queueList.currentIndexChanged.connect(self.playlistPosChanged) def add(self, data): """Add track to the queue""" queueData = { 'pc_title': data['pc_title'], 'title': data['title'], 'url': data['url'], 'date': data['date_format'], 'description': data['description'] } self.queueData.append(queueData) self.queueList.addMedia(QMediaContent(QUrl(data['url']))) def playPause(self): icon = QIcon.fromTheme("media-playback-pause") if self.player.state() == QMediaPlayer.StoppedState: if self.player.mediaStatus() == QMediaPlayer.NoMedia: if self.queueList.mediaCount() != 0: self.player.play() elif self.player.mediaStatus() == QMediaPlayer.LoadedMedia: self.queueList.setCurrentIndex(self.position) self.player.play() elif self.player.mediaStatus() == QMediaPlayer.BufferedMedia: self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: icon = QIcon.fromTheme("media-playback-start") self.player.pause() elif self.player.state() == QMediaPlayer.PausedState: self.player.play() self.parent.playBtn.setIcon(icon) def startPlay(self): data = self.queueData[0] self.queueList.setCurrentIndex(0) self.parent.curPCLabel.setText(data['pc_title']) self.parent.curTrackName.setText(data['title']) self.playstatus = 1 self.player.play() icon = QIcon.fromTheme("media-playback-pause") self.parent.playBtn.setIcon(icon) def stop(self): self.player.stop() icon = QIcon.fromTheme("media-playback-start") self.parent.playBtn.setIcon(icon) def setPosition(self, pos): self.player.setPosition(pos) def durationChanged(self, duration): total_time = '0:00:00' duration = self.player.duration() total_time = ms_to_time(duration) self.parent.timeSlider.setMaximum(duration) self.currentTrackDuration = duration self.parent.totalTimeLabel.setText(total_time) def qmp_mediaStatusChanged(self, status): icon = QIcon.fromTheme("media-playback-pause") if self.player.state() == QMediaPlayer.StoppedState: icon = QIcon.fromTheme("media-playback-start") elif self.player.state() == QMediaPlayer.PausedState: icon = QIcon.fromTheme("media-playback-start") self.parent.playBtn.setIcon(icon) def qmp_positionChanged(self, position, senderType=False): self.currentTime = position current_time = '0:00:00' if position != -1: current_time = ms_to_time(position) self.parent.timeLabel.setText(current_time) self.parent.timeSlider.blockSignals(True) self.parent.timeSlider.setValue(position) self.parent.timeSlider.blockSignals(False) def playlistPosChanged(self): pos = self.queueList.currentIndex() data = self.queueData[pos] self.parent.curPCLabel.setText(data['pc_title']) self.parent.curTrackName.setText(data['title']) windowTitle = '{0} - {1}'.format(data['pc_title'], data['title']) self.parent.setWindowTitle(windowTitle) if self.queueList.mediaCount() > 1: if pos < self.queueList.mediaCount(): self.parent.queueNextBtn.setEnabled(True) else: self.parent.queueNextBtn.setEnabled(False) if pos > 0: self.parent.queuePrevBtn.setEnabled(True) else: self.parent.queuePrevBtn.setEnabled(False) if pos < self.queueList.mediaCount(): prevPos = 0 if self.position < pos: prevPos = pos - 1 else: prevPos = pos + 1 prevItem = self.parent.queueList.item(prevPos) prevWidget = self.parent.queueList.itemWidget(prevItem) if prevItem: prevWidget.statusIcon.setPixmap(QPixmap()) self.position = pos item = self.parent.queueList.item(pos) widget = self.parent.queueList.itemWidget(item) icon = QIcon.fromTheme("media-playback-start") widget.statusIcon.setPixmap(icon.pixmap(16, 16)) def setVolume(self, volume): self.player.setVolume(volume) def rev10Secs(self): position = self.player.position() new_pos = position - 10000 self.player.setPosition(new_pos) def for10Secs(self): position = self.player.position() new_pos = position + 10000 self.player.setPosition(new_pos) def delete(self, position): """ Delete the track and her data from position""" self.queueData.pop(position) self.queueList.removeMedia(position) if (position == self.position): self.playlistPosChanged()
class VentanaFinal(QWidget): def __init__(self, ancho, alto, volumen, ruta_fiesta, ruta_smoke, ruta_victoria, ruta_derrota): # Definición de atributos super().__init__() self.tamano = (ancho, alto) self.setFixedSize(*self.tamano) self.volumen = volumen self.init_gui(ruta_fiesta, ruta_smoke, ruta_victoria, ruta_derrota) def init_gui(self, ruta_fiesta, ruta_smoke, ruta_victoria, ruta_derrota): # Reproductor de musica url_victoria = QUrl.fromLocalFile(ruta_victoria) self.kumbia = QMediaContent(url_victoria) url_derrota = QUrl.fromLocalFile(ruta_derrota) self.flauta_sad = QMediaContent(url_derrota) self.reproductor = QMediaPlayer() self.reproductor.setVolume(self.volumen) # Letras letra1 = QFont() letra1.setFamily("Agency FB") letra1.setPointSize(70) letra1.setBold(True) letra2 = QFont() letra2.setFamily("Agency FB") letra2.setPointSize(75) letra2.setBold(True) # Gifs self.label_gif = QLabel('', self) self.gif_fiesta = QMovie(ruta_fiesta) self.gif_smoke = QMovie(ruta_smoke) # Texto self.label_borde = QLabel('', self) self.label_borde.setFont(letra2) self.label_texto = QLabel('', self) self.label_texto.setFont(letra1) def actualizar_pantalla(self, gif, texto, musica): # Setea el gif, texto y musica correspondiente a la ventana. self.label_gif.setMovie(gif) gif.setScaledSize(QSize(*self.tamano)) self.label_gif.resize(*self.tamano) self.reproductor.setMedia(musica) self.label_texto.setText(texto) self.label_texto.resize(self.label_texto.sizeHint()) self.label_borde.setText(texto) self.label_borde.resize(self.label_borde.sizeHint()) def mostrar_final(self, victoria): # Realiza cambios especificos a las situaciones de victoria o derrota a la ventana. # Son diferencias puramente esteticas. # Comienza la reproducion del GIF y la musica y muestra la ventana. if victoria: self.actualizar_pantalla(self.gif_fiesta, 'YOU WIN', self.kumbia) self.label_borde.setStyleSheet('color: rgb(255, 225, 225);') self.label_texto.setStyleSheet('color: rgb(255, 51, 102);') self.label_texto.move( (self.width() - self.label_texto.width()) // 2, 30) self.label_borde.move( (self.width() - self.label_borde.width()) // 2, 30) self.gif_fiesta.start() else: self.actualizar_pantalla(self.gif_smoke, 'YOU LOSE', self.flauta_sad) self.label_borde.setStyleSheet('color: rgb(0, 0, 0);') self.label_texto.setStyleSheet('color: rgb(255, 225, 225);') self.label_texto.move( (self.width() - self.label_texto.width()) // 2, self.height() - 150) self.label_borde.move( (self.width() - self.label_borde.width()) // 2, self.height() - 150) self.gif_smoke.start() self.reproductor.play() self.show()
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 ## self.setWindowTitle("Demo10_1,音乐播放器") self.player = QMediaPlayer(self) self.playlist = QMediaPlaylist(self) self.player.setPlaylist(self.playlist) self.playlist.setPlaybackMode(QMediaPlaylist.Loop) #循环模式 self.__duration = "" #文件总时间长度 self.__curPos = "" #当前播放到位置 self.player.stateChanged.connect(self.do_stateChanged) self.player.positionChanged.connect(self.do_positionChanged) self.player.durationChanged.connect(self.do_durationChanged) self.playlist.currentIndexChanged.connect(self.do_currentChanged) ## ==============自定义功能函数============ ## ===============event 处理函数========== def closeEvent(self, event): ##窗体关闭时 ## 窗口关闭时不能自动停止播放,需手动停止 if (self.player.state() == QMediaPlayer.PlayingState): self.player.stop() ## ==========由connectSlotsByName() 自动连接的槽函数================== # 播放列表管理 @pyqtSlot() ##添加文件 def on_btnAdd_clicked(self): ## curPath=os.getcwd() #获取系统当前目录 ## curPath=QDir.homePath() curPath = QDir.currentPath() dlgTitle = "选择音频文件" filt = "音频文件(*.mp3 *.wav *.wma);;所有文件(*.*)" fileList, flt = QFileDialog.getOpenFileNames(self, dlgTitle, curPath, filt) count = len(fileList) if count < 1: return filename = fileList[0] fileInfo = QFileInfo(filename) #文件信息 QDir.setCurrent(fileInfo.absolutePath()) #重设当前路径 for i in range(count): filename = fileList[i] fileInfo.setFile(filename) song = QMediaContent(QUrl.fromLocalFile(filename)) self.playlist.addMedia(song) #添加播放媒体 ## basename=os.path.basename(filename) #文件名和后缀 basename = fileInfo.baseName() self.ui.listWidget.addItem(basename) #添加到界面文件列表 if (self.player.state() != QMediaPlayer.PlayingState): self.playlist.setCurrentIndex(0) self.player.play() @pyqtSlot() ##移除一个文件 def on_btnRemove_clicked(self): pos = self.ui.listWidget.currentRow() item = self.ui.listWidget.takeItem(pos) #python会自动删除 if (self.playlist.currentIndex() == pos): #是当前播放的曲目 nextPos = 0 if pos >= 1: nextPos = pos - 1 self.playlist.removeMedia(pos) #从播放列表里移除 if self.ui.listWidget.count() > 0: #剩余个数 self.playlist.setCurrentIndex(nextPos) self.do_currentChanged(nextPos) #当前曲目变化 else: self.player.stop() self.ui.LabCurMedia.setText("无曲目") else: self.playlist.removeMedia(pos) @pyqtSlot() ##清空播放列表 def on_btnClear_clicked(self): self.playlist.clear() #清空播放列表 self.ui.listWidget.clear() self.player.stop() #停止播放 ## @pyqtSlot() ##双击时切换播放文件 def on_listWidget_doubleClicked(self, index): rowNo = index.row() #行号 self.playlist.setCurrentIndex(rowNo) self.player.play() # 播放控制 @pyqtSlot() ##播放 def on_btnPlay_clicked(self): if (self.playlist.currentIndex() < 0): self.playlist.setCurrentIndex(0) self.player.play() @pyqtSlot() ##暂停 def on_btnPause_clicked(self): self.player.pause() @pyqtSlot() ##停止 def on_btnStop_clicked(self): self.player.stop() @pyqtSlot() ##上一曲目 def on_btnPrevious_clicked(self): self.playlist.previous() @pyqtSlot() ##下一曲目 def on_btnNext_clicked(self): self.playlist.next() @pyqtSlot() ##静音控制 def on_btnSound_clicked(self): mute = self.player.isMuted() self.player.setMuted(not mute) if mute: self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp")) else: self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp")) @pyqtSlot(int) ##调节音量 def on_sliderVolumn_valueChanged(self, value): self.player.setVolume(value) @pyqtSlot(int) ##文件进度调控 def on_sliderPosition_valueChanged(self, value): self.player.setPosition(value) ## =============自定义槽函数=============================== def do_stateChanged(self, state): ##播放器状态变化 self.ui.btnPlay.setEnabled(state != QMediaPlayer.PlayingState) self.ui.btnPause.setEnabled(state == QMediaPlayer.PlayingState) self.ui.btnStop.setEnabled(state == QMediaPlayer.PlayingState) def do_positionChanged(self, position): ##当前文件播放位置变化,更新进度显示 if (self.ui.sliderPosition.isSliderDown()): #在拖动滑块调整进度 return self.ui.sliderPosition.setSliderPosition(position) secs = position / 1000 #秒 mins = secs / 60 #分钟 secs = secs % 60 #余数秒 self.__curPos = "%d:%d" % (mins, secs) self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration) def do_durationChanged(self, duration): ##文件时长变化 self.ui.sliderPosition.setMaximum(duration) secs = duration / 1000 #秒 mins = secs / 60 #分钟 secs = secs % 60 #余数秒 self.__duration = "%d:%d" % (mins, secs) self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration) def do_currentChanged(self, position): ##playlist当前曲目变化 self.ui.listWidget.setCurrentRow(position) item = self.ui.listWidget.currentItem() #QListWidgetItem if (item != None): self.ui.LabCurMedia.setText(item.text())
class App(QMainWindow): def __init__(self): super().__init__() self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.title = 'Personal audio player v2.3' self.left = 300 self.top = 300 self.width = 300 self.height = 150 self.color = 0 # 0- toggle to dark 1- toggle to light self.userAction = -1 # 0- stopped, 1- playing 2-paused self.duration = 0 #self.getRecommendedPlaylist() self.initUI() def initUI(self): # Add file menu menubar = self.menuBar() filemenu = menubar.addMenu('File') windowmenu = menubar.addMenu('Window') connectTo = menubar.addMenu('Connect to...') fileAct = QAction('Open File', self) folderAct = QAction('Open Folder', self) themeAct = QAction('Toggle light/dark theme', self) yandexMusic = QAction('Yandex Music', self) deezer = QAction('Deezer', self) spotify = QAction('Spotify', self) pandora = QAction('Pandora', self) mixcloud = QAction('Pandora', self) fileAct.setShortcut('Ctrl+O') folderAct.setShortcut('Ctrl+D') themeAct.setShortcut('Ctrl+T') filemenu.addAction(fileAct) filemenu.addAction(folderAct) windowmenu.addAction(themeAct) connectTo.addAction(yandexMusic) connectTo.addAction(deezer) connectTo.addAction(pandora) connectTo.addAction(mixcloud) connectTo.addAction(spotify) fileAct.triggered.connect(self.openFile) folderAct.triggered.connect(self.addFiles) themeAct.triggered.connect(self.toggleColors) yandexMusic.triggered.connect(self.connectYandexMusic) deezer.triggered.connect(self.connectYandexMusic) pandora.triggered.connect(self.connectYandexMusic) mixcloud.triggered.connect(self.connectYandexMusic) spotify.triggered.connect(self.connectYandexMusic) self.addControls() self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.toggleColors() self.show() def downloadTrack(self, name): page = requests.get("http://zaycev.net/search.html?query_search=" + name).text parser = fromstring(page) fileJSON = parser.xpath('//div/@data-url') resp = requests.get("http://zaycev.net" + fileJSON[1]) data = resp.json() with open("track.json", 'w') as outfile: json.dump(data, outfile) connection_file = open("track.json", 'r') conn_string = json.load(connection_file) track = requests.get(conn_string['url'].rsplit('?')[0]) try: os.makedirs('./tracks') except OSError: pass out = open("./tracks/" + name.strip() + ".mp3", 'wb') out.write(track.content) out.close() QMessageBox.about(self, "Track added!", name.strip() + " was added") def playRecommend(self): try: similarTracks = open("playlist.txt", 'r') i = 0 for line in similarTracks.readlines(): if i == 5: break else: i = i+1 print(line) self.downloadTrack(line) self.openFileRec("./tracks/" + line.strip() + ".mp3") except: QMessageBox.about(self, "Play error!", "Unknown error!") def getRecommendedPlaylist(self, song): try: audio = ID3(song[0]) title = ''.join(audio['TIT2'].text[0].rsplit('(')[0]) if title[-1] == ' ': title = title[0:-1] artist = audio['TPE1'].text[0] if artist[-1] == ' ': artist = artist[0:-1] print(artist + " " + title) resp = requests.get("http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&artist=" + artist + "&track=" + title + "&api_key=API_key&format=json") data = resp.json() with open("playlist" + artist + "-" + title + ".json", 'w') as outfile: json.dump(data, outfile) connection_file = open("playlist" + artist + "-" + title + ".json", 'r') conn_string = json.load(connection_file) with open("playlist.txt", 'a') as playlistFile: for track in conn_string['similartracks']['track']: playlistFile.write(track['artist']['name'] + " " + track['name'] + "\n") playlistFile.close() except: QMessageBox.about(self, "Error!", "Some trouble with export title or artist name, try other track") def getRecommendedPlaylistFolder(self, song): audio = ID3(song) title = ''.join(audio['TIT2'].text[0].rsplit('(')[0]) if title[-1] == ' ': title = title[0:-1] artist = audio['TPE1'].text[0] if artist[-1] == ' ': artist = artist[0:-1] print(artist + " " + title) resp = requests.get("http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&artist=" + artist + "&track=" + title + "&api_key=API_key&format=json") data = resp.json() with open("playlist" + artist + "-" + title + ".json", 'w') as outfile: json.dump(data, outfile) connection_file = open("playlist" + artist + "-" + title + ".json", 'r') conn_string = json.load(connection_file) with open("playlist.txt", 'a') as playlistFile: for track in conn_string['similartracks']['track']: playlistFile.write(track['artist']['name'] + " " + track['name'] + "\n") playlistFile.close() def addControls(self): wid = QWidget(self) self.setCentralWidget(wid) # Add song controls volumeslider = QSlider(Qt.Horizontal, self) volumeslider.setFocusPolicy(Qt.NoFocus) volumeslider.valueChanged[int].connect(self.changeVolume) volumeslider.setValue(50) sldPosition = QSlider(Qt.Horizontal, self) sldPosition.setMinimum(0) sldPosition.setFocusPolicy(Qt.NoFocus) #sldPosition.valueChanged.connect(self.player.setPosition) self.player.positionChanged.connect(sldPosition.setValue) sldPosition.setMaximum(180000) playBtn = QPushButton('Play') # play button pauseBtn = QPushButton('Pause') # pause button stopBtn = QPushButton('Stop') # stop button # Add playlist controls prevBtn = QPushButton('Prev') shuffleBtn = QPushButton('Shuffle') nextBtn = QPushButton('Next') playRecommendedBtn = QPushButton('Play Recommended Playlist') like = QPushButton('Like') dislike = QPushButton('DisLike') # Add button layouts controlArea = QVBoxLayout() # centralWidget controls = QHBoxLayout() playlistCtrlLayout = QHBoxLayout() playRec = QHBoxLayout() ld = QHBoxLayout() # Add buttons to song controls layout controls.addWidget(playBtn) controls.addWidget(pauseBtn) controls.addWidget(stopBtn) # Add buttons to playlist controls layout playlistCtrlLayout.addWidget(prevBtn) playlistCtrlLayout.addWidget(shuffleBtn) playlistCtrlLayout.addWidget(nextBtn) playRec.addWidget(playRecommendedBtn) ld.addWidget(like) ld.addWidget(dislike) # Add to vertical layout controlArea.addWidget(sldPosition) controlArea.addWidget(volumeslider) controlArea.addLayout(controls) controlArea.addLayout(playlistCtrlLayout) controlArea.addLayout(playRec) controlArea.addLayout(ld) wid.setLayout(controlArea) # Connect each signal to their appropriate function playBtn.clicked.connect(self.playhandler) pauseBtn.clicked.connect(self.pausehandler) stopBtn.clicked.connect(self.stophandler) prevBtn.clicked.connect(self.prevSong) shuffleBtn.clicked.connect(self.shufflelist) nextBtn.clicked.connect(self.nextSong) playRecommendedBtn.clicked.connect(self.playRecommend) like.clicked.connect(self.like) dislike.clicked.connect(self.dislike) self.statusBar() self.playlist.currentMediaChanged.connect(self.songChanged) def like(self, text): QMessageBox.about(self, "Attention!", "You have Liked track!") def dislike(self, text): QMessageBox.about(self, "Attention!", "You have DisLiked track!") def connectYandexMusic(self): apple = LoginWindow() apple.exec_() def openFile(self): print("File button clicked!") song = QFileDialog.getOpenFileName(self, "Open Song", "~", "Sound Files (*.mp3 *.ogg *.wav *.m4a)") print(song[0]) if song[0] != '': url = QUrl.fromLocalFile(song[0]) if self.playlist.mediaCount() == 0: self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.player.play() self.userAction = 1 print(self.playlist.mediaCount()) else: self.playlist.addMedia(QMediaContent(url)) print(self.playlist.mediaCount()) self.getRecommendedPlaylist(song) def openFileRec(self, path): song = path if song != '': url = QUrl.fromLocalFile(song) if self.playlist.mediaCount() == 0: self.playlist.addMedia(QMediaContent(url)) self.player.setPlaylist(self.playlist) self.player.play() self.userAction = 1 print(self.playlist.mediaCount()) else: self.playlist.addMedia(QMediaContent(url)) print(self.playlist.mediaCount()) def addFiles(self): print("Folder button clicked!") if self.playlist.mediaCount() != 0: self.folderIterator() print(self.playlist.mediaCount()) else: self.folderIterator() self.player.setPlaylist(self.playlist) self.player.playlist().setCurrentIndex(0) self.player.play() print(self.playlist.mediaCount()) self.userAction = 1 def folderIterator(self): folderChosen = QFileDialog.getExistingDirectory(self, 'Open Music Folder', '~') if folderChosen != None: it = QDirIterator(folderChosen) it.next() while it.hasNext(): if it.fileInfo().isDir() == False and it.filePath() != '.': fInfo = it.fileInfo() print(it.filePath(), fInfo.suffix()) if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'): print('added file', fInfo.fileName()) self.getRecommendedPlaylistFolder(it.filePath()) self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) it.next() if it.fileInfo().isDir() == False and it.filePath() != '.': fInfo = it.fileInfo() print(it.filePath(), fInfo.suffix()) if fInfo.suffix() in ('mp3', 'ogg', 'wav', 'm4a'): print('added file', fInfo.fileName()) self.getRecommendedPlaylistFolder(it.filePath()) self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(it.filePath()))) def playhandler(self): if self.playlist.mediaCount() == 0: self.openFile() elif self.playlist.mediaCount() != 0: self.player.play() print(self.playlist.mediaCount()) self.userAction = 1 def pausehandler(self): self.userAction = 2 self.player.pause() def stophandler(self): self.userAction = 0 self.player.stop() self.playlist.clear() print("Playlist cleared!") self.statusBar().showMessage("Stopped and cleared playlist") def changeVolume(self, value): self.player.setVolume(value) def changePosition(self, value): self.player.setPosition(value) def prevSong(self): if self.playlist.mediaCount() == 0: self.openFile() elif self.playlist.mediaCount() != 0: self.player.playlist().previous() def shufflelist(self): self.playlist.shuffle() print("Shuffled playlist!") def nextSong(self): if self.playlist.mediaCount() == 0: self.openFile() elif self.playlist.mediaCount() != 0: self.player.playlist().next() def songChanged(self, media): if not media.isNull(): url = media.canonicalUrl() self.statusBar().showMessage(url.fileName()) def toggleColors(self): app.setStyle("Fusion") palette = QPalette() if self.color == 0: 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(235, 101, 54)) palette.setColor(QPalette.Highlight, QColor(235, 101, 54)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) self.color = 1 elif self.color == 1: palette.setColor(QPalette.Window, Qt.white) palette.setColor(QPalette.WindowText, Qt.black) palette.setColor(QPalette.Base, QColor(240, 240, 240)) palette.setColor(QPalette.AlternateBase, Qt.white) palette.setColor(QPalette.ToolTipBase, Qt.white) palette.setColor(QPalette.ToolTipText, Qt.white) palette.setColor(QPalette.Text, Qt.black) palette.setColor(QPalette.Button, Qt.white) palette.setColor(QPalette.ButtonText, Qt.black) palette.setColor(QPalette.BrightText, Qt.red) palette.setColor(QPalette.Link, QColor(66, 155, 248)) palette.setColor(QPalette.Highlight, QColor(66, 155, 248)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) self.color = 0
class Control: """A class that handles the logic behind the program by manipulating the GUI classes and calling their methods in response to received signals.""" MAGIC = b"\x01\xff" def __init__(self, screens: list) -> None: self.player = QMediaPlayer() self.player.setAudioRole(QAudio.MusicRole) self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.mainWindow = MainWindow(self, screens) self.mainArea = self.mainWindow.centralWidget().upperBox.mainArea self.songList = self.mainWindow.centralWidget().upperBox.songList self.mediaControlArea = self.mainWindow.centralWidget( ).mediaControlArea self.mainWindow.show() self.library = None self.currentSong = None self.playing = False self.random = False self.repeat = 0 self.volume = 50 self.volumeChange(self.volume) self.mediaControlArea.volumeControl.setValue(self.volume) self.mainTimer = QTimer() self.mainTimer.setInterval(100) self.mainTimer.timeout.connect(self.updateSongProgress) self.mainTimer.start() self.libraryUpdateTimer = QTimer() self.libraryUpdateTimer.setInterval(15_000) self.libraryUpdateTimer.timeout.connect(self.updateLibrary) self.libraryUpdateTimer.start() self._connection = None self.connections() self.displayedType = None self.displayedName = None self.types = None self.songListWidth = None values = self.load() if values: self.mainWindow.setGeometry(*values) self.volumeChange(self.volume) self.mediaControlArea.volumeControl.setValue(self.volume) self.setUpTimer = QTimer() self.setUpTimer.setInterval(20) self.setUpTimer.setSingleShot(True) self.setUpTimer.timeout.connect(self.setAreas) self.setUpTimer.start() def connections(self): self.player.currentMediaChanged.connect(self.updateCurrentSong) self.player.durationChanged.connect(self.updateSongProgressRange) self.player.stateChanged.connect(self.playerStatusChanged) self.mediaControlArea.previousButton.click.connect( self.playlist.previous) self.mediaControlArea.repeatButton.click.connect( self.repeatButtonClick) self.mediaControlArea.stopButton.click.connect(self.stopButtonClick) self.mediaControlArea.playButton.click.connect(self.playButtonClick) self.mediaControlArea.randomButton.click.connect( self.randomButtonClick) self.mediaControlArea.nextButton.click.connect(self.playlist.next) self.mediaControlArea.muteButton.click.connect(self.mute) self.mediaControlArea.songProgress.sliderMoved.connect( self.songProgressMove) self.mediaControlArea.volumeControl.sliderMoved.connect( self.volumeChange) def setAreas(self) -> None: """Called after the GUI is created to provide user with a feedback that the program is running in case a larger amount of songs will be added when the Library class is initialized.""" # TODO add a tooltip that will notify the user larger amount of songs is being loaded # (freezes the program as the execution moves to the Library class.) self.library = library.Library() self.types = { "artist": self.library.getSongsForArtist, "album": self.library.getSongsForAlbum, "playlist": self.library.getSongsForPlaylist } self.mainArea.setAreas(self.library) self.setUpTimer.deleteLater() self.setUpTimer = None self.getSongs(self.displayedType, self.displayedName) if self.songListWidth is not None: songListGeometry = self.songList.geometry() self.songList.preferredWidth = songListGeometry.width( ) - self.songListWidth self.mainWindow.centralWidget().upperBox.line.resizeWidgets( songListGeometry.width() - self.songListWidth) def updateLibrary(self) -> None: self.library.update() self.mainArea.updateView(self.library) def updateCurrentSong(self) -> None: """Update all areas that may display information about the currently playing song - SongList, Now Playing tab, BottomBox""" media = self.player.currentMedia() self.currentSong = media.request().url().toLocalFile().replace( "/", "\\") if self.currentSong in self.library.library: self.songList.updateActiveSong(self.currentSong) self.mainArea.updateActiveSong(self.playlist.currentIndex()) songEntry = self.library.library[self.currentSong] self.mediaControlArea.updateSongInfo( f"{songEntry[ARTIST]} - {songEntry[NAME]}") def updateSongProgressRange(self) -> None: """Updates the range of the slider that represents the song position.""" self.mediaControlArea.updateSongProgressRange(self.player.duration()) def playerStatusChanged(self) -> None: """Used to properly update the player look after the current playlist has finished.""" index = self.playlist.currentIndex() if index == -1: self.stopButtonClick() def getSongs(self, isType: str, name: str) -> None: """Retrieves the songs for a given artist, album or playlist based on type and passes the resulting list to the SongList class.""" if isType is None: isType = self.displayedType if name is None: name = self.displayedName orderBy = self.songList.buttonOrderBy.text() reverse = True if self.songList.buttonOrderReverse.text() == chr( 0x25bc) else False listForType = self.types[isType](name, orderBy, reverse) playlist = None if isType == "playlist": playlist = name if len(listForType) == 0: artists = self.library.artists if len(artists): listForType = self.library.getSongsForArtist(artists[0]) self.songList.updateSongList(listForType, self.library.library, self.currentSong, playlist, isType) self.displayedType = isType self.displayedName = name def playSongList(self, song: str = None) -> None: """Called when user double-clicks on an artist/album/playlist widget or a song in right-hand side panel.""" self.playlist.clear() index = 0 loopIndex = 0 for songPath in self.songList.garbageProtector: if song == songPath: index = loopIndex self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(songPath))) loopIndex += 1 if self.playlist.isEmpty(): return self.player.play() if index > 0: self.playlist.setCurrentIndex(index) self.playing = True self.mediaControlArea.playButton.updatePictures( bottom.pausePixmap, bottom.pauseHoverPixmap, False) self.mainArea.setNowPlayingArea(self.library) self.mainArea.updateActiveSong(self.playlist.currentIndex()) def playSongWidget(self, songPath: str, afterCurrent: bool = False) -> None: if afterCurrent: index = self.playlist.currentIndex() + 1 self.playlist.insertMedia( index, QMediaContent(QUrl.fromLocalFile(songPath))) else: self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(songPath))) self.mainArea.setNowPlayingArea(self.library) self.mainArea.updateActiveSong(self.playlist.currentIndex()) self.playing = True def removeFromNowPlaying(self, widget) -> None: if self.playlist.mediaCount() > 1: for row in range(self.mainArea.nowPlayingLayout.rowCount()): for column in range( self.mainArea.nowPlayingLayout.columnCount()): if self.mainArea.nowPlayingLayout.itemAtPosition( row, column).widget() is widget: self.playlist.removeMedia(row - 1) break else: continue break else: self.stopButtonClick() self.playlist.clear() self.mainArea.setNowPlayingArea(self.library) if self.playing: self.mainArea.updateActiveSong(self.playlist.currentIndex()) def playMediaWidget(self, isType: str, target: str, startOver: bool, afterCurrent: bool) -> None: """Called from MediaWidget - plays all songs for MediaWidget's type and name.""" if startOver: self.playlist.clear() if afterCurrent: index = self.playlist.currentIndex() + 1 for songPath in self.types[isType](target): self.playlist.insertMedia( index, QMediaContent(QUrl.fromLocalFile(songPath))) index += 1 else: for songPath in self.types[isType](target): self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(songPath))) if startOver: self.player.play() self.playing = True self.mediaControlArea.playButton.updatePictures( bottom.pausePixmap, bottom.pauseHoverPixmap, False) self.mainArea.setNowPlayingArea(self.library) self.mainArea.updateActiveSong(self.playlist.currentIndex()) def playFromNowPlaying(self, song: str) -> None: """Called when user double-clicks on a song in the Now Playing tab.""" for n in range(self.playlist.mediaCount()): media = self.playlist.media(n) if song == media.request().url().toLocalFile().replace("/", "\\"): self.playlist.setCurrentIndex(n) if not self.playing: self.player.play() self.playing = True return def createPlaylist(self, playlistName: str) -> None: self.library.createPlaylist(playlistName) self.mainArea.setMainAreaPlaylists(self.library) def addToExistingPlaylist(self, playlist: str, songOrWidget: str, isType: str) -> None: if isType in self.types: for song in self.types[isType](songOrWidget): self.library.addToPlaylist(playlist, song) else: self.library.addToPlaylist(playlist, songOrWidget) self.library.update() def removeFromPlaylist(self, playlist: str, song: str) -> None: self.library.deleteFromPlaylist(playlist, song) self.mainArea.setMainAreaPlaylists(self.library) self.library.update() self.getSongs("playlist", playlist) def renamePlaylist(self, playlistName: str, newPlaylistName: str) -> None: self.library.renamePlaylist(playlistName, newPlaylistName) self.mainArea.setMainAreaPlaylists(self.library) self.library.update() def deletePlaylist(self, playlistName: str) -> None: self.library.deletePlaylist(playlistName) self.mainArea.setMainAreaPlaylists(self.library) self.library.update() def addWatchedFolder(self, folder: str) -> None: """Adds a folder to the Library class. all mp3 files within the folder and its sub-folders will be added to the library and accessible to the player.""" self.library.addFolder(folder.replace("/", "\\")) self.mainArea.updateView(self.library) def removeWatchedFolder(self, folder: str) -> None: """Removes folder from the library, updates view and stops playback if the current song was in the now-removed folder.""" self.library.deleteFolder(folder) self.mainArea.updateView(self.library) if self.currentSong not in self.library.library: self.songList.updateSongList([], [], "", "") self.player.stop() self.playlist.clear() self.mediaControlArea.updateSongInfo("") self.songList.nowPlayingSong = None self.mainArea.nowPlayingSong = None self.playing = False self.mediaControlArea.updatePlayButton(self.playing, False) def playButtonClick(self, passMove: bool = True) -> None: if not self.playing: if self.playlist.isEmpty(): self.playSongList() return self.playing = True self.player.play() self.mainArea.updateActiveSong(self.playlist.currentIndex()) self.songList.updateActiveSong(self.currentSong) else: self.playing = False self.player.pause() self.mediaControlArea.updatePlayButton(self.playing, passMove) def repeatButtonClick(self) -> None: if self.repeat == 0: self.repeat = 1 self.playlist.setPlaybackMode(QMediaPlaylist.Loop) elif self.repeat == 1: self.repeat = 2 self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) elif self.repeat == 2: self.repeat = 0 self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.mediaControlArea.updateRepeatButton(self.repeat) def randomButtonClick(self) -> None: if not self.random: self.random = True self.playlist.setPlaybackMode(QMediaPlaylist.Random) else: self.random = False self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) self.mediaControlArea.updateRandomButton(self.random) def stopButtonClick(self) -> None: self.playing = False self.player.stop() if self.songList.nowPlayingSong is not None: self.songList.nowPlayingSong.clear() if self.mainArea.nowPlayingSong is not None: self.mainArea.nowPlayingSong.clear() self.mediaControlArea.updatePlayButton(self.playing, False) def mute(self) -> None: if not self.player.isMuted(): self.player.setMuted(True) self.mediaControlArea.showMute() else: self.player.setMuted(False) self.volumeChange(self.volume) def volumeChange(self, volume: int) -> None: logVolume = QAudio.convertVolume(volume / 100, QAudio.LogarithmicVolumeScale, QAudio.LinearVolumeScale) * 100 self.player.setVolume(logVolume) self.volume = volume self.mediaControlArea.updateVolumeBar(volume) def songProgressMove(self, position: int) -> None: self.player.setPosition(position) def updateSongProgress(self) -> None: position = self.player.position() if 0 <= position < 2_000_000_000: if self.player.state() > 0: self.mediaControlArea.updateSongProgress(position) if self.playing: self.songList.activeSongPixmap() self.mainArea.activeSongPixmap() else: self.mediaControlArea.updateSongProgress(0) def disconnect(self): self.player.currentMediaChanged.disconnect() self.player.durationChanged.disconnect() self.player.stateChanged.disconnect() self.mediaControlArea.previousButton.click.disconnect() self.mediaControlArea.repeatButton.click.disconnect() self.mediaControlArea.stopButton.click.disconnect() self.mediaControlArea.playButton.click.disconnect() self.mediaControlArea.randomButton.click.disconnect() self.mediaControlArea.nextButton.click.disconnect() self.mediaControlArea.muteButton.click.disconnect() self.mediaControlArea.songProgress.sliderMoved.disconnect() self.mediaControlArea.volumeControl.sliderMoved.disconnect() def close(self) -> None: self.disconnect() self.player.stop() self.mainTimer.stop() self.save() def save(self) -> None: """Called on exit, saves current view, geometry and volume.""" with gzip.open(r"musicplayer\mpdata", "wb") as fh: fh.write(self.MAGIC) toBeWritten = struct.pack(f"<h{len(self.displayedType.encode())}s", len(self.displayedType.encode()), self.displayedType.encode()) fh.write(toBeWritten) fh.write(self.MAGIC) toBeWritten = struct.pack(f"<h{len(self.displayedName.encode())}s", len(self.displayedName.encode()), self.displayedName.encode()) fh.write(toBeWritten) fh.write(self.MAGIC) geo = self.mainWindow.geometry() toBeWritten = struct.pack("<4h", geo.x(), geo.y(), geo.width(), geo.height()) fh.write(toBeWritten) toBeWritten = struct.pack("<h", self.volume) fh.write(toBeWritten) toBeWritten = struct.pack("<h", self.songList.width()) fh.write(toBeWritten) def load(self) -> [bool, tuple]: """Called on startup, loads view, geometry and volume saved on previous run.""" try: with gzip.open(r"musicplayer\mpdata", "rb") as fh: if not fh.read(2) == self.MAGIC: return False length = fh.read(2) length = struct.unpack("<h", length)[0] displayedType = fh.read(length) displayedType = struct.unpack(f"<{length}s", displayedType)[0].decode("utf8") if displayedType in ["artist", "album", "playlist"]: self.displayedType = displayedType if not fh.read(2) == self.MAGIC: return False length = fh.read(2) length = struct.unpack("<h", length)[0] displayedName = fh.read(length) displayedName = struct.unpack(f"<{length}s", displayedName)[0].decode("utf8") if not fh.read(2) == self.MAGIC: return False self.displayedName = displayedName variables = [] for n in range(6): var = fh.read(2) var = struct.unpack("<h", var)[0] variables.append(var) x, y, width, height, volume, songListWidth = variables self.volume = volume self.songListWidth = songListWidth return x, y, width, height except Exception: return False
class MyWidget(QMainWindow): def __init__(self): super().__init__() # !Костыль # Запрещаю менять размер окна, т.к. не хочу работать с layout`ами self.setFixedSize(656, 532) self.setWindowIcon(QIcon('icons/icon.ico')) # Добавляем эквалайзер громкости self.equalizer = QVolumeEq((255, 255, 102), (255, 26, 10), bg_color=(0, 0, 0, 20)) self.equalizer.setParent(self) self.equalizer.move(20, 391) self.equalizer.resize(341, 31) uic.loadUi('icons/djap.ui', self) self.lightThemeAction.triggered.connect(self.change_theme) self.darkThemeAction.triggered.connect(self.change_theme) # Создаём организатор плейлистов self.playlist_handler = QPlaylistHandler() self.playlist_handler.setParent(self) self.playlist_handler.move(380, 40) # Настраиваем меню self.saveOption.triggered.connect(self.playlist_handler.save_playlist) self.saveAsOption.triggered.connect(self.playlist_handler.save_playlist_as) self.deleteOption.triggered.connect(self.playlist_handler.delete_playlist) self.aboutOption.triggered.connect(self.about) self.helpOption.triggered.connect(self.help) self.repeatModeOption.triggered.connect(self.playlist_handler.change_playmode) self.oneModeOption.triggered.connect(self.playlist_handler.change_playmode) self.randomModeOption.triggered.connect(self.playlist_handler.change_playmode) # Реализация проигрывателя и основного плейлиста self.player = QMediaPlayer() self.player.durationChanged.connect(self.update_song) self.player.setVolume(25) self.player.positionChanged.connect(self.update_timeline_position) self.queue = QMediaPlaylist(self.player) self.player.setPlaylist(self.queue) self.queue.setPlaybackMode(QMediaPlaylist.Loop) self.is_looped_queue = True # Загрузка музыки из плейлиста self.load_songs_from_playlist() # Подключаем кнопки к их функциям self.is_playing = False self.playBtn.clicked.connect(self.play_or_pause) self.queue.currentMediaChanged.connect(self.check_to_stop) self.nextBtn.clicked.connect(self.next_audio) self.prevBtn.clicked.connect(self.prev_audio) self.is_looped_current_track = False self.loopBtn.clicked.connect(self.loop_or_unloop_current_track) # Настройка слайдера звука self.volumeSlider.hide() self.volumeSlider.setValue(25) self.equalizer.setValue(25) self.volumeSlider.sliderReleased.connect(self.volumeSlider.hide) self.volumeSlider.valueChanged.connect(self.change_volume) self.volumeBtn.clicked.connect(self.change_volume) # Настройка таймлайна self.is_timeline_dragged = False self.timeline.sliderReleased.connect(self.timeline_changed) self.timeline.sliderPressed.connect(self.timeline_is_dragged) # !Костыль # Имитируем запуск аудиодорожки, чтобы подгрузить данные self.play_or_pause() self.play_or_pause() self.icon_changed() def palette(self): """Функция для создания темы""" con = sqlite3.connect('user_data.sqlite') cur = con.cursor() if int(cur.execute('SELECT * FROM theme').fetchone()[0]): palette = QPalette() palette.setColor(QPalette.Window, QColor(240, 240, 240)) palette.setColor(QPalette.WindowText, Qt.black) palette.setColor(QPalette.Base, Qt.white) palette.setColor(QPalette.AlternateBase, QColor(246, 246, 246)) palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 240)) palette.setColor(QPalette.ToolTipText, Qt.black) palette.setColor(QPalette.Text, Qt.black) palette.setColor(QPalette.Button, QColor(240, 240, 240)) palette.setColor(QPalette.ButtonText, Qt.black) palette.setColor(QPalette.BrightText, Qt.white) palette.setColor(QPalette.Highlight, QColor(0, 120, 215).lighter()) palette.setColor(QPalette.HighlightedText, Qt.white) else: palette = QPalette() palette.setColor(QPalette.Window, QColor(53, 53, 53)) palette.setColor(QPalette.WindowText, Qt.white) palette.setColor(QPalette.Base, QColor(15, 15, 15)) 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.Highlight, QColor(142, 45, 197).lighter()) palette.setColor(QPalette.HighlightedText, Qt.black) return palette def change_theme(self): """Функция для смены темы""" con = sqlite3.connect('user_data.sqlite') cur = con.cursor() if self.sender() == self.lightThemeAction: cur.execute('UPDATE theme SET isit = 1') else: cur.execute('UPDATE theme SET isit = 0') con.commit() QMessageBox.warning(self, 'DJust Audio Player', 'Чтобы изменения вступили в силу, ' 'перезапустите приложение.', QMessageBox.Ok) def help(self): """Функция для показа формы справки""" self.help = QHelp() def about(self): """Функция для показа формы О программе""" self.about = QAbout() def delete_song_from_mediaplayer(self, index): """Удалить трек из медиаплеера""" self.queue.removeMedia(index) def add_song_to_mediaplayer(self, url): """Добавить трек в медиаплеер""" self.queue.addMedia(QMediaContent(QUrl(url))) def change_track_by_click(self, row): """Функция для смены трека по нажатию в списке""" self.queue.setCurrentIndex(row) def check_to_stop(self): """Проверяем, чтобы плеер не играл с пустым плейлистом""" if self.queue.isEmpty() and self.is_playing: self.play_or_pause() def load_songs_from_playlist(self): """Загрузка музыки из БД в плейлист""" self.queue.clear() for url in self.playlist_handler.urls(): self.queue.addMedia(QMediaContent(QUrl(url))) def icon_changed(self): """Функция для вывода обложки трека""" def noicon(): """В случае отсутствия обложки эта функция ставить свою заглушку""" try: pixmap = QPixmap() if pixmap.load('icons/noicon.png'): self.audioPic.setPixmap(pixmap) except Exception as e: print(e.__class__.__name__, ': ', e, sep='') try: # Читаем метаданные трека n = self.queue.currentIndex() url = self.playlist_handler.urls()[n if n > -1 else 0] file = File(url) for i in file.tags.keys(): if 'APIC:' in i: artwork = file.tags[i].data break else: raise KeyError # Переводим их в байтовый массив ba = QByteArray(artwork) # И загружаем на форму, если это возможно pixmap = QPixmap() if pixmap.loadFromData(ba): self.audioPic.setPixmap(pixmap.scaled(341, 341, Qt.IgnoreAspectRatio)) else: raise KeyError except Exception as e: # print(e.__class__.__name__, ': ', e, sep='') noicon() def timeline_is_dragged(self): """Мини-функция для изменения переменной""" # При вызове этой функции мы понимаем, что пользователь # взаимодействует с таймлайном трека self.is_timeline_dragged = True def timeline_changed(self): """Функция для пользовательской перемотки данного трека""" # Перематываем позицию плеера self.player.setPosition(self.timeline.value() * 1000) # Пользователь отпустил язычок слайдера и больше не взаимодействует с таймлайном self.is_timeline_dragged = False # Вызываем обновление временной шкалы, т.к. произошла перемотка self.update_timeline_position() def update_song(self): """Изменение данных о треке""" # !Костыль # Проматываем несколько миллисекунд, чтобы избежать повреждённых треков self.player.setPosition(10) # Меняем обложку self.icon_changed() # Выделяем в списке новый трек self.playlist_handler.set_current_select(self.queue.currentIndex()) # Меняем название окна в соответствии с играющим треком title = self.queue.currentMedia().canonicalUrl().path().split('/')[-1] if title: self.setWindowTitle('DJust Audio Player | %s' % title) else: self.setWindowTitle('DJust Audio Player') # Изменяем длину таймлайна на длину трека self.timeline.setMaximum(self.player.duration() // 1000) # Выводим длину трека в минутах/секундах на экран minutes, seconds = self.player.duration() // 1000 // 60, self.player.duration() // 1000 % 60 self.endTimeLabel.setText(str(minutes) + ':{:02d}'.format(seconds)) def update_timeline_position(self): """Функция для обновления временной шкалы""" # Выводим текущее положение плеера в минутах/секундах minutes, seconds = self.player.position() // 1000 // 60, self.player.position() // 1000 % 60 self.currentTimeLabel.setText(str(minutes) + ':{:02d}'.format(seconds)) # Чтобы не "вырывать" язычок слайдера из рук пользователя, # проверяем, что пользователь НЕ взаимодейтсвует с таймлайном. if not self.is_timeline_dragged: self.timeline.setValue(minutes * 60 + seconds) def loop_or_unloop_current_track(self): """Мини-функция для зацикливания данного трека""" if not self.is_looped_current_track: # Зацикливаем self.is_looped_current_track = True self.queue.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) # Меняем картинку на перечёркнутый круг self.loopBtn.setStyleSheet('background-image: url(icons/unloop.png)') else: # убираем цикл self.is_looped_current_track = False self.queue.setPlaybackMode(self.playlist_handler.mode) self.loopBtn.setStyleSheet('background-image: url(icons/loop.png)') def next_audio(self): """Функция для перемотки на следующий в списке трек""" if self.queue.mediaCount() - 1 == self.queue.currentIndex(): # Если трек ппоследний в списке, возвращаемся к первому self.queue.setCurrentIndex(0) else: # Иначе просто перемещаемся к следующему self.queue.next() def prev_audio(self): """Функция для перемотки на предыдущий в списке трек""" if 0 == self.queue.currentIndex(): # Если трек первый в списке, возвращаемся к последнему self.queue.setCurrentIndex(self.queue.mediaCount() - 1) else: # Иначе просто возвращаемся к предыдущему self.queue.previous() def play_or_pause(self): """Функция для запуска или остановки проигрывателя""" if self.queue.isEmpty(): # Меняем картинку на стрелочку (проигрывание) self.is_playing = False self.playBtn.setStyleSheet('background-image: url(icons/play.png)') # Ставим на паузу self.player.pause() return if self.is_playing: # Меняем картинку на стрелочку (проигрывание) self.is_playing = False self.playBtn.setStyleSheet('background-image: url(icons/play.png)') # Ставим на паузу self.player.pause() else: # Меняем картинку на 2 палочки (пауза) self.is_playing = True self.playBtn.setStyleSheet('background-image: url(icons/pause.png)') # Запускаем звук self.player.play() def change_volume(self): """Мини-Функция для передачи уровня громкости в плеер""" # Функцию использует несколько объектов сразу, проверяем вызывателя if self.sender() == self.volumeBtn: # Если функцию вызвала кнопка, то включаем/выключаем отображение слайдера if not self.volumeSlider.isHidden(): self.volumeSlider.hide() else: self.volumeSlider.show() else: # Иначе функцию вызвал сам слайдер. Значит, меняем значение self.player.setVolume(self.volumeSlider.value()) self.equalizer.setValue(self.volumeSlider.value())
class Music_Player(QWidget, Ui_Form): with open("path.txt", 'r') as f: home_dir = f.read() home_dir = home_dir.rstrip() def __init__(self): #super(Music_Player, self).__init__() super().__init__() #set up the user interface from Designer self.setupUi(self) # this gets the inforation needed for the table lib = [] directory = os.path.join(Music_Player.home_dir, "Music") walk = os.walk(directory) for root, dirs, files in walk: for file in files: path = os.path.join(root, file) if file.endswith( '.mp3'): # then we should add file to library\ song = os.path.splitext(file)[0] song = song.replace('_', ' ') # using eyed3 to get song info audiofile = eyed3.load(path) artist = audiofile.tag.artist album = audiofile.tag.album length_secs = audiofile.info.time_secs # seconds length_formatted = seconds_to_minutes(length_secs) # list of lists with information lib.append([ song, artist, album, length_formatted, path, str(length_secs) ]) # length shows seconds # usedfor the functions self.library = lib self.songTableWidget_tab3.setRowCount(len(lib)) self.songTableWidget_2.setRowCount(len(lib)) self.songTableWidget.setRowCount(len(lib)) self.songTableWidget.setColumnHidden(4, True) #hide path column self.songTableWidget.setColumnHidden( 5, True) #hide length column that shows seconds self.songTableWidget_2.setColumnHidden(4, True) #hide path column self.songTableWidget_2.setColumnHidden( 5, True) #hide length column that shows seconds self.songTableWidget_tab3.setColumnHidden(4, True) #hide path column self.songTableWidget_tab3.setColumnHidden( 5, True) #hide length column that shows seconds self.songTableWidget.setEditTriggers( QAbstractItemView.NoEditTriggers) # no way to edit items self.songTableWidget_tab3.setEditTriggers( QAbstractItemView.NoEditTriggers) # setting the column widths self.songTableWidget.setColumnWidth(0, 220) self.songTableWidget.setColumnWidth(1, 160) self.songTableWidget.setColumnWidth(2, 165) self.songTableWidget.setColumnWidth(3, 60) # setting up touch scrolling for the songTableWidget scroller = QScroller.scroller(self.songTableWidget) QScroller.grabGesture(self.songTableWidget, QScroller.LeftMouseButtonGesture) # setting up touch scrolling for the playlistTableWidget_2 scroller_playlist_2 = QScroller.scroller(self.playlistTableWidget_2) QScroller.grabGesture(self.playlistTableWidget_2, QScroller.LeftMouseButtonGesture) # setting up touch scrolling for the songTableWidget_2 scroller_2 = QScroller.scroller(self.songTableWidget_2) QScroller.grabGesture(self.songTableWidget_2, QScroller.LeftMouseButtonGesture) # setting up touch scrolling for the songTableWidget_tab3 scroller_3 = QScroller.scroller(self.songTableWidget_tab3) QScroller.grabGesture(self.songTableWidget_tab3, QScroller.LeftMouseButtonGesture) # populating the table for i in range(len(lib)): #number of rows for k in range(6): # there are 6 columns item = QTableWidgetItem(lib[i][k]) item2 = QTableWidgetItem(lib[i][k]) item3 = QTableWidgetItem(lib[i][k]) self.songTableWidget.setItem(i, k, item) self.songTableWidget_tab3.setItem(i, k, item2) # for tab3 self.songTableWidget_2.setItem(i, k, item3) self.songTableWidget.sortItems(0, Qt.AscendingOrder) self.songTableWidget_tab3.sortItems(0, Qt.AscendingOrder) # tab 3 # add the check mark boxes so they don't only appear when the song is played for the first time for i in range(self.songTableWidget.rowCount()): self.songTableWidget.item(i, 0).setCheckState(Qt.Unchecked) self.songTableWidget_2.item(i, 0).setCheckState(Qt.Unchecked) # setting up media Player self.player = QMediaPlayer(None) if not os.path.exists("log.txt"): with open("log.txt", 'w') as f: pass # the time doesn't work but the row does # this will load the last song played into the media player, though time will start from 0 with open("log.txt", 'r') as f: info = f.read() if info: row = int(info.split(',')[0]) self.time = int( info.split(',')[1] ) # used in mediaStatusChanged to allow for the startup time song_path = self.songTableWidget.item(row, 4).text() self.player.setMedia(QMediaContent(QUrl.fromLocalFile(song_path))) #self.player.play() # used by mediaStatusChanged to load in the correct place the player left off from #self.startup = 1 else: row = 0 default_song_path = self.songTableWidget.item(0, 4).text() self.player.setMedia( QMediaContent(QUrl.fromLocalFile(default_song_path))) # make adjustments self.volumeSlider.setMaximum(100) self.volumeSlider.setSliderPosition(100) self.volumeLabel.setText(str(100)) self.songSlider.setMinimum(0) self.songSlider.setMaximum( int(self.songTableWidget.item(row, 5).text())) self.endLabel.setText(self.songTableWidget.item(row, 3).text()) self.songPlayingLabel.setText(self.songTableWidget.item(row, 0).text()) # tab 3 signals and slots self.saveButton_tab3.clicked.connect(self.save_click) self.searchEdit_tab3.textChanged.connect(self.search_edit) #conncect buttons self.volumeSlider.valueChanged.connect(self.volume_change) self.playButton.clicked.connect(self.play_click) self.songTableWidget.cellDoubleClicked.connect(self.double_click) self.player.stateChanged.connect( self.state_changed) # playing, paused, no media self.player.positionChanged.connect(self.position_changed) self.player.mediaStatusChanged.connect( self.media_status) # #loading media, end of media, etc. self.player.currentMediaChanged.connect( self.song_changed) # when the song changes self.songSlider.sliderMoved.connect(self.slider_moved) self.songSlider.sliderReleased.connect(self.slider_released) self.nextButton.clicked.connect(self.next) self.prevButton.clicked.connect(self.prev) ################################################################## ########################################################### #################### tab 2 #############################\ self.finaldeleteButton_2.setVisible(False) self.player_2 = QMediaPlayer(None) self.player_2.setVolume(100) # make adjustments self.volumeSlider_2.setMaximum(100) self.volumeSlider_2.setSliderPosition(100) self.volumeLabel_2.setText(str(100)) self.endLabel_2.setText(self.songTableWidget_2.item(0, 3).text()) self.songPlayingLabel_2.setText( self.songTableWidget_2.item(0, 0).text()) self.playlistTableWidget_2.setEditTriggers( QAbstractItemView.NoEditTriggers) self.songTableWidget_2.setEditTriggers( QAbstractItemView.NoEditTriggers) #conncect buttons self.volumeSlider_2.valueChanged.connect(self.volume_change_2) self.playButton_2.clicked.connect(self.play_click_2) self.songTableWidget_2.cellDoubleClicked.connect(self.double_click_2) self.player_2.stateChanged.connect( self.state_changed_2) # playing, paused, no media self.player_2.positionChanged.connect(self.position_changed_2) self.player_2.mediaStatusChanged.connect( self.media_status_2) # #loading media, end of media, etc. self.player_2.currentMediaChanged.connect( self.song_changed_2) # when the song changes self.songSlider_2.sliderMoved.connect(self.slider_moved_2) self.songSlider_2.sliderReleased.connect(self.slider_released_2) self.nextButton_2.clicked.connect(self.next_2) self.prevButton_2.clicked.connect(self.prev_2) # if there are playlists present on the system we want to list them files = os.listdir(Music_Player.home_dir + "/Desktop/music_player/playlists") if files: self.playlistTableWidget_2.setRowCount(len(files)) playlist_names = [os.path.splitext(file)[0] for file in files] x = 0 for file in files: with open( Music_Player.home_dir + '/Desktop/music_player/playlists/{}'.format(file), 'r') as f: lines = f.readlines() amount_of_songs = lines[-2] date_added = lines[-1] playlist_name = os.path.splitext(file)[0] item_1 = QTableWidgetItem(playlist_name) item_2 = QTableWidgetItem(amount_of_songs) item_3 = QTableWidgetItem(date_added) self.playlistTableWidget_2.setItem(x, 0, item_1) self.playlistTableWidget_2.setItem(x, 1, item_2) self.playlistTableWidget_2.setItem(x, 2, item_3) x = x + 1 self.playlistTableWidget_2.cellDoubleClicked.connect( self.choose_playlist) self.playlist_button_2.clicked.connect(self.back_to_playlists) self.deleteButton_2.clicked.connect(self.delete_button_2) self.finaldeleteButton_2.clicked.connect(self.finaldelete_clicked_2) def delete_button_2(self): if self.deleteButton_2.isChecked(): self.playlistTableWidget_2.setSelectionMode( QtWidgets.QAbstractItemView.MultiSelection) # show delete button self.finaldeleteButton_2.setVisible(True) if self.deleteButton_2.isChecked() == False: self.playlistTableWidget_2.setSelectionMode( QtWidgets.QAbstractItemView.ExtendedSelection) self.finaldeleteButton_2.setVisible(False) def finaldelete_clicked_2(self): items = self.playlistTableWidget_2.selectedItems( ) # will have many duplicates in the list that is returned if items: # if list is not empty pass else: self.finalDeleteLabel_2.setText("Must Select Playlist[s]") def back_to_playlists(self): self.stackedWidget.setCurrentIndex(0) def choose_playlist(self, row, column): # when the playlist is clicked ## get back to neutral so we don't keep removing songs from table self.songTableWidget_2.sortItems(0, Qt.AscendingOrder) count = self.songTableWidget_2.rowCount() for k in range(count): self.songTableWidget_2.setRowHidden(k, False) playlist_name = self.playlistTableWidget_2.item(row, 0).text() self.stackedWidget.setCurrentIndex(1) self.playlist_name_2.setText(playlist_name) with open( Music_Player.home_dir + '/Desktop/music_player/playlists/{}.txt'.format(playlist_name), 'r') as f: songs = f.readlines( )[: -2] # the last two lines are amount of songs in the playlist and the date the playlist was created songs = [song.rstrip() for song in songs] items = [] for song in songs: items.append( self.songTableWidget_2.findItems(song, Qt.MatchContains)) items = [item[0] for item in items] rows = {i.row() for i in items} # hiding the songs not in playlist for k in range(count): if k not in rows: self.songTableWidget_2.setRowHidden(k, True) def prev_2(self): path = self.player_2.currentMedia().canonicalUrl().path() item = self.songTableWidget_2.findItems(path, Qt.MatchExactly) row = item[0].row() # gives the index starting at 0 #print(row, self.songTableWidget.rowCount()) if self.player_2.position() >= 2000: self.player_2.setPosition(0) return True if row == 0: print("row==0") for i in range(1, self.songTableWidget_2.rowCount()): next_row = self.songTableWidget_2.rowCount( ) - i # row count starts counting at 1 so index = rowCount -1 if self.songTableWidget_2.isRowHidden(next_row): continue else: break new_song_path = self.songTableWidget_2.item(next_row, 4).text() else: for i in range( 1, self.songTableWidget_2.rowCount()): # 1 to the row count next_row = row - i # all you need is 1 minus the row count to make the list full circle if next_row < 0: next_row = self.songTableWidget_2.rowCount( ) + next_row # then we need be back at the last index if self.songTableWidget_2.isRowHidden(next_row): continue else: break new_song_path = self.songTableWidget_2.item(next_row, 4).text() if self.player_2.state() == QMediaPlayer.PlayingState: self.player_2.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) self.player_2.play() else: self.player_2.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) def next_2(self): path = self.player_2.currentMedia().canonicalUrl().path() item = self.songTableWidget_2.findItems(path, Qt.MatchExactly) row = item[0].row() # gives the index starting at 0 if self.songTableWidget_2.rowCount() == ( row + 1): # then we are at end of table next_row = 0 if self.songTableWidget_2.isRowHidden(next_row): for i in range(1, self.songTableWidget_2.rowCount()): next_row = next_row + i if self.songTableWidget_2.isRowHidden(next_row): continue else: break new_song_path = self.songTableWidget_2.item(next_row, 4).text() else: for i in range(1, self.songTableWidget_2.rowCount()): next_row = row + i if next_row >= self.songTableWidget_2.rowCount( ): # then the index is out of range next_row = next_row - self.songTableWidget_2.rowCount() if self.songTableWidget_2.isRowHidden(next_row): continue else: break new_song_path = self.songTableWidget_2.item(next_row, 4).text() if self.player_2.state() == QMediaPlayer.PlayingState: self.player_2.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) self.player_2.play() else: self.player_2.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) def slider_moved_2(self, value): # signal when slider is pressed down if self.songSlider_2.isSliderDown(): time = seconds_to_minutes(value) self.startLabel_2.setText(time) def slider_released_2(self): seconds = self.songSlider_2.sliderPosition() self.player_2.setPosition(seconds * 1000) def song_changed_2(self, song): # takes QMediaContent path = (song.canonicalUrl().path() ) # path of song used to locate row in table item = self.songTableWidget_2.findItems(path, Qt.MatchExactly) row = item[0].row() # there can only be one match in the list self.songPlayingLabel_2.setText( self.songTableWidget_2.item(row, 0).text()) self.endLabel_2.setText(self.songTableWidget_2.item(row, 3).text()) self.songSlider_2.setMaximum( int(self.songTableWidget_2.item(row, 5).text())) # now need to setup how the slider will work # when slider is pressed down song still plays at normal pace but start label adjusts to where the slider is # shen slider is released then move the song to that position def media_status_2(self, status): # takes QMediaPlayer.MediaStatus if status == QMediaPlayer.BufferedMedia: # get rid of all the check marks on the songs that have been played for i in range(self.songTableWidget_2.rowCount()): self.songTableWidget_2.item(i, 0).setCheckState(Qt.Unchecked) path = self.player_2.currentMedia().canonicalUrl().path() item = self.songTableWidget_2.findItems( path, Qt.MatchExactly) #qtbalewidgetitem row = item[0].row( ) # this finds the row that the qtablewidgetitem originates self.songTableWidget_2.item(row, 0).setCheckState(Qt.Checked) elif status == QMediaPlayer.EndOfMedia: path = self.player_2.currentMedia().canonicalUrl().path() item = self.songTableWidget_2.findItems( path, Qt.MatchExactly) #qtbalewidgetitem row = item[0].row( ) # this finds the row that the qtablewidgetitem originates self.songTableWidget_2.item(row, 0).setCheckState(Qt.Unchecked) print("end of media") def position_changed_2(self, position): # position is expressed in milleseconds seconds = int(position / 1000) # now its in seconds if self.songSlider_2.isSliderDown() == False: self.songSlider_2.setSliderPosition(seconds) time = seconds_to_minutes(seconds) self.startLabel_2.setText(time) def state_changed_2(self, state): if self.player_2.state() == QMediaPlayer.PlayingState: self.playButton_2.setText("Pause") # turns the library player off self.player.pause() if self.player_2.state( ) == QMediaPlayer.PausedState or self.player_2.state( ) == QMediaPlayer.StoppedState: self.playButton_2.setText("Play") def play_click_2(self): if self.player_2.state() == 1: # playing state self.player_2.pause() elif self.player_2.state() == 2: # paused state self.player_2.play() else: # stopped state which = 0 self.player_2.play() def volume_change_2(self, value): self.volumeLabel_2.setText(str(value)) self.player_2.setVolume(value) def double_click_2(self, row, column): #row and column are ints song = self.songTableWidget_2.item( row, 0).text() # this is the cell with song name # returns the qtablewidgetitem need to change it to text path = self.songTableWidget_2.item(row, 4).text() self.songPlayingLabel_2.setText(song) self.player_2.setMedia(QMediaContent(QUrl.fromLocalFile(path))) self.player_2.play() ##################################################################################### ##################################################################################### #################################### tab 3 ########################################### ##################################################################################### ##################################################################################### def search_edit(self, text): # reset at the beginnning so that everything shows up count = self.songTableWidget_tab3.rowCount() for k in range(count): self.songTableWidget_tab3.setRowHidden(k, False) items = self.songTableWidget_tab3.findItems(text, Qt.MatchContains) rows = {i.row() for i in items} count = self.songTableWidget_tab3.rowCount() for k in range(count): if k not in rows: self.songTableWidget_tab3.setRowHidden(k, True) def save_click(self): playlist_name = self.playlistNameEdit_tab3.text() if playlist_name: # will need to check that there is no other playlist name that has the same Name if self.songTableWidget_tab3.selectedItems(): rows_selected = { i.row() for i in self.songTableWidget_tab3.selectedItems() } songs_selected = [ self.songTableWidget_tab3.item(i, 4).text() for i in rows_selected ] print(rows_selected) print(songs_selected) with open( Music_Player.home_dir + '/Desktop/music_player/playlists/{}.txt'.format( playlist_name), 'w') as f: for i in songs_selected: f.write(i + '\n') f.write(str(len(songs_selected)) + '\n') f.write(str(datetime.datetime.now())) # update the playlist table in tab2 files = os.listdir(Music_Player.home_dir + '/Desktop/music_player/playlists') if files: self.playlistTableWidget_2.setRowCount(len(files)) playlist_names = [ os.path.splitext(file)[0] for file in files ] x = 0 for file in files: with open( Music_Player.home_dir + '/Desktop/music_player/playlists/{}'.format( file), 'r') as f: lines = f.readlines() amount_of_songs = lines[-2] date_added = lines[-1] playlist_name = os.path.splitext(file)[0] item_1 = QTableWidgetItem(playlist_name) item_2 = QTableWidgetItem(amount_of_songs) item_3 = QTableWidgetItem(date_added) self.playlistTableWidget_2.setItem(x, 0, item_1) self.playlistTableWidget_2.setItem(x, 1, item_2) self.playlistTableWidget_2.setItem(x, 2, item_3) x = x + 1 else: self.playlist_verifier_tab3.setText("Need to Select Songs") else: self.playlist_verifier_tab3.setText("Not a Valid Name") ############################################################## ########################################################### #################### tab 1 ############################# def prev(self): path = self.player.currentMedia().canonicalUrl().path() item = self.songTableWidget.findItems(path, Qt.MatchExactly) row = item[0].row() # gives the index starting at 0 #print(row, self.songTableWidget.rowCount()) if self.player.position() >= 2000: self.player.setPosition(0) return True if row == 0: next_row = self.songTableWidget.rowCount( ) - 1 # row count starts counting at 1 so index = rowCount -1 new_song_path = self.songTableWidget.item(next_row, 4).text() else: next_row = row - 1 new_song_path = self.songTableWidget.item(next_row, 4).text() if self.player.state() == QMediaPlayer.PlayingState: self.player.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) self.player.play() else: self.player.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) def next(self): path = self.player.currentMedia().canonicalUrl().path() item = self.songTableWidget.findItems(path, Qt.MatchExactly) row = item[0].row() # gives the index starting at 0 if self.songTableWidget.rowCount() == ( row + 1): # then we are at end of table next_row = 0 new_song_path = self.songTableWidget.item(next_row, 4).text() else: next_row = row + 1 new_song_path = self.songTableWidget.item(next_row, 4).text() if self.player.state() == QMediaPlayer.PlayingState: self.player.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) self.player.play() else: self.player.setMedia( QMediaContent(QUrl.fromLocalFile(new_song_path))) def slider_moved(self, value): # signal when slider is pressed down if self.songSlider.isSliderDown(): time = seconds_to_minutes(value) self.startLabel.setText(time) def slider_released(self): seconds = self.songSlider.sliderPosition() self.player.setPosition(seconds * 1000) def song_changed(self, song): # takes QMediaContent path = (song.canonicalUrl().path() ) # path of song used to locate row in table item = self.songTableWidget.findItems(path, Qt.MatchExactly) row = item[0].row() # there can only be one match in the list self.songPlayingLabel.setText(self.songTableWidget.item(row, 0).text()) self.endLabel.setText(self.songTableWidget.item(row, 3).text()) self.songSlider.setMaximum( int(self.songTableWidget.item(row, 5).text())) # now need to setup how the slider will work # when slider is pressed down song still plays at normal pace but start label adjusts to where the slider is # shen slider is released then move the song to that position def media_status(self, status): # takes QMediaPlayer.MediaStatus if status == QMediaPlayer.BufferedMedia: # get rid of all the check marks on the songs that have been played for i in range(self.songTableWidget.rowCount()): self.songTableWidget.item(i, 0).setCheckState(Qt.Unchecked) path = self.player.currentMedia().canonicalUrl().path() item = self.songTableWidget.findItems( path, Qt.MatchExactly) #qtbalewidgetitem row = item[0].row( ) # this finds the row that the qtablewidgetitem originates self.songTableWidget.item(row, 0).setCheckState(Qt.Checked) elif status == QMediaPlayer.EndOfMedia: path = self.player.currentMedia().canonicalUrl().path() item = self.songTableWidget.findItems( path, Qt.MatchExactly) #qtbalewidgetitem row = item[0].row( ) # this finds the row that the qtablewidgetitem originates self.songTableWidget.item(row, 0).setCheckState(Qt.Unchecked) print("end of media") def position_changed(self, position): # position is expressed in milleseconds seconds = int(position / 1000) # now its in seconds if self.songSlider.isSliderDown() == False: self.songSlider.setSliderPosition(seconds) time = seconds_to_minutes(seconds) self.startLabel.setText(time) def state_changed(self, state): if self.player.state() == QMediaPlayer.PlayingState: self.playButton.setText("Pause") self.player_2.pause() if self.player.state( ) == QMediaPlayer.PausedState or self.player.state( ) == QMediaPlayer.StoppedState: self.playButton.setText("Play") def play_click(self): if self.player.state() == 1: # playing state self.player.pause() elif self.player.state() == 2: # paused state self.player.play() else: # stopped state which = 0 self.player.play() def volume_change(self, value): self.volumeLabel.setText(str(value)) self.player.setVolume(value) def double_click(self, row, column): #row and column are ints song = self.songTableWidget.item( row, 0).text() # this is the cell with song name # returns the qtablewidgetitem need to change it to text path = self.songTableWidget.item(row, 4).text() self.songPlayingLabel.setText(song) self.player.setMedia(QMediaContent(QUrl.fromLocalFile(path))) self.player.play() #self.songTableWidget. def closeEvent(self, event): path = self.player.currentMedia().canonicalUrl().path() item = self.songTableWidget.findItems( path, Qt.MatchExactly) #qtbalewidget item row = item[0].row( ) # this finds the row that the qtablewidgetitem originates time = int( self.player.position() / 1000) - 1 # saves the milliseconds from the beginning of the song with open('log.txt', 'w') as f: info = "{},{}".format(str(row), str(time)) f.write(info) event.accept()
class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(1200, 720) Form.setMinimumSize(QtCore.QSize(200, 199)) Form.setStyleSheet("background-color:black;") self.isOnline = False self.isMini = False self.isOnTop = True self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.mainFrame = QtWidgets.QFrame(Form) self.mainFrame.setMinimumSize(QtCore.QSize(200, 82)) self.mainFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.mainFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.mainFrame.setObjectName("mainFrame") self.verticalLayout = QtWidgets.QVBoxLayout(self.mainFrame) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.verticalLayout.setObjectName("verticalLayout") self.frame_3 = QtWidgets.QFrame(self.mainFrame) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.frame_3.sizePolicy().hasHeightForWidth()) self.frame_3.setSizePolicy(sizePolicy) self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_3.setObjectName("frame_3") self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.frame_3) self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.Player_name = QtWidgets.QLabel(self.frame_3) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.Player_name.sizePolicy().hasHeightForWidth()) self.Player_name.setSizePolicy(sizePolicy) self.Player_name.setStyleSheet("QLabel\n" " {\n" " font: 12pt \"Helvetica\";\n" " color: white;\n" " border: 0px solid #076100;\n" " }") self.Player_name.setObjectName("status_label") self.horizontalLayout_6.addWidget(self.Player_name) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_6.addItem(spacerItem) self.minimize_button = QtWidgets.QPushButton(self.frame_3) self.minimize_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.minimize_button.setText("") icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("icon_sets/minimize.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.minimize_button.setIconSize(QSize(25, 17)) self.minimize_button.setMaximumSize(QSize(25, 17)) self.minimize_button.setIcon(icon) self.minimize_button.setIconSize(QtCore.QSize(27, 20)) # self.minimize_button.setFlat(True) self.minimize_button.setObjectName("minimize_button") self.horizontalLayout_6.addWidget(self.minimize_button) self.maximize_button = QtWidgets.QPushButton(self.frame_3) self.maximize_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.maximize_button.setText("") icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("icon_sets/maximize.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.maximize_button.setIcon(icon1) self.maximize_button.setIconSize(QSize(25, 17)) self.maximize_button.setMaximumSize(QSize(25, 17)) self.maximize_button.setIconSize(QtCore.QSize(27, 20)) # self.maximize_button.setFlat(True) self.maximize_button.setObjectName("maximize_button") self.horizontalLayout_6.addWidget(self.maximize_button) self.cross_button = QtWidgets.QPushButton(self.frame_3) self.cross_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.cross_button.setText("") self.cross_button.setIconSize(QSize(25, 17)) self.cross_button.setMaximumSize(QSize(25, 17)) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap("icon_sets/cross.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.cross_button.setIcon(icon2) self.cross_button.setIconSize(QtCore.QSize(27, 20)) # self.cross_button.setFlat(True) self.cross_button.setObjectName("cross_button") self.horizontalLayout_6.addWidget(self.cross_button) self.verticalLayout.addWidget(self.frame_3) self.video_playback = Videowidget(self.frame_3) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(200) sizePolicy.setHeightForWidth( self.video_playback.sizePolicy().hasHeightForWidth()) self.video_playback.setSizePolicy(sizePolicy) self.video_playback.setMinimumSize(QtCore.QSize(200, 100)) self.video_playback.setMouseTracking(False) self.video_playback.setTabletTracking(False) self.video_playback.setAcceptDrops(False) self.video_playback.setAutoFillBackground(False) self.video_playback.setObjectName("video_playback") self.video_playback.setStyleSheet("background-color:grey") self.verticalLayout.addWidget(self.video_playback) self.pos_frame = QtWidgets.QFrame(self.mainFrame) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(10) sizePolicy.setHeightForWidth( self.pos_frame.sizePolicy().hasHeightForWidth()) self.pos_frame.setSizePolicy(sizePolicy) self.pos_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.pos_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.pos_frame.setObjectName("pos_frame") self.horizontalLayout = QtWidgets.QHBoxLayout(self.pos_frame) self.horizontalLayout.setObjectName("horizontalLayout") self.position_slider = PosSlider(self.pos_frame) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(100) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.position_slider.sizePolicy().hasHeightForWidth()) self.position_slider.setSizePolicy(sizePolicy) self.position_slider.setMouseTracking(True) self.position_slider.setAutoFillBackground(False) self.position_slider.setStyleSheet( "QSlider::handle:horizontal \n" " {\n" " background: transparent;\n" " width: 8px;\n" " }\n" "QSlider::groove:horizontal {\n" " border: 1px solid white;\n" " height: 8px;\n" " background: qlineargradient(y1: 0, y2: 1,stop: 0 #2e3436, stop: 1.0 #000000);\n" "}\n" " QSlider::sub-page:horizontal {\n" " background:qlineargradient( y1: 0, y2: 1,\n" " stop: 0 #42a6db, stop: 1 #0074e0); \n" " border: 1px solid white;\n" " height: 8px;\n" "}\n" "QSlider::handle:horizontal:hover {\n" " background: black;\n" " height: 8px;\n" " width: 8px;\n" " border: 1px solid white;\n" " }\n" "") self.position_slider.setOrientation(QtCore.Qt.Horizontal) self.position_slider.setInvertedAppearance(False) self.position_slider.setInvertedControls(False) self.position_slider.setObjectName("position_slider") self.horizontalLayout.addWidget(self.position_slider) self.time_status = QtWidgets.QLabel(self.pos_frame) font = QtGui.QFont() font.setFamily("Arial Rounded MT Bold") font.setPointSize(8) font.setBold(False) font.setItalic(False) font.setWeight(50) self.time_status.setFont(font) self.time_status.setStyleSheet( "QLabel\n" " {\n" " \n" " font: 8pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" "\n" " }") self.time_status.setObjectName("time_status") self.horizontalLayout.addWidget(self.time_status) self.backslash = QtWidgets.QLabel(self.pos_frame) font = QtGui.QFont() font.setFamily("Arial Rounded MT Bold") font.setPointSize(8) font.setBold(False) font.setItalic(False) font.setWeight(50) self.backslash.setFont(font) self.backslash.setStyleSheet( "QLabel\n" " {\n" " \n" " font: 8pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" "\n" " }") self.backslash.setObjectName("backslash") self.horizontalLayout.addWidget(self.backslash) self.duration_status = QtWidgets.QLabel(self.pos_frame) font = QtGui.QFont() font.setFamily("Arial Rounded MT Bold") font.setPointSize(8) font.setBold(False) font.setItalic(False) font.setWeight(50) self.duration_status.setFont(font) self.duration_status.setStyleSheet( "QLabel\n" " {\n" " \n" " font: 8pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" "\n" " }") self.duration_status.setObjectName("duration_status") self.horizontalLayout.addWidget(self.duration_status) self.verticalLayout.addWidget(self.pos_frame) self.frame_2 = QtWidgets.QFrame(self.mainFrame) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(22) # sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) self.frame_2.setSizePolicy(sizePolicy) self.frame_2.setContentsMargins(0, 0, 0, 0) self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) self.frame_2.setObjectName("frame_2") self.frame_2.setStyleSheet("") self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame_2) self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.play_button = QtWidgets.QPushButton(self.frame_2) self.play_button.setEnabled(False) self.play_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.play_button.setStyleSheet( "QPushButton[play=true]{image:url(icon_sets/play/play.png);width:22px;height:22px}\n" "QPushButton[play=false]{image:url(icon_sets/pause/pause.png);width:22px;height:22px }\n" ) self.play_button.setProperty("play", True) self.play_button.setText("") self.play_button.setObjectName("play_button") self.horizontalLayout_4.addWidget(self.play_button) self.playback_button = QtWidgets.QPushButton(self.frame_2) self.playback_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.playback_button.setStyleSheet( "QPushButton{image:url(icon_sets/playback/playback.png);width:22px;height:22px }\n" ) self.playback_button.setText("") self.playback_button.setObjectName("playback_button") self.horizontalLayout_4.addWidget(self.playback_button) self.always_on_top_button = QtWidgets.QPushButton(self.frame_2) self.always_on_top_button.setCursor( QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.always_on_top_button.setStyleSheet( "QPushButton[top=false]{image : url(icon_sets/always_on_top/top_off.png) }\n" "QPushButton[top=true]{image : url(icon_sets/always_on_top/top_on.png) }\n" ) self.always_on_top_button.setProperty("top", True) self.always_on_top_button.setText("") self.always_on_top_button.setObjectName("always_on_top_button") self.horizontalLayout_4.addWidget(self.always_on_top_button) self.miniplayer_button = QtWidgets.QPushButton(self.frame_2) self.miniplayer_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.miniplayer_button.setStyleSheet( "QPushButton[mini=false]{image : url(icon_sets/standard_player/standard.png) }\n" # "QPushButton[mini=false]:hover{ image:url(icon_sets/standard_player/.png) }\n" "QPushButton[mini=true]{image : url(icon_sets/mini_player/mini.png) }\n" # "QPushButton[mini=true]:hover{ image:url(icon_sets/mini_player/.png) }\n" ) self.miniplayer_button.setProperty("mini", False) self.miniplayer_button.setContentsMargins(0, 0, 0, 0) self.miniplayer_button.setText("") self.miniplayer_button.setObjectName("miniplayer_button") self.horizontalLayout_4.addWidget(self.miniplayer_button) self.open_File_button = QtWidgets.QPushButton(self.frame_2) self.open_File_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.open_File_button.setStyleSheet( "QPushButton{image:url(icon_sets/new_file/new_file.png);width:22px;height:22px }\n" ) self.open_File_button.setText("") self.open_File_button.setObjectName("playback_button") self.horizontalLayout_4.addWidget(self.open_File_button) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_4.addItem(spacerItem1) self.screenshot_button = QtWidgets.QPushButton(self.frame_2) self.screenshot_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.screenshot_button.setStyleSheet( "QPushButton{image : url(icon_sets/snapshot/snapshot.png);width:22px;height:22px} \n" ) self.screenshot_button.setText("") self.screenshot_button.setObjectName("screenshot_button") self.horizontalLayout_4.addWidget(self.screenshot_button) ''' Video Setting button for Video subs and dubs''' # self.video_setting_button = QtWidgets.QPushButton(self.frame_2) # self.video_setting_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) # self.video_setting_button.setText("") # self.video_setting_button.setIconSize(QtCore.QSize(22, 22)) # self.video_setting_button.setStyleSheet("QPushButton{image : url(icon_sets/video_setting/video_settings.png) }\n" # ) # self.video_setting_button.setObjectName("video_setting_button") # self.horizontalLayout_4.addWidget(self.video_setting_button) self.setting_button = QtWidgets.QPushButton(self.frame_2) self.setting_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.setting_button.setStyleSheet( "QPushButton{image : url(icon_sets/settings/settings.png) }\n") self.setting_button.setText("") self.setting_button.setObjectName("setting_button") self.horizontalLayout_4.addWidget(self.setting_button) self.Quality_box = QtWidgets.QComboBox(self.frame_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.Quality_box.sizePolicy().hasHeightForWidth()) self.Quality_box.setSizePolicy(sizePolicy) self.Quality_box.setStyleSheet( "QComboBox\n" " {\n" " border-image :url(icon_sets/quality/border.png);\n" " color: #fcffff;\n" " font-size: 8pt;\n" " font-weight: bold;\n" # " width: 41px;\n" " background-color: #000000;\n" " }\n" " QComboBox QAbstractItemView \n" " {\n" " background: #fcffff;\n" " border: 2px solid darkgray;\n" " selection-background-color: #000000;\n" " }\n" "QComboBox::drop-down {\n" " border: 0px;\n" " subcontrol-origin: padding;\n" " subcontrol-position: top right;\n" "\n" " border-top-right-radius: 3px;\n" " border-bottom-right-radius: 3px;\n" "}\n") self.Quality_box.setIconSize(QtCore.QSize(0, 0)) self.Quality_box.setDuplicatesEnabled(False) self.Quality_box.setObjectName("comboBox") self.Quality_box.addItem(" -") self.horizontalLayout_4.addWidget(self.Quality_box) self.volume_button = QtWidgets.QPushButton(self.frame_2) self.volume_button.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.volume_button.setText("") icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volume_button.setIconSize(QtCore.QSize(22, 22)) self.volume_button.setCheckable(True) # self.volume_button.setFlat(True) self.volume_button.setObjectName("volume_button") self.horizontalLayout_4.addWidget(self.volume_button) self.volumeslider = VolSlider(self.frame_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.volumeslider.sizePolicy().hasHeightForWidth()) self.volumeslider.setSizePolicy(sizePolicy) self.volumeslider.setAutoFillBackground(False) self.volumeslider.setStyleSheet( "QSlider::handle:horizontal \n" " {\n" " background: transparent;\n" " width: 5px;\n" " }\n" "QSlider::groove:horizontal {\n" " border: 1px solid #444444;\n" " height: 5px;\n" " background: qlineargradient(y1: 0, y2: 1,stop: 0 grey, stop: 1.0 grey);\n" "}\n" " QSlider::sub-page:horizontal {\n" " background:qlineargradient( y1: 0, y2: 1,\n" " stop: 0 #42a6db, stop: 1 #0074e0); \n" " border: 1px solid #777;\n" " height: 5px;\n" "}\n" "QSlider::handle:horizontal:hover {\n" " background: black;\n" " height: 5px;\n" " width: 5px;\n" " border: 1px solid #0074e0;\n" " }\n" "QSlider::sub-page:horizontal:disabled{background:qlineargradient( y1: 0, y2: 1,\n" " stop: 0 #909090, stop: 1 #A8A8A8 );}\n" "") self.volumeslider.setOrientation(QtCore.Qt.Horizontal) self.volumeslider.setObjectName("volume_slider") self.horizontalLayout_4.addWidget(self.volumeslider) self.volume_percentage = QtWidgets.QLabel(self.frame_2) self.volume_percentage.setStyleSheet( "QLabel\n" " {\n" " font: 7pt \"Arial Rounded MT Bold\";\n" " color: white;\n" " border: 0px solid #076100;\n" " }") self.volume_percentage.setObjectName("volume_status") self.volume_percentage.setMinimumWidth(35) self.volume_percentage.setText(" 75 %") self.horizontalLayout_4.addWidget(self.volume_percentage) self.verticalLayout.addWidget(self.frame_2) self.frame = QtWidgets.QFrame(self.mainFrame) font = QtGui.QFont() font.setFamily("Lucida Console") self.frame.setFont(font) self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.frame.setFrameShadow(QtWidgets.QFrame.Raised) self.frame.setObjectName("frame") self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.frame) self.horizontalLayout_5.setObjectName("horizontalLayout_5") sizegrip_2 = QtWidgets.QSizeGrip(Form) sizegrip_2.setStyleSheet("image:url(icon_sets/.png)") self.horizontalLayout_5.addWidget( sizegrip_2, 0, QtCore.Qt.AlignBottom | QtCore.Qt.AlignLeft) # self.enter_url_label = QtWidgets.QLabel(self.frame) # font = QtGui.QFont() # font.setFamily("Arial Rounded MT Bold") # font.setPointSize(8) # font.setBold(False) # font.setItalic(False) # font.setWeight(50) # self.enter_url_label.setFont(font) # self.enter_url_label.setStyleSheet("QLabel\n" # " {\n" # " \n" # " font: 8pt \"Arial Rounded MT Bold\";\n" # " color: white;\n" # " border: 0px solid #076100;\n" # " }") # self.enter_url_label.setObjectName("enter_url_label") # self.horizontalLayout_5.addWidget(self.enter_url_label) self.url_box = QtWidgets.QComboBox(self.frame) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(200) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.url_box.sizePolicy().hasHeightForWidth()) self.url_box.setSizePolicy(sizePolicy) self.url_box.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.url_box.setMouseTracking(False) self.url_box.setAcceptDrops(False) self.url_box.setWhatsThis("") self.url_box.setAccessibleDescription("") self.url_box.setAutoFillBackground(True) self.url_box.setStyleSheet("QComboBox\n" " {\n" " border: 2px solid #0074e0;\n" " color: #fcffff;\n" " font-size: 8pt;\n" " font-weight: bold;\n" " background-color: #000000;\n" " border-radius: 6px;\n" " }\n" " QComboBox QAbstractItemView \n" " {\n" " background: #fcffff;\n" " border: 2px solid darkgray;\n" " selection-background-color: #000000;\n" " }\n" "QComboBox::down-arrow {\n" " image: url(icon_sets/url/url4.png)\n" "}\n" "QComboBox::drop-down {\n" " subcontrol-origin: padding;\n" " subcontrol-position: top right;\n" " width: 20px;\n" " \n" " border-top-right-radius: 3px;\n" " border-bottom-right-radius: 3px;\n" "}") self.url_box.setInputMethodHints(QtCore.Qt.ImhUrlCharactersOnly) self.url_box.setEditable(True) self.url_box.setCurrentText("") self.url_box.setMaxVisibleItems(100) self.url_box.setMaxCount(100) self.url_box.setInsertPolicy(QtWidgets.QComboBox.InsertAtCurrent) self.url_box.setSizeAdjustPolicy( QtWidgets.QComboBox.AdjustToContentsOnFirstShow) self.url_box.setMinimumContentsLength(2) self.url_box.setIconSize(QtCore.QSize(20, 20)) self.url_box.setDuplicatesEnabled(False) self.url_box.setFrame(True) self.url_box.setObjectName("url_box") self.horizontalLayout_5.addWidget(self.url_box) self.verticalLayout.addWidget(self.frame) sizegrip_1 = QtWidgets.QSizeGrip(Form) sizegrip_1.setStyleSheet( "image:url(icon_sets/size.png);width:15; height:18;") self.horizontalLayout_5.addWidget( sizegrip_1, 0, QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight) self.verticalLayout_2.addWidget(self.mainFrame) self.retranslateUi(Form) self.url_box.setCurrentIndex(-1) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Q-Stream Player")) self.Player_name.setText(_translate("Form", "Q-Stream Player")) self.time_status.setText(_translate("Form", "00:00:00")) self.backslash.setText(_translate("Form", "/")) self.duration_status.setText(_translate("Form", "00:00:00")) # self.enter_url_label.setText(_translate("Form", statusList[4])) # Set intial Volume self.volumeslider.setRange(0, 100) self.volumeslider.setValue(75) self.mediaPlayer.setVolume(75) self.position_slider.setRange(0, 100) # connecting buttons self.miniplayer_button.clicked.connect(self.setupMiniPlayer) self.position_slider.sliderMoved.connect(self.setPosition) self.position_slider.sliderMoved.connect(self.handleLabel) self.volume_button.clicked.connect(self.mute) self.volumeslider.valueChanged.connect(self.setVolume) self.screenshot_button.clicked.connect(self.screenshot) self.playback_button.clicked.connect(self.stopplayback) self.always_on_top_button.clicked.connect(self.checkOnTop) self.play_button.clicked.connect(self.play) self.open_File_button.clicked.connect(self.openFile) # self.video_setting_button.clicked.connect(self.handleQuality) self.setting_button.clicked.connect(self.handleSetting) self.Quality_box.currentTextChanged.connect(self.handleQuality) self.cross_button.clicked.connect(self.exit) self.maximize_button.clicked.connect(self.max) self.minimize_button.clicked.connect(self.min) # Shortcuts shortcut = QShortcut(QKeySequence('Esc'), self.video_playback) shortcut.activated.connect(self.EscFun) shortcut = QShortcut(QKeySequence('Space'), self.video_playback) shortcut.activated.connect(self.play) shortcut = QShortcut(QKeySequence('f'), self.video_playback) shortcut.activated.connect(self.fullscreen_video) shortcut = QShortcut(QKeySequence('c'), self.video_playback) shortcut.activated.connect(self.setupMiniPlayer) shortcut = QShortcut(QKeySequence('o'), self.video_playback) shortcut.activated.connect(self.openFile) shortcut = QShortcut(QKeySequence('a'), self.video_playback) shortcut.activated.connect(self.checkOnTop) shortcut = QShortcut(QKeySequence("Return"), self.video_playback) shortcut.activated.connect(self.playOnline) shortcut = QShortcut(QKeySequence('m'), self.video_playback) shortcut.activated.connect(self.mute) shortcut = QShortcut(QKeySequence(Qt.Key_Right), self.video_playback) shortcut.activated.connect(self.forwardSlider) shortcut = QShortcut(QKeySequence(Qt.Key_Left), self.video_playback) shortcut.activated.connect(self.backSlider) self.volupshortcut = QShortcut(QKeySequence(Qt.Key_Up), self.video_playback) self.volupshortcut.activated.connect(self.volumeUp) self.voldownshortcut = QShortcut(QKeySequence(Qt.Key_Down), self.video_playback) self.voldownshortcut.activated.connect(self.volumeDown) shortcut = QShortcut(QKeySequence(Qt.ControlModifier + Qt.Key_Right), self.video_playback) shortcut.activated.connect(self.forwardSlider10) shortcut = QShortcut(QKeySequence(Qt.ControlModifier + Qt.Key_Left), self.video_playback) shortcut.activated.connect(self.backSlider10) shortcut = QShortcut(QKeySequence(Qt.AltModifier + Qt.Key_Left), self.video_playback) shortcut.activated.connect(self.backSlider5) shortcut = QShortcut(QKeySequence(Qt.AltModifier + Qt.Key_Right), self.video_playback) shortcut.activated.connect(self.forwardSlider5) # loading history to Url Box items = self.load() self.url_box.addItems(items) self.url_box.setCurrentIndex(-1) # icon size # iconSize = QSize(5,5) # self.play_button.setIconSize(iconSize) # self.playback_button.setIconSize(iconSize) # self.screenshot_button.setIconSize(iconSize) # self.always_on_top_button.setIconSize(iconSize) # self.miniplayer_button.setIconSize(iconSize) # self.setting_button.setIconSize(iconSize) # self.volume_button.setIconSize(iconSize) # button size btnSize = QSize(22, 22) self.play_button.setMaximumSize(btnSize) self.playback_button.setMaximumSize(btnSize) self.screenshot_button.setMaximumSize(btnSize) self.always_on_top_button.setMaximumSize(btnSize) self.miniplayer_button.setMaximumSize(btnSize) # self.video_setting_button.setMaximumSize(btnSize) self.setting_button.setMaximumSize(btnSize) self.volume_button.setMaximumSize(btnSize) # set margin self.horizontalLayout.setContentsMargins(10, 5, 9, 0) self.horizontalLayout_4.setContentsMargins(9, 0, 9, 0) self.horizontalLayout_4.setSpacing(4) self.horizontalLayout_5.setContentsMargins(0, 5, 5, 5) self.horizontalLayout_6.setContentsMargins(9, 0, 9, 0) # Media player settings self.mediaPlayer.setVideoOutput(self.video_playback) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) def handleLabel(self): self.time_status.clear() mtime = QtCore.QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.time_status.setText(self.time.toString()) def hide_all(self): self.frame_3.close() # self.frame.close() self.url_box.close() self.playback_button.close() self.screenshot_button.close() self.Quality_box.close() self.volume_button.close() # self.video_setting_button.close() # self.setting_button.close() def show_all(self): self.frame_3.show() # self.frame.show() self.url_box.show() self.playback_button.show() self.screenshot_button.show() self.Quality_box.show() self.volume_button.show() # self.video_setting_button.show() self.setting_button.show() def checkOnTop(self): self.isOnTop = not self.isOnTop if self.isOnTop: self.always_on_top_button.setProperty("top", True) self.always_on_top_button.setStyle( self.always_on_top_button.style()) Form.setWindowFlags(Form.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) else: self.always_on_top_button.setProperty("top", False) self.always_on_top_button.setStyle( self.always_on_top_button.style()) Form.setWindowFlags(Form.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint) Form.show() def miniProperty(self): self.video_playback.setMinimumSize(QSize(200, 100)) self.video_playback.resize(QSize(550, 270)) Form.resize(QSize(550, 270)) Form.setMinimumSize(QSize(200, 175)) self.mainFrame.setMinimumSize(QSize(200, 60)) self.mainFrame.resize(QSize(200, 53)) def standardProperty(self): self.video_playback.setMinimumSize(QSize(200, 100)) self.mainFrame.setMinimumSize(QSize(200, 82)) Form.setMinimumSize(QSize(200, 202)) Form.resize(550, 369) def setupMiniPlayer(self): self.isMini = not self.isMini if self.isMini: self.miniplayer_button.setProperty("mini", True) self.miniplayer_button.setStyle(self.miniplayer_button.style()) self.hide_all() self.miniProperty() else: self.miniplayer_button.setProperty("mini", False) self.miniplayer_button.setStyle(self.miniplayer_button.style()) self.standardProperty() self.show_all() def load(self): scorefile = "db.bat" if os.path.exists(scorefile): with open(scorefile, 'rb') as sf: scores = pickle.load(sf) else: scores = [] with open(scorefile, "wb") as sf: pickle.dump(scores, sf) return scores def scor_func(self, url): scorefile = "db.bat" if os.path.exists(scorefile): with open(scorefile, 'rb') as sf: scores = pickle.load(sf) else: scores = [] scores.append(url) with open(scorefile, "wb") as sf: if len(scores) > 100: print("here", scores) scores = scores[1:] pickle.dump(scores, sf) return scores def mute(self): if self.mediaPlayer.isMuted(): print('[ ! Full Volume]') self.mediaPlayer.setMuted(False) icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volume_button.setIconSize(QSize(22, 22)) self.volumeslider.setEnabled(True) # shortcut Enable self.volupshortcut.setEnabled(True) self.voldownshortcut.setEnabled(True) else: print('[ ! Mute Volume]') self.mediaPlayer.setMuted(True) icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volume_button.setIconSize(QSize(22, 22)) self.volumeslider.setEnabled(False) # shrotcut disable self.volupshortcut.setEnabled(False) self.voldownshortcut.setEnabled(False) def play(self): if self.mediaPlayer.isVideoAvailable(): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: print("[ ! PAUSE PRESSED ]") self.mediaPlayer.pause() else: print("[ ! PLAY PRESSED ]") self.mediaPlayer.play() def playOnline(self): if self.url_box.currentText() != '': print('[ ! GETTING VIDEO ONLINE ]') fileName = self.url_box.currentText() res = requests.get('https://mediaplayerserver.herokuapp.com/', params={"key": fileName}) try: self.streams = json.loads(res.text) try: self.mediaPlayer.setMedia( QMediaContent(QUrl(self.streams['best']))) self.play_video() self.isOnline = True self.addQuality() if self.url_box.findText(fileName, Qt.MatchExactly) < 0: self.url_box.addItem(fileName) self.scor_func(fileName) except KeyError: print("[ ! Error Video Not Supported By platform]") except json.JSONDecodeError: print("[ ! Error NoPluginError]") finally: self.url_box.setCurrentText("") def openFile(self): print('[ ! OPEN FILE ]') username = getpass.getuser() if sys.platform == 'win32': path = 'C:/Users/' + username + '/Videos/' elif sys.platform == 'linux' or sys.platform == 'Darwin': path = '/home/' + username + '/Videos/' formats = str.join(' ', [ '*.%s' % str(fmt).strip('b').strip("'") for fmt in QtGui.QMovie.supportedFormats() ]) fileName, _ = QFileDialog.getOpenFileName( self.video_playback, "Select media file", path, "Video Files (*.mp4 *.flv *.ts *.mts *.avi *.mkv)") if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.play_video() # def decodeLink(self,url): # try: # streams = streamlink.streams(url) # keys = [k for k in streams.keys()] # data = dict() # for k in keys: # data[k] = streams[k].url # return data # except streamlink.NoPluginError: # return None # def playOnline(self): # if self.url_box.currentText() != '': # print('[ ! GETTING VIDEO ONLINE ]') # fileName = self.url_box.currentText() # self.streams = self.decodeLink(fileName) # try: # self.mediaPlayer.setMedia(QMediaContent(QUrl(self.streams['best']))) # self.play_video() # self.isOnline = True # self.addQuality() # if self.url_box.findText(fileName, Qt.MatchExactly) < 0: # self.url_box.addItem(fileName) # self.scor_func(fileName) # except KeyError: # print("[ ! Error Video Not Supported By platform]") # finally: # self.url_box.setCurrentText("") def play_video(self): print('[ ! PLAYING VIDEO ]') self.play_button.setEnabled(True) if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): print('[ ! CHANGING MEDIA STATE ]') if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.play_button.setProperty('play', False) self.play_button.setStyle(self.play_button.style()) else: self.play_button.setProperty('play', True) self.play_button.setStyle(self.play_button.style()) def stopplayback(self): print('[ ! STOP PLAYBACK VIDEO ]') self.mediaPlayer.stop() self.play_video() def positionChanged(self, position): print('[ ! POSITION CHANGED ]') self.position_slider.setValue(position) def durationChanged(self, duration): print('[ ! DURATION CHANGED ]') self.position_slider.setRange(0, duration) self.duration_status.clear() mtime = QtCore.QTime(0, 0, 0, 0) time = mtime.addMSecs(self.mediaPlayer.duration()) self.duration_status.setText(time.toString()) def setPosition(self, position): print('[ ! POSITION SET ]') self.mediaPlayer.setPosition(position) def setVolumePos(self, remain): print('[ ! REMANING VOLUME ]') print(remain) self.volumeslider.setRange(remain, 100) def setVolume(self, vol): print('[ ! SET VOLUME ]') print("set volume = " + str(vol)) if vol >= 0 and vol <= 100: self.volume_percentage.setText(" " + str(vol) + " %") if vol <= 0: icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) else: icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("icon_sets/volume/volume1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.volume_button.setIcon(icon9) self.volumeslider.setValue(vol) self.mediaPlayer.setVolume(vol) def screenshot(self): print('[ ! SCREENSHOT ]') wincen = Form.geometry() topX = wincen.topLeft().x() topY = wincen.topLeft().y() geo = self.video_playback.geometry() image = pyautogui.screenshot(region=(topX, topY + 38, geo.width(), geo.height() - 35)) filename = "screenshot" + str(uuid.uuid4()) + ".png" username = getpass.getuser() if sys.platform == 'win32': path = 'C:/Users/' + username + '/Pictures/' + filename elif sys.platform == 'linux' or sys.platform == 'Darwin': path = '/home/' + username + '/Pictures/' + filename image.save(path) def EscFun(self): if self.video_playback.isFullScreen(): Form.show() self.video_playback.setFullScreen(False) def fullscreen_video(self): if self.mediaPlayer.isVideoAvailable(): if self.video_playback.isFullScreen(): self.video_playback.setFullScreen(False) print('[ ! Normal Screen ]') Form.show() else: print('[ ! Full Screen ]') self.video_playback.setFullScreen(True) Form.hide() def getFormat(self): li = [k for k in self.streams.keys()] for q in li: if q.startswith('audio'): li.remove(q) try: li.remove('audio_opus') except ValueError: pass return li def changeQuality(self, quality): pos = self.mediaPlayer.position() try: self.mediaPlayer.setMedia( QMediaContent(QUrl(self.streams[quality]))) except KeyError: pass self.setPosition(pos) self.mediaPlayer.play() def handleSetting(self): from setting import SettingDialog dlg = SettingDialog() dlg.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) dlg.exec_() def addQuality(self): self.Quality_box.clear() self.Quality_box.addItems(self.getFormat()) def handleQuality(self): if self.isOnline: self.changeQuality(self.Quality_box.currentText()) def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000) def forwardSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000) def forwardSlider5(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 5000) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000) def backSlider10(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000) def backSlider5(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 5000) def volumeUp(self): self.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def max(self): if not Form.isMaximized(): print("[! Window is Maximized]") Form.showMaximized() else: print("[! Window is Normal]") Form.showNormal() def min(self): if not Form.isMinimized(): print("[! Window is Minimized]") Form.showMinimized() else: print("[! Window is Normal]") Form.showNormal() def exit(self): self.mediaPlayer.stop() sys.exit()
class clipEditor(QMainWindow): downloaded_more_scripts = pyqtSignal() def __init__(self, videoWrapper): QtWidgets.QWidget.__init__(self) uic.loadUi(f"{current_path}/UI/ClipEditor.ui", self) try: self.setWindowIcon(QIcon('Assets/tiktoklogo.png')) except Exception as e: pass #Variables and stuff for the editor to send to the video generator self.videoWrapper = videoWrapper self.mainCommentIndex = 0 self.populateTreeWidget() self.treeWidget.currentItemChanged.connect(self.setSelection) self.treeWidget.clicked.connect(self.setSelection) self.downloaded_more_scripts.connect(self.receiveMoreClips) self.introClipPath = None self.firstClipPath = None self.intervalClipPath = None self.outroClipPath = None self.keep = [] #All of the stuff to make the clip editor work self.playlist = QMediaPlaylist() vid_path = QUrl.fromLocalFile(f'{current_path}/VideoFiles') self.mediaPlayer = QMediaPlayer() self.playPauseButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) #self.addClipsToPlaylist() self.mediaPlayer.stateChanged.connect(self.playPauseMedia) self.mediaPlayer.setVideoOutput(self.clipPlayer) self.mediaPlayer.setPlaylist(self.playlist) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.videoDurationSlider.sliderMoved.connect(self.setPosition) self.defaultIntro.stateChanged.connect(self.defaultIntroToggle) self.chooseFirstClip.clicked.connect(self.firstClipFileDialog) self.chooseIntro.clicked.connect(self.introFileDialog) self.chooseInterval.clicked.connect(self.intervalFileDialog) self.chooseOutro.clicked.connect(self.outroFileDialog) self.timer = QTimer(self, interval=1) self.timer.start() self.mediaPlayer.positionChanged.connect(self.vidTimeStamp) self.playPauseButton.clicked.connect(self.play) self.skipButton.clicked.connect(self.skipComment) self.downloadMore.clicked.connect(self.downloadMoreScripts) self.keepButton.clicked.connect(self.keepComment) self.exportButton.clicked.connect(self.videoExportConfirmation) self.moveDown.clicked.connect(self.moveClipDown) self.moveUp.clicked.connect(self.moveClipUp) #self.nextButton.clicked.connect(self.nextClip) self.playlist.currentIndexChanged.connect(self.checkForLastClip) if settings.enforceInterval: self.loadDefaultInterval() else: self.chooseInterval.hide() self.defaultInterval.hide() if settings.enforceIntro: self.loadDefaultIntro() else: self.chooseIntro.hide() self.defaultIntro.hide() if settings.enforceOutro: self.loadDefaultOutro() else: self.chooseOutro.hide() self.defaultOutro.hide() if not settings.enforceFirstClip: self.chooseFirstClip.hide() self.firstClipCred.hide() self.firstClipNameLabel.hide() self.updateDisplay() def muteBackgroundVolume(self): self.backgroundVolume.setText("0") def defaultIntroToggle(self): print(self.defaultIntro.isChecked()) def receiveMoreClips(self): self.populateTreeWidget() def downloadMoreScripts(self): self.gameSelect = ClipDownloadMenu(self) self.gameSelect.show() pass def moveClipDown(self): self.videoWrapper.scriptWrapper.moveUp(self.mainCommentIndex) self.updateDisplay() def moveClipUp(self): self.videoWrapper.scriptWrapper.moveDown(self.mainCommentIndex) self.updateDisplay() def updateDisplay(self): #self.scriptWrapper.saveScriptWrapper() self.getCurrentWidget(self.mainCommentIndex).setForeground( 0, QtGui.QBrush(QtGui.QColor("blue"))) twitchclip = self.videoWrapper.scriptWrapper.getCommentInformation( self.mainCommentIndex) mp4file = twitchclip.mp4 video_duration = twitchclip.vid_duration audio = twitchclip.audio self.clipTitle.setText( f'{twitchclip.author_name}-{twitchclip.clip_name}') self.likeCount.setText("Likes: %s" % twitchclip.diggCount) self.shareCount.setText("Shares: %s" % twitchclip.shareCount) self.playCount.setText("Plays: %s" % twitchclip.playCount) self.commentCount.setText("Comments: %s" % twitchclip.commentCount) self.updateClipDuration() self.mediaPlayer.stop() if len(mp4file.split("/")) > 2: self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(f'{current_path}/{mp4file}'))) else: self.mediaPlayer.setMedia( QMediaContent( QUrl.fromLocalFile( f'{current_path}/TempClips/{mp4file}.mp4'))) self.mediaPlayer.setVolume(audio * 100) self.estTime.setText( str(self.videoWrapper.scriptWrapper.getEstimatedVideoTime())) self.videoLength.setText(f'{round(video_duration, 1)}') self.mediaPlayer.play() self.clipCountLabel.setText( f"Clip {self.mainCommentIndex+1}/{len(self.videoWrapper.scriptWrapper.rawScript)}" ) def setSelection(self): try: self.currentTreeWidget = self.treeWidget.currentItem() if self.currentTreeWidget.parent() is None: self.mainCommentIndex = int( str(self.currentTreeWidget.text(0)).split(" ")[1]) self.updateColors() self.updateDisplay() except Exception: print("error trying to update selection index") def getCurrentWidget(self, x): return self.getTopLevelByName("Vid %s" % str(x)) def incrimentSelection(self): if not self.mainCommentIndex + 1 > self.videoWrapper.scriptWrapper.getCommentAmount( ) - 1: self.mainCommentIndex += 1 def updateColors(self): for x, mainComment in enumerate( self.videoWrapper.scriptWrapper.scriptMap): self.selectedMainComment = self.getTopLevelByName("Vid %s" % str(x)) if mainComment is True: self.selectedMainComment.setForeground( 0, QtGui.QBrush(QtGui.QColor("green"))) else: self.selectedMainComment.setForeground( 0, QtGui.QBrush(QtGui.QColor("red"))) def keepComment(self): self.videoWrapper.scriptWrapper.keep(self.mainCommentIndex) self.incrimentSelection() self.updateColors() self.updateDisplay() def skipComment(self): self.videoWrapper.scriptWrapper.skip(self.mainCommentIndex) self.updateColors() self.nextMainComment() self.updateDisplay() def nextMainComment(self): if not self.mainCommentIndex + 1 > self.videoWrapper.scriptWrapper.getCommentAmount( ) - 1: self.mainCommentIndex += 1 self.selectedMainComment = self.getTopLevelByName( "Main Comment %s" % str(self.mainCommentIndex)) def populateTreeWidget(self): self.treeWidget.clear() for i, clip in enumerate(self.videoWrapper.scriptWrapper.rawScript): treeParentName = "Vid %s" % str(i) self.addTopLevel(treeParentName) self.selectedMainComment = self.getTopLevelByName("Vid %s" % str(0)) self.updateColors() def getTopLevelByName(self, name): for index in range(self.treeWidget.topLevelItemCount()): item = self.treeWidget.topLevelItem(index) if item.text(0) == name: return item return None def addTopLevel(self, name): if self.getTopLevelByName(name) is None: QTreeWidgetItem(self.treeWidget, [name]) def checkForLastClip(self): if self.playlist.currentIndex() == len(self.startCut) - 1: self.playlist.setPlaybackMode(0) def updateClipDuration(self): twitchclip = self.videoWrapper.scriptWrapper.getCommentInformation( self.mainCommentIndex) #self.clipDurationLabel.setText(f'Clip Duration: {duration}') #Getting the timestamp for the video player def vidTimeStamp(self): self.timeStamp.setText(f"00:{self.getPositionInSecs()}") #Controlling the play/pause of the videos, kinda obvious def playPauseMedia(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playPauseButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playPauseButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) #Giving the play button function def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() #This makes the duration slider move with the video def positionChanged(self, position): self.videoDurationSlider.setValue(position) #Sets the range of each slider to the duration of each video def durationChanged(self, duration): self.videoDurationSlider.setRange(0, duration) #This is to control the position of the video in the media player so I can control the video with the duration slider def setPosition(self, position): self.mediaPlayer.setPosition(position) self.mediaPlayer.play() def introFileDialog(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getOpenFileName( self, "Select The Intro Clip", f"{current_path}/Intros", "All Files (*);;MP4 Files (*.mp4)", options=options) if fileName: try: vid = cv2.VideoCapture(fileName) height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT) width = vid.get(cv2.CAP_PROP_FRAME_WIDTH) if width != int(1920) or height != int(1080): self.uploadFail( "Incorrect resolution for file %s.\n Resolution was %sx%s, required 1920x1080" % (fileName, width, height)) else: self.introClipPath = fileName self.chooseIntro.setText("Reselect Intro") except Exception as e: self.uploadFail("Error occured uploading file \n %s" % (e)) def outroFileDialog(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getOpenFileName( self, "Select The Outro Clip", f"{current_path}/Outros", "All Files (*);;MP4 Files (*.mp4)", options=options) if fileName: try: vid = cv2.VideoCapture(fileName) height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT) width = vid.get(cv2.CAP_PROP_FRAME_WIDTH) if int(width) != 1920 or int(height) != 1080: self.uploadFail( "Incorrect resolution for file %s.\n Resolution was %sx%s, required 1920x1080" % (fileName, width, height)) else: self.outroClipPath = fileName self.chooseOutro.setText("Reselect Outro") except Exception as e: self.uploadFail("Error occured uploading file \n %s" % (e)) def intervalFileDialog(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getOpenFileName( self, "Select The Interval Clip", f"{current_path}/Intervals", "All Files (*);;MP4 Files (*.mp4)", options=options) if fileName: try: vid = cv2.VideoCapture(fileName) height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT) width = vid.get(cv2.CAP_PROP_FRAME_WIDTH) if int(width) != 1920 or int(height) != 1080: self.uploadFail( "Incorrect resolution for file %s.\n Resolution was %sx%s, required 1920x1080" % (fileName, width, height)) else: self.intervalClipPath = fileName self.chooseInterval.setText("Reselect Interval") except Exception as e: self.uploadFail("Error occured uploading file \n %s" % (e)) def firstClipFileDialog(self): options = QFileDialog.Options() fileName, _ = QFileDialog.getOpenFileName( self, "Select The First Clip", f"{current_path}/FirstClips", "All Files (*);;MP4 Files (*.mp4)", options=options) if fileName: # name = len(fileName.split("/")) # self.firstClipPath = (fileName.split("/")[name-1]) try: vid = cv2.VideoCapture(fileName) height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT) width = vid.get(cv2.CAP_PROP_FRAME_WIDTH) if int(width) != 1920 or int(height) != 1080: self.uploadFail( "Incorrect resolution for file %s.\n Resolution was %sx%s, required 1920x1080" % (fileName, width, height)) else: self.firstClipPath = fileName name = len(self.firstClipPath.split("/")) new_name = (self.firstClipPath.split("/")[name - 1]).replace( ".mp4", "") self.firstClipCred.setText(new_name) firstClip = scriptwrapper.DownloadedTwitchClipWrapper( "", "", "", "", None, 0, 0, 0, 0) firstClip.author_name = new_name firstClip.mp4 = self.firstClipPath firstClip.upload = True media_info = MediaInfo.parse(self.firstClipPath) duration = media_info.tracks[0].duration / 1000 firstClip.vid_duration = float(duration) self.videoWrapper.scriptWrapper.addClipAtStart(firstClip) self.populateTreeWidget() self.chooseFirstClip.setText("Reselect First Clip") except Exception as e: self.uploadFail("Error occured uploading file \n %s" % (e)) def saveDefaultIntro(self): with open(f'Save Data/defaultintro.save', 'wb') as pickle_file: pickle.dump(self.introClip, pickle_file) def saveDefaultInterval(self): with open(f'Save Data/defaultinterval.save', 'wb') as pickle_file: pickle.dump(self.intervalClipPath, pickle_file) def saveDefaultOutro(self): with open(f'Save Data/defaultoutro.save', 'wb') as pickle_file: pickle.dump(self.outroClipPath, pickle_file) def loadDefaultIntro(self): if os.path.exists("Save Data/defaultintro.save"): with open(f'Save Data/defaultintro.save', 'rb') as pickle_file: self.introClip = pickle.load(pickle_file) self.introClipPath = self.introClip.mp4 self.defaultIntro.setChecked(True) self.chooseIntro.setText("Reselect Intro") def loadDefaultInterval(self): if os.path.exists("Save Data/defaultinterval.save"): with open(f'Save Data/defaultinterval.save', 'rb') as pickle_file: self.intervalClip = pickle.load(pickle_file) self.intervalClipPath = self.intervalClip self.defaultInterval.setChecked(True) self.chooseInterval.setText("Reselect Interval") def loadDefaultOutro(self): if os.path.exists("Save Data/defaultoutro.save"): with open(f'Save Data/defaultoutro.save', 'rb') as pickle_file: self.outroClip = pickle.load(pickle_file) self.outroClipPath = self.outroClip self.defaultOutro.setChecked(True) self.chooseOutro.setText("Reselect Outro") #Collecting all of the information for video generator def exportVideo(self): intervalCheck = True if (self.intervalClipPath is not None and settings.enforceInterval ) or not settings.enforceInterval else False firstClipCheck = True if (self.firstClipPath is not None and settings.enforceFirstClip ) or not settings.enforceFirstClip else False introClipCheck = True if ( self.introClipPath is not None and settings.enforceIntro) or not settings.enforceIntro else False outroClipCheck = True if ( self.outroClipPath is not None and settings.enforceOutro) or not settings.enforceOutro else False if intervalCheck is True and firstClipCheck is True and introClipCheck is True and outroClipCheck is True: self.mediaPlayer.stop() final_clips = self.videoWrapper.scriptWrapper.getFinalClips() with_intro = [] if settings.enforceIntro: self.introClip = scriptwrapper.DownloadedTwitchClipWrapper( "", "", " ", "", None, 0, 0, 0, 0) self.introClip.author_name = None self.introClip.mp4 = self.introClipPath self.introClip.isIntro = True self.introClip.isInterval = False self.introClip.upload = True self.introClip.isUsed = True media_info_intro = MediaInfo.parse(self.introClipPath) duration_intro = media_info_intro.tracks[0].duration / 1000 self.introClip.vid_duration = float(duration_intro) if settings.enforceInterval: self.intervalClip = scriptwrapper.DownloadedTwitchClipWrapper( "", "", " ", "", None, 0, 0, 0, 0) self.intervalClip.author_name = None self.intervalClip.mp4 = self.intervalClipPath self.intervalClip.isInterval = True self.intervalClip.isIntro = False self.intervalClip.upload = True self.intervalClip.isUsed = True media_info_interval = MediaInfo.parse(self.intervalClipPath) duration_interval = media_info_interval.tracks[ 0].duration / 1000 self.intervalClip.vid_duration = float(duration_interval) if settings.enforceOutro: self.outroClip = scriptwrapper.DownloadedTwitchClipWrapper( "", "", " ", "", None, 0, 0, 0, 0) self.outroClip.author_name = None self.outroClip.mp4 = self.outroClipPath self.outroClip.isOutro = True self.outroClip.upload = True self.outroClip.isUsed = True media_info_outro = MediaInfo.parse(self.outroClipPath) duration_outro = media_info_outro.tracks[0].duration / 1000 self.outroClip.vid_duration = float(duration_outro) if self.defaultIntro.isChecked(): self.saveDefaultIntro() if self.defaultInterval.isChecked(): self.saveDefaultInterval() if self.defaultOutro.isChecked(): self.saveDefaultOutro() for i, clip in enumerate(final_clips): with_intro.append(clip) if i == 0: if settings.enforceInterval: with_intro.append(self.intervalClip) if settings.enforceIntro: with_intro.append(self.introClip) if settings.enforceOutro: with_intro.append(self.outroClip) self.videoWrapper.final_clips = with_intro self.clipupload = ClipUploadMenu(self.videoWrapper, self.videoName.text()) self.clipupload.show() else: print("Choose intro clip and first clip") #Converting the video duration/position to seconds so it makes sense def getPositionInSecs(self): try: index = self.playlist.currentIndex() vid_position = self.mediaPlayer.position() vid_duration = self.mediaPlayer.duration() vid_percentage = (vid_position / vid_duration) twitchclip = self.videoWrapper.scriptWrapper.getCommentInformation( self.mainCommentIndex) return int(twitchclip.vid_duration * vid_percentage) except: pass def videoExportConfirmation(self): msg = 'Is the video long enough?\nIs everything properly cut?' buttonReply = QMessageBox.information( self, 'Video Export Confirmation', msg, QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel) if buttonReply == QMessageBox.Yes: intervalCheck = True if ( self.intervalClipPath is not None and settings.enforceInterval ) or not settings.enforceInterval else False firstClipCheck = True if ( self.firstClipPath is not None and settings.enforceFirstClip ) or not settings.enforceFirstClip else False introClipCheck = True if (self.introClipPath is not None and settings.enforceIntro ) or not settings.enforceIntro else False outroClipCheck = True if (self.outroClipPath is not None and settings.enforceOutro ) or not settings.enforceOutro else False msg = "Could not publish due to the following reasons: \n" if not intervalCheck: msg += "No interval selected, but interval expected (see config.ini)\n" if not firstClipCheck: msg += "No first clip selected, but first clip expected (see config.ini)\n" if not introClipCheck: msg += "No intro clip selected, but intro expected (see config.ini)\n" if not outroClipCheck: msg += "No outro clip selected, but outro expected (see config.ini)\n" amountClips = len(self.videoWrapper.scriptWrapper.getKeptClips()) if amountClips < 2: msg += "Not enough clips! Need at least two clips to be kept." if intervalCheck is False or firstClipCheck is False or introClipCheck is False or outroClipCheck is False or amountClips < 2: self.publishFail(msg) return self.mediaPlayer.stop() self.close() self.exportVideo() print('Yes clicked.') if buttonReply == QMessageBox.Cancel: print('Cancel') def uploadFail(self, msg): buttonReply = QMessageBox.information(self, 'Upload fail', msg, QMessageBox.Ok) def publishFail(self, msg): buttonReply = QMessageBox.information(self, 'Publish fail', msg, QMessageBox.Ok)
class VideoPlayer(QWidget): def __init__(self, aPath, parent=None): super(VideoPlayer, self).__init__(parent) self.setAttribute(Qt.WA_NoSystemBackground, True) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.setVolume(80) self.videoWidget = QVideoWidget(self) self.lbl = QLineEdit('00:00:00') self.lbl.setReadOnly(True) # self.lbl.setDisabled(False) self.lbl.setFixedWidth(60) self.lbl.setUpdatesEnabled(True) self.lbl.setStyleSheet(stylesheet(self)) self.elbl = QLineEdit('00:00:00') self.elbl.setReadOnly(True) # self.elbl.setDisabled(True) self.elbl.setFixedWidth(60) self.elbl.setUpdatesEnabled(True) self.elbl.setStyleSheet(stylesheet(self)) 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.sliderMoved.connect(self.handleLabel) self.positionSlider.setSingleStep(2) self.positionSlider.setPageStep(20) self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) 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 if aPath is not None: self.loadFilm(aPath) #### 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("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.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) print("QT5 Player started") def openFile(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open Movie", QDir.homePath(), "Videos (*.mp4 *.ts *.avi *.mpeg *.mpg *.mkv *.VOB *.m4v)") if fileName != '': self.loadFilm(fileName) print("File loaded") def playFromURL(self): self.mediaPlayer.pause() clip = QApplication.clipboard() myurl = clip.text() if myurl.startswith("http"): self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) else: self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(myurl))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() print(myurl) 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) 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() print("Goodbye ...") app.quit() def contextMenuRequested(self, point): menu = QtWidgets.QMenu() actionFile = menu.addAction("open File (o)") actionclipboard = menu.addSeparator() actionURL = menu.addAction("URL / File from Clipboard (u)") actionclipboard = menu.addSeparator() actionToggle = menu.addAction("show / hide Slider (s)") actionFull = menu.addAction("Fullscreen (f)") action169 = menu.addAction("16 : 9") action43 = menu.addAction("4 : 3") actionSep = menu.addSeparator() actionInfo = menu.addAction("Info (i)") action5 = menu.addSeparator() actionQuit = menu.addAction("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) 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, (mwidth + mscale) / 1.778) else: self.setGeometry(mleft, mtop, mwidth + mscale, (mwidth + mscale) / 1.33) 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, 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, mwidth / mratio) def handleFullscreen(self): if self.windowState() & QtCore.Qt.WindowFullScreen: self.showNormal() print("no Fullscreen") else: self.showFullScreen() print("Fullscreen entered") def handleInfo(self): msg = QMessageBox() msg.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SplashScreen) msg.setGeometry(self.frameGeometry().left() + 30, self.frameGeometry().top() + 30, 300, 400) msg.setIcon(QMessageBox.Information) msg.setText("QT5 Player") msg.setInformativeText(self.myinfo) msg.setStandardButtons(QMessageBox.Close) msg.exec() 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, mwidth / 1.778) else: self.setGeometry(mleft, mtop, mwidth, 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, mwidth / 1.55) else: self.setGeometry(mleft, mtop, mwidth, 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 mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: self.move(event.globalPos() \ - QPoint(self.frameGeometry().width() / 2, \ self.frameGeometry().height() / 2)) event.accept() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): f = str(event.mimeData().urls()[0].toLocalFile()) self.loadFilm(f) def loadFilm(self, f): self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) self.playButton.setEnabled(True) self.mediaPlayer.play() print(self.mediaPlayer.media().canonicalResource().resolution()) def openFileAtStart(self, filelist): matching = [s for s in filelist if ".myformat" in s] if len(matching) > 0: self.loadFilm(matching) ##################### update Label ################################## def handleLabel(self): self.lbl.clear() mtime = QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.lbl.setText(self.time.toString())
class Main(QWidget): """主窗口。""" def __init__(self, parent=None): super(Main, self).__init__(parent) # 信息。 self.result = {'uid': 0} # 歌单歌曲id。 self.playurl = {} # 搜索歌曲id。 self.ids = {} # 本地音乐地址。 self.local_url = {} # 歌曲图片。 self.pictures = {} # 歌曲列表id们。 self.playids = {} self.setObjectName('Main') self.setWindowFlags(Qt.FramelessWindowHint) self.setWindowTitle('NetEase') self.setWindowIcon(QIcon('icons/format.ico')) # 功能。 self.function = api.WebApi() # 主页及其他功能。 self.index = Index(self) self.current_list = SongsWindow(self) # ------- # 待改进。 self.resize(1000, 650) # 按钮start. self.btn_exit = QPushButton(self) self.btn_min = QPushButton(self) self.btn_max = QPushButton(self) self.btn_login = QPushButton("Unlogin", self) self.btn_search = QPushButton(self) self.find_music = QPushButton(self) self.locale_music = QPushButton(self) self.select_path = QPushButton(self) self.play = QPushButton(self) self.stop = QPushButton(self) self.nextSong = QPushButton(self) self.beforeSong = QPushButton(self) self.pause = QPushButton(self) self.btn_list = QPushButton(self) self.add_all_song = QPushButton(self) self.single = QPushButton(self) self.cycle = QPushButton(self) self.loop_flags = True # 按钮end. # ------- # 标签start. self.lbe_pic = QLabel(self) self.header_hr = QLabel(self) self.header_icon = QLabel(self) self.header_text = QLabel(self) self.spacing = QLabel(self) self.spacing2 = QLabel(self) self.spacing3 = QFrame() self.spacing4 = QFrame() self.songs_list = QLabel(self) self.song_pic = QLabel(self) self.time1 = QLabel(self) self.time2 = QLabel(self) self.song_name = QLabel(self) # 歌单内的信息。 self.detail_pic = QLabel(self) self.detail_pic.hide() self.detail_author = QLabel(self) self.detail_author.hide() self.detail_tag = QLabel(self) self.detail_tag.hide() self.detail_name = QLabel(self) self.detail_name.hide() self.detail_description = QLabel(self) self.detail_description.hide() # 标签end. # ------- # 输入框start. self.search_line = QLineEdit(self) # 输入框end. # ------- # 列表框start. self.playlist = PlayList(self) # 列表框end. # ------- # 表格start. self.table = QTableWidget(self) self.table.setObjectName("tablelist") # 表格连接信号. self.table.itemDoubleClicked.connect(self.add_song) self.table.itemDoubleClicked.connect(self.play_song) self.table.hide() # 表格end. # ------- # 滚动条start。 self.slider = QSlider(self) # 滚动条end. # ------- # 播放功能。 self.player = QMediaPlayer() # ------- # 布局与属性设置。 self.mainLayout = QGridLayout() self.topLayout = QHBoxLayout() self.leftLayout = QVBoxLayout() self.centerLayout = QHBoxLayout() self.rightLayout = QVBoxLayout() self.rightLayout1 = QHBoxLayout() self.rightLayout2 = QVBoxLayout() self.rightLayout21 = QHBoxLayout() self.bottomLayout = QHBoxLayout() self.bottomLayout1 = QVBoxLayout() self.playLayout = QHBoxLayout() self.set_buttons() self.set_labels() self.set_lines() self.set_sliders() self.set_medias() # ------- # 其他功能。 self.load_login() self.manager = QNetworkAccessManager() self.setLayout(self.set_layouts()) # 登陆部分start. def lwindow(self): """ 登陆框。 """ login = LoginWindow(self) login.exec_() def load_login(self): """ 查看是否已经登陆。 """ os.chdir('.' + '/data' + '/cookies') filedir = os.listdir('.') if filedir: try: with open(filedir[0], 'r') as f: content = f.readlines() self.result['uid'] = content[1][:-1] # 读入当前用户uid. self.btn_login.setText(content[0][:-1]) # 加载昵称。 self.btn_login.disconnect() self.btn_login.clicked.connect(self.quit_login) # 改变登陆按钮连接到退出功能。 with open(filedir[-1], 'rb') as fi: p3 = QPixmap() p3.loadFromData(QByteArray(fi.read())) self.lbe_pic.setStyleSheet("border: 0px;") # 发现圆角只是边框,图片并不变化。 self.lbe_pic.setPixmap(p3.scaled(40, 40)) # 加载头像。 self.btn_login.setToolTip("登出") except: pass else: pass os.chdir('..') os.chdir('..') try: self.playlist.set_list() except: pass def quit_login(self): """ 退出登陆。 """ self.set_labels() self.lbe_pic.setStyleSheet("") self.btn_login.setText("Unlogin") self.btn_login.disconnect() self.btn_login.clicked.connect(self.lwindow) self.playlist.disconnect() self.playlist.clear() shutil.rmtree('data/cookies') os.makedirs('.' + '/data' + '/cookies') # 登陆部分end. # 内置组件部分start. def set_buttons(self): """ 全部的按钮组件。 """ # 退出。 self.btn_exit.setObjectName('exit') self.btn_exit.setText('×') self.btn_exit.clicked.connect(self.close) self.btn_exit.setToolTip('退出') # 最小化。 self.btn_min.setObjectName('mini') self.btn_min.setText('-') self.btn_min.clicked.connect(self.showMinimized) self.btn_min.setToolTip('最小化') # 最大化。 self.btn_max.setObjectName('maxi') self.btn_max.setText('□') self.btn_max.setToolTip('^_^此功能已上火星') # 登陆。 self.btn_login.setObjectName('login') self.btn_login.clicked.connect(self.lwindow) self.btn_login.setToolTip('登陆') # 搜索。 self.btn_search.setObjectName('searchBtn') self.btn_search.resize(48, 48) self.btn_search.clicked.connect(self.song_search) # 发现音乐。 self.find_music.setObjectName('find') self.find_music.setIcon(QIcon('icons/music.png')) self.find_music.setText("发现音乐") self.find_music.clicked.connect(self.show_index) # 本地音乐。 self.locale_music.setObjectName('locale') self.locale_music.setIcon(QIcon('icons/music.png')) self.locale_music.setText("本地音乐") self.locale_music.clicked.connect(self.looking_music) self.select_path.setObjectName('selection') self.select_path.clicked.connect(self.set_path) self.select_path.setText("选择目录") self.select_path.hide() # 播放页。 self.play.setObjectName('play') self.play.setToolTip("播放歌曲") self.play.clicked.connect(self.play_song) self.stop.setObjectName('stop') self.stop.setToolTip("停止播放") self.stop.clicked.connect(self.stop_song) self.nextSong.setObjectName('next') self.nextSong.setToolTip("下一首歌曲") self.nextSong.clicked.connect(self.next_song) self.beforeSong.setObjectName('before') self.beforeSong.setToolTip("上一首歌曲") self.beforeSong.clicked.connect(self.before_song) self.pause.setObjectName("pause") self.pause.setToolTip("暂停播放") self.pause.hide() self.pause.clicked.connect(self.pause_song) self.single.setObjectName('single') self.single.setToolTip('单曲循环') self.single.clicked.connect(self.set_modles) self.single.hide() self.cycle.setObjectName('cycle') self.cycle.setToolTip('循环播放') self.cycle.clicked.connect(self.set_modles) # 歌曲列表。 self.btn_list.setObjectName('songslist') self.btn_list.clicked.connect(self.songs_lists) # 歌单内功能。 self.add_all_song.setObjectName("addbutton") self.add_all_song.setText("播放全部") self.add_all_song.clicked.connect(self.add_all) self.add_all_song.hide() def set_labels(self): """ 全部的标签组件。 """ p = QPixmap() p.load('icons/unlogin.png') p2 = QPixmap() p2.load('icons/format_2.png') # 头部装饰start。 self.lbe_pic.setObjectName("headpic") self.lbe_pic.setPixmap(p.scaled(40, 40)) self.header_hr.setObjectName('Headerhr') self.header_hr.setText("推荐") self.header_icon.setObjectName('HIcon') self.header_icon.setPixmap(p2.scaled(50, 50)) self.header_text.setObjectName('HText') self.header_text.setText(" Music") # 头部装饰end。 # 头部竖线装饰start。 self.spacing.setObjectName('spacing1') self.spacing.resize(50, 50) self.spacing2.setObjectName('spacing2') self.spacing2.resize(50, 50) # 头部竖线装饰end。 self.songs_list.setObjectName("songlist") self.songs_list.setText("我的音乐") # 歌单标签设置start。 self.detail_pic.setObjectName("pic") self.detail_author.setObjectName("author") self.detail_tag.setObjectName("tag") self.detail_name.setObjectName("name") self.detail_description.setObjectName("description") # 歌单标签设置end。 # 歌曲图片。 self.song_pic.setObjectName("songpic") p3 = QPixmap() p3.load('icons/nosong.png') self.song_pic.setPixmap(p3) # 时间显示组件。 self.time1.setObjectName("time1") self.time1.setText('00:00') self.time1.setAlignment(Qt.AlignCenter | Qt.AlignRight | Qt.AlignBottom) self.time2.setObjectName("time2") self.time2.setText('00:00') self.time2.setAlignment(Qt.AlignBottom) # 间隔装饰。 self.spacing3.setFrameShape(QFrame.VLine) self.spacing3.setFrameShadow(QFrame.Plain) self.spacing3.setLineWidth(2) self.spacing4.setFrameShape(QFrame.HLine) self.spacing3.setFrameShadow(QFrame.Plain) self.spacing3.setLineWidth(2) # 歌曲名字。 self.song_name.setObjectName("songname") self.song_name.setAlignment(Qt.AlignCenter) self.song_name.setText("~~~还没有歌曲呦~~~") def set_lines(self): """ 输入框。 """ self.search_line.setObjectName('SearchLine') self.search_line.setPlaceholderText('搜索音乐。') def set_sliders(self): """ 滚动组件。 """ self.slider.setObjectName("slider") self.slider.setOrientation(Qt.Horizontal) self.slider.sliderMoved.connect(self.slider_media) self.slider.sliderReleased.connect(self.slider_setdone) # 内置组件备份end. # 歌曲部分start. # 框架,播放器及功能的处理。 def set_tables(self): """ 表格呈现歌单详细信息。 """ self.table.setColumnCount(6) self.table.setHorizontalHeaderLabels([' ', '操作', '音乐', '歌手', '专辑', '时长']) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) # 设置列宽。 self.table.setColumnWidth(0, 40) self.table.setColumnWidth(1, 40) self.table.setColumnWidth(2, 360) self.table.setColumnWidth(3, 140) self.table.setColumnWidth(4, 140) self.table.setColumnWidth(5, 60) # 设置充满表宽。 self.table.horizontalHeader().setStretchLastSection(True) # 设置表头亮度。 self.table.horizontalHeader().setHighlightSections(False) # 设置每次选择为一行。 self.table.setSelectionBehavior(QAbstractItemView.SelectRows) # 设置垂直表头不显示。 self.table.verticalHeader().setVisible(False) def set_medias(self): """ 设置播放器。 """ self.player.setVolume(100) self.player.stateChanged.connect(self.loop) self.player.positionChanged.connect(self.set_time) def song_search(self): """ 搜索功能。 name: 歌曲名称。 id: 歌曲id。 artists: [0][1]['name']歌曲作者可能不止一人,['img1v1Url']作者头像。 album: ['name']专辑名称。 """ # 暂时只做一页。翻页属后续功能。 text = self.search_line.text() if text: self.set_tables() self.hide_index() details = self.function.search(text) try: # 搜到没有的情况。 songs = details['songs'] except KeyError: self.table.hide() self.detail_description.setText('〖很抱歉,木有此歌曲〗') return songcount = details['songCount'] if songcount > 100: count = 100 else: count = songcount self.table.setRowCount(count) for i in range(count): self.ids[str(i)] = songs[i]['id'] self.table.setItem(i, 0, QTableWidgetItem(str(i))) self.table.setItem(i, 1, QTableWidgetItem(QIcon('icons/playlist.png'), '')) self.table.setItem(i, 2, QTableWidgetItem(songs[i]['name'])) people = ','.join([c['name'] for c in songs[i]['artists']]) self.table.setItem(i, 3, QTableWidgetItem(people)) self.table.setItem(i, 4, QTableWidgetItem(songs[i]['album']['name'])) minuties = songs[i]['duration'] // 60000 seconds = songs[i]['duration'] // 1000 % 60 time = QTime(0, minuties, seconds) self.table.setItem(i, 5, QTableWidgetItem(time.toString("mm:ss"))) else: return # 加载图片。 pic = QPixmap() pic.load('icons/search2.jpg') self.detail_pic.setPixmap(pic.scaled(200, 200)) self.detail_name.setText('遨游在音乐的天空。') self.detail_author.setText("It's my sky!") self.detail_tag.setText('『Music, music』') self.detail_description.setText('〖Search Result〗') def show_playlist(self, name): """ 显示歌单详细信息。 trackCount: 总数。 name: 歌单名称。 tags: 歌单标签。 coverImgUrl: 歌单图片。 creator: ['nickname'] 创建者名字。 description: 歌单简介。 tracks: 歌曲总列表[] ,['bMusic']['id']歌曲id,['name']歌曲名称 , ['mp3Url']歌曲地址 , ['artists'][0]['name']歌曲作者,['id']作者id , ['album']['name']专辑名称,['blurPicUrl']图片。 """ self.set_tables() self.hide_index() details = self.function.details_playlist(self.result[name.replace('\n', '')]) self.table.setRowCount(details['trackCount']) # 加载在表格里。 for i in range(len(details['tracks'])): if not details['tracks'][i]['bMusic']['name']: self.playurl[str(i)] = details['tracks'][i]['id'] self.pictures[str(i)] = details['tracks'][i]['album']['blurPicUrl'] else: self.playurl[details['tracks'][i]['bMusic']['name']] = details['tracks'][i]['id'] self.pictures[details['tracks'][i]['bMusic']['name']] = details['tracks'][i]['album']['blurPicUrl'] # 设置序号。 self.table.setItem(i, 0, QTableWidgetItem(str(i))) self.table.setItem(i, 1, QTableWidgetItem(QIcon('icons/playlist.png'), '')) if not details['tracks'][i]['bMusic']['name']: self.table.setItem(i, 2, QTableWidgetItem(str(i))) else: self.table.setItem(i, 2, QTableWidgetItem(details['tracks'][i]['bMusic']['name'])) people = ','.join([t['name'] for t in details['tracks'][i]['artists']]) self.table.setItem(i, 3, QTableWidgetItem(people)) self.table.setItem(i, 4, QTableWidgetItem(details['tracks'][i]['album']['name'])) minuties = details['tracks'][i]['bMusic']['playTime'] // 60000 seconds = details['tracks'][i]['bMusic']['playTime'] // 1000 % 60 time = QTime(0, minuties, seconds) self.table.setItem(i, 5, QTableWidgetItem(time.toString("mm:ss"))) # 加载歌单图片。 self.manager.clearAccessCache() pic = self.manager.get(QNetworkRequest(QUrl(details['coverImgUrl']))) self.manager.finished.connect(lambda: load_pic(pic)) def load_pic(picture): p4 = QPixmap() p4.loadFromData(picture.readAll()) self.detail_pic.setPixmap(p4.scaled(200, 200)) # 加载歌单名称,创建者,标签,简介。 self.detail_name.setText('::======>>歌单: ' + details['name']) self.detail_author.setText('Creator: ' + details['creator']['nickname']) self.detail_tag.setText('『' + str(details['tags'])[1:-1] + '』') try: self.detail_description.setText('〖' + details['description'] + '〗') self.detail_description.setWordWrap(True) except TypeError: self.detail_description.setText('〖〗') # 歌曲组件start。 def set_song(self, name, author): """ 设置歌曲链接连接。 """ try: self.manager.disconnect() except TypeError: pass self.manager.clearAccessCache() try: self.player.setMedia(QMediaContent(QUrl(self.function.details_search(self.playids[name][author])))) data = self.manager.get(QNetworkRequest(QUrl(self.pictures[name]))) self.manager.finished.connect(lambda: self.load(data)) except KeyError: self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.playids[name][author]))) def add_song(self): """ 将歌曲加入到播放列表。 """ name = self.table.item(self.table.currentRow(), 2).text() author = self.table.item(self.table.currentRow(), 3).text() times = self.table.item(self.table.currentRow(), 5).text() content = author + ' - ' + name + ' - ' + times for i in range(self.current_list.count()): if self.current_list.item(i).text() == content: if self.current_list.currentItem().text() == content: break else: self.current_list.setCurrentRow(i) self.set_song(name, author) break else: self.current_list.addItem(content) self.current_list.setCurrentRow(self.current_list.count()-1) try: self.playids[name] except KeyError: self.playids[name] = {} try: self.playids[name][author] = self.playurl[name] except KeyError: self.playids[name][author] = self.ids[str(self.table.currentRow())] self.set_song(name, author) # 将列表保存到文件夹下。 with open('data/music/' + content.replace(':', '.'), 'w') as f: try: f.write(self.pictures[name]) except KeyError: pass def add_all(self): """ 将表格中所有的歌曲添加到播放列表。 """ for i in reversed(range(self.table.rowCount())): name = self.table.item(i, 2).text() author = self.table.item(i, 3).text() times = self.table.item(i, 5).text() content = name + ' - ' + author + ' - ' + times temp = [self.current_list.item(j).text() for j in range(self.current_list.count())] if content in temp: pass else: self.current_list.addItem(content) self.playids[name] = {} try: self.playids[name][author] = self.playurl[name] except KeyError: self.playids[name][author] = self.ids[str(self.table.currentRow())] with open('data/music/' + content.replace(':', '.'), 'w') as f: try: f.write(self.pictures[name]) except KeyError: pass self.set_song(name, author) self.play_song() def play_song(self): """ 播放组件。 """ # BUG: 用isAudio判断是否为有效音频是特么的双击居然显示无效。 try: self.song_name.setText(self.current_list.currentItem().text().split(' - ')[1]) self.time2.setText(self.current_list.currentItem().text().split(' - ')[2]) self.player.play() self.play.hide() self.pause.show() except AttributeError: return def pause_song(self): """ 暂停组件。 """ self.player.pause() self.pause.hide() self.play.show() def stop_song(self): """ 停止组件。 """ self.player.stop() self.pause.hide() self.play.show() def next_song(self): """ 下一首,若到头了则播放当前。 """ try: self.manager.disconnect() except TypeError: pass self.manager.clearAccessCache() try: content = self.current_list.item(self.current_list.currentRow()+1).text().split(' - ') self.song_name.setText(content[1]) self.time2.setText(content[2]) self.player.setMedia(QMediaContent(QUrl(self.function.details_search(self.playids[content[1]][content[0]])))) data = self.manager.get(QNetworkRequest(QUrl(self.pictures[content[1]]))) self.manager.finished.connect(lambda: self.load(data)) self.current_list.setCurrentRow(self.current_list.currentRow()+1) self.player.play() except AttributeError: self.player.play() def before_song(self): """ 前一首,若到头则播放当前。 """ try: self.manager.disconnect() except TypeError: pass self.manager.clearAccessCache() try: content = self.current_list.item(self.current_list.currentRow()-1).text().split(' - ') self.song_name.setText(content[1]) self.time2.setText(content[2]) self.player.setMedia(QMediaContent(QUrl(self.function.details_search(self.playids[content[1]][content[0]])))) data = self.manager.get(QNetworkRequest(QUrl(self.pictures[content[1]]))) self.manager.finished.connect(lambda: self.load(data)) self.current_list.setCurrentRow(self.current_list.currentRow()-1) self.player.play() except AttributeError: self.player.play() # 本地音乐查找start. def looking_music(self): """本地音乐查找组件。""" p = QPixmap() p.load('icons/local.jpg') self.detail_pic.setPixmap(p.scaled(200, 200)) self.detail_name.setText("本地音乐") self.detail_author.setText("You, You, You") self.detail_tag.setText("Your Collection Music") self.hide_index() self.select_path.show() self.set_tables() self.locale_show_on_table(os.getcwd() + r"\myMusic") def set_path(self): file_path = QFileDialog.getExistingDirectory(self, 'Select Folder') self.locale_show_on_table(file_path) def locale_show_on_table(self, path): songs_list = [i for i in os.listdir(path) if i[-3:] == 'mp3'] print(songs_list) self.table.setRowCount(len(songs_list)) for i in range(len(songs_list)): temp = songs_list[i][:-4] temp2 = temp.split(' - ') self.table.setItem(i, 0, QTableWidgetItem(str(i))) self.table.setItem(i, 1, QTableWidgetItem(QIcon('icons/playlist.png'), '')) try: self.table.setItem(i, 2, QTableWidgetItem(temp2[1])) self.table.setItem(i, 3, QTableWidgetItem(temp2[0])) except IndexError: self.table.setItem(i, 2, QTableWidgetItem(temp)) self.table.setItem(i, 3, QTableWidgetItem("暂时无法获取")) self.table.setItem(i, 4, QTableWidgetItem("暂时无法获取")) self.table.setItem(i, 5, QTableWidgetItem("暂时无法获取")) self.playids[temp] = {} self.playids[temp]["暂时无法获取"] = path + '\\' + songs_list[i] continue self.table.setItem(i, 4, QTableWidgetItem("暂时无法获取")) self.table.setItem(i, 5, QTableWidgetItem("暂时无法获取")) self.playids[temp2[1]] = {} self.playids[temp2[1]][temp2[0]] = path + '\\' + songs_list[i] # 本地音乐查找end. # 歌曲组件end. # 歌曲图片,时间和滚动条的设置。 def load(self, data): """用于加载选中歌曲的图片。""" data = data.readAll() p = QPixmap() if data: p.loadFromData(data) self.song_pic.setPixmap(p.scaled(64, 64)) else: p.load('icons/nosong.png') self.song_pic.setPixmap(p.scaled(64, 64)) def set_time(self): """ 设置当前时间。 """ times = self.player.position() / 1000 minutes = times // 60 seconds = times % 60 time = QTime(0, minutes, seconds) self.time1.setText(time.toString("mm:ss")) try: alltime = float(self.current_list.item(\ self.current_list.currentRow()).text().split(' - ')[2].replace(':', '.')) except (AttributeError, ValueError): return curtime = float(time.toString('mm.ss')) self.slider.setValue((curtime / alltime) * 100) def slider_media(self): """ 拖动滚动条时时间的改变。基于时间的变化,若无法获取到时间是不变的,且会报ValueError的错误。当然可以随便写个2:00冒充。- -。 """ try: self.player.positionChanged.disconnect() except TypeError: pass content = self.current_list.item(self.current_list.currentRow()).text().split(' - ') alltime = float(content[2].replace(':', '.')) trans_alltime = int(alltime) * 60 + (alltime - int(alltime)) * 100 currentTime = trans_alltime * self.slider.value() minuties = currentTime / 100 // 60 seconds = currentTime / 100 % 60 time = QTime(0, minuties, seconds) self.time1.setText(time.toString("mm:ss")) def slider_setdone(self): """ 鼠标放开后播放位置。待改进。 """ self.player.positionChanged.connect(self.set_time) content = self.current_list.item(self.current_list.currentRow()).text().split(' - ') alltime = float(content[2].replace(':', '.')) trans_alltime = int(alltime) * 60 + (alltime - int(alltime)) * 100 currentTime = trans_alltime * self.slider.value() self.player.setPosition(currentTime * 10) # 设置歌曲播放模式。 def set_modles(self): """ 切换图标及将循环标志变false。 """ if self.loop_flags: self.cycle.hide() self.single.show() self.loop_flags = False else: self.single.hide() self.cycle.show() self.loop_flags = True def loop(self): """ 设置为循环播放。默认。 """ if self.player.position() > 0 and self.player.state() == 0 and self.loop_flags: try: self.manager.disconnect() except TypeError: pass self.manager.clearAccessCache() content = self.current_list.item(self.current_list.currentRow()+1).text().split(' - ') self.current_list.setCurrentRow(self.current_list.currentRow()+1) try: self.player.setMedia(\ QMediaContent(QUrl(self.function.details_search(self.playids[content[1]][content[0]])))) data = self.manager.get(QNetworkRequest(QUrl(self.pictures[content[1]]))) self.manager.finished.connect(lambda: self.load(data)) except KeyError: self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.playids[content[1]][content[0]]))) self.play_song() elif self.player.state() == 0: self.solo() def solo(self): """ 设置为单曲。 """ self.player.setPosition(0) self.play_song() # 歌曲部分end. # ------- # 切换页面start。 def songs_lists(self): """ 歌曲列表。 """ if self.current_list.flag: self.current_list.show() self.current_list.flag = False else: self.current_list.hide() self.current_list.flag = True def hide_index(self): """ 隐藏主页, 显示歌单详细信息。 """ self.centerLayout.setStretch(0, 160) self.centerLayout.setStretch(1, 1) self.centerLayout.setStretch(2, 850) self.centerLayout.setStretch(3, 0) self.centerLayout.setStretch(4, 0) self.index.hide() self.select_path.hide() self.current_list.hide() self.detail_pic.show() self.detail_name.show() self.detail_author.show() self.add_all_song.show() self.detail_tag.show() self.detail_description.show() self.table.show() def show_index(self): """ 显示主页。 """ self.centerLayout.setStretch(0, 160) self.centerLayout.setStretch(1, 1) self.centerLayout.setStretch(2, 0) self.centerLayout.setStretch(3, 850) self.centerLayout.setStretch(4, 0) self.current_list.hide() self.detail_pic.hide() self.detail_name.hide() self.select_path.hide() self.detail_author.hide() self.add_all_song.hide() self.detail_tag.hide() self.detail_description.hide() self.table.hide() self.index.show() # 切换页面end. # 设置布局。 def set_layouts(self): """ 布局。 """ # 头布局start. self.topLayout.setObjectName('Headerhbox') self.topLayout.addWidget(self.header_icon) self.topLayout.addWidget(self.header_text) self.topLayout.addWidget(self.spacing2) self.topLayout.addWidget(self.search_line) self.topLayout.addWidget(self.btn_search) self.topLayout.addStretch(1) self.topLayout.addWidget(self.lbe_pic) self.topLayout.addWidget(self.btn_login) self.topLayout.addWidget(self.spacing) self.topLayout.addWidget(self.btn_min) self.topLayout.addWidget(self.btn_max) self.topLayout.addWidget(self.btn_exit) self.topLayout.setSpacing(7) # ------- self.mainLayout.addLayout(self.topLayout, 0, 0, Qt.AlignTop) self.mainLayout.addWidget(self.header_hr, 1, 0, Qt.AlignTop) # 头布局end. # -------- # 中心布局start. # 左部分start. self.leftLayout.addWidget(self.find_music) self.leftLayout.addWidget(self.locale_music) self.leftLayout.addWidget(self.songs_list) self.leftLayout.addWidget(self.playlist) self.leftLayout.setSpacing(10) # 左部分end。 # ------- # 右部分start. self.rightLayout.addLayout(self.rightLayout1) self.rightLayout1.addWidget(self.detail_pic) self.rightLayout1.addLayout(self.rightLayout2) self.rightLayout1.setStretch(0, 1) self.rightLayout1.setStretch(1, 5) self.rightLayout21.addWidget(self.detail_name) self.rightLayout21.addWidget(self.select_path) self.rightLayout21.addStretch(1) self.rightLayout2.addLayout(self.rightLayout21) self.rightLayout2.addWidget(self.detail_author) self.playLayout.addWidget(self.add_all_song) self.playLayout.addStretch(1) self.rightLayout2.addLayout(self.playLayout) self.rightLayout2.addWidget(self.detail_tag) self.rightLayout2.addWidget(self.detail_description) self.rightLayout.addWidget(self.table) self.rightLayout.setStretch(0, 1) self.rightLayout.setStretch(1, 2) # 右部分end. # ------- self.centerLayout.addLayout(self.leftLayout) self.centerLayout.addWidget(self.spacing3) self.centerLayout.addLayout(self.rightLayout) self.centerLayout.addWidget(self.index) self.centerLayout.addWidget(self.current_list) self.centerLayout.setStretch(0, 180) self.centerLayout.setStretch(1, 1) self.centerLayout.setStretch(2, 0) self.centerLayout.setStretch(3, 830) self.centerLayout.setStretch(4, 0) self.mainLayout.addLayout(self.centerLayout, 2, 0, Qt.AlignTop | Qt.AlignLeft) # 中心布局end. # ------- # 下部分start. self.bottomLayout.addWidget(self.stop) self.bottomLayout.addWidget(self.beforeSong) self.bottomLayout.addWidget(self.play) self.bottomLayout.addWidget(self.pause) self.bottomLayout.addWidget(self.nextSong) self.bottomLayout.addWidget(self.song_pic) self.bottomLayout.addWidget(self.time1) self.bottomLayout1.addWidget(self.song_name) self.bottomLayout1.addWidget(self.slider) self.bottomLayout.addLayout(self.bottomLayout1) self.bottomLayout.addWidget(self.time2) self.bottomLayout.addWidget(self.cycle) self.bottomLayout.addWidget(self.single) self.bottomLayout.addWidget(self.btn_list) self.bottomLayout.setStretch(6, 1) self.bottomLayout.setStretch(7, 6) self.bottomLayout.setStretch(8, 1) self.mainLayout.addWidget(self.spacing4, 3, 0, Qt.AlignTop) self.mainLayout.addLayout(self.bottomLayout, 3, 0, Qt.AlignBottom) # self.mainLayout.addWidget(self.current_list, 2, 0, Qt.AlignBottom | Qt.AlignRight) # 下部分end. self.mainLayout.setRowStretch(1, 1) self.mainLayout.setRowStretch(2, 20) self.mainLayout.setRowStretch(3, 3) return self.mainLayout """重写鼠标事件,实现窗口拖动。""" def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: self.m_drag = True self.m_DragPosition = event.globalPos()-self.pos() event.accept() def mouseMoveEvent(self, event): try: if event.buttons() and Qt.LeftButton: self.move(event.globalPos()-self.m_DragPosition) event.accept() except AttributeError: pass def mouseReleaseEvent(self, event): self.m_drag = False """按键绑定。。""" def keyPressEvent(self, event): if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Enter-1: self.song_search() """退出窗口时做的一些事。""" def closeEvent(self, event): # 退出时保存歌曲列表缓存。 try: with open('data/music/load/playids.pkl', 'wb') as f: pickle.dump(self.playids, f) except FileNotFoundError: pass """界面开始前的一些事。""" def showEvent(self, event): # 查看是否有歌曲缓存。 try: with open('data/music/load/playids.pkl', 'rb') as r: self.playids = pickle.load(r) # 没有就算了。 except FileNotFoundError: pass # 没有也不会报错。 for i in os.listdir('.' + '/data/music/'): if os.path.isfile('.' + '/data/music/' + i): self.current_list.addItem(i.replace('.', ':')) with open('.' + '/data/music/' + i, 'r') as f: self.pictures[i.split(' - ')[1]] = f.read() # 有的话设置为0,防止其他功能报错。 self.current_list.setCurrentRow(0)